[mle] attach process enhancements (#2675)

This commit is contained in:
Jonathan Hui
2018-04-24 13:22:23 -07:00
4 changed files with 156 additions and 139 deletions
+122 -114
View File
@@ -66,9 +66,9 @@ Mle::Mle(Instance &aInstance)
, mRetrieveNewNetworkData(false)
, mRole(OT_DEVICE_ROLE_DISABLED)
, mDeviceMode(ModeTlv::kModeRxOnWhenIdle | ModeTlv::kModeSecureDataRequest)
, mParentRequestState(kParentIdle)
, mAttachState(kAttachStateIdle)
, mReattachState(kReattachStop)
, mParentRequestTimer(aInstance, &Mle::HandleParentRequestTimer, this)
, mAttachTimer(aInstance, &Mle::HandleAttachTimer, this)
, mDelayedResponseTimer(aInstance, &Mle::HandleDelayedResponseTimer, this)
, mChildUpdateRequestTimer(aInstance, &Mle::HandleChildUpdateRequestTimer, this)
, mLastPartitionId(0)
@@ -260,7 +260,7 @@ otError Mle::Start(bool aEnableReattach, bool aAnnounceAttach)
}
else
{
mParentRequestState = kParentSynchronize;
mAttachState = kAttachStateSynchronize;
mChildUpdateAttempts = 0;
SendChildUpdateRequest();
}
@@ -534,7 +534,7 @@ otError Mle::BecomeChild(AttachMode aMode)
otError error = OT_ERROR_NONE;
VerifyOrExit(mRole != OT_DEVICE_ROLE_DISABLED, error = OT_ERROR_INVALID_STATE);
VerifyOrExit(mParentRequestState == kParentIdle, error = OT_ERROR_BUSY);
VerifyOrExit(mAttachState == kAttachStateIdle, error = OT_ERROR_BUSY);
otLogInfoMle(GetInstance(), "Attempt to attach");
@@ -551,8 +551,8 @@ otError Mle::BecomeChild(AttachMode aMode)
}
ResetParentCandidate();
mParentRequestState = kParentRequestStart;
mParentRequestMode = aMode;
mAttachState = kAttachStateStart;
mParentRequestMode = aMode;
if (aMode != kAttachBetter)
{
@@ -564,7 +564,7 @@ otError Mle::BecomeChild(AttachMode aMode)
netif.GetMeshForwarder().SetRxOnWhenIdle(true);
mParentRequestTimer.Start(1 + Random::GetUint32InRange(0, kParentRequestRouterTimeout));
mAttachTimer.Start(1 + Random::GetUint32InRange(0, kParentRequestRouterTimeout));
exit:
return error;
@@ -585,8 +585,8 @@ otError Mle::SetStateDetached(void)
}
SetRole(OT_DEVICE_ROLE_DETACHED);
mParentRequestState = kParentIdle;
mParentRequestTimer.Stop();
mAttachState = kAttachStateIdle;
mAttachTimer.Stop();
mChildUpdateRequestTimer.Stop();
netif.GetMeshForwarder().SetRxOnWhenIdle(true);
netif.GetMac().SetBeaconEnabled(false);
@@ -608,7 +608,7 @@ otError Mle::SetStateChild(uint16_t aRloc16)
SetRloc16(aRloc16);
SetRole(OT_DEVICE_ROLE_CHILD);
mParentRequestState = kParentIdle;
mAttachState = kAttachStateIdle;
mReattachState = kReattachStop;
mChildUpdateAttempts = 0;
netif.GetMac().SetBeaconEnabled(false);
@@ -1431,127 +1431,152 @@ exit:
}
#endif
void Mle::HandleParentRequestTimer(Timer &aTimer)
void Mle::HandleAttachTimer(Timer &aTimer)
{
aTimer.GetOwner<Mle>().HandleParentRequestTimer();
aTimer.GetOwner<Mle>().HandleAttachTimer();
}
void Mle::HandleParentRequestTimer(void)
void Mle::HandleAttachTimer(void)
{
ThreadNetif &netif = GetNetif();
uint32_t delay = 0;
switch (mParentRequestState)
switch (mAttachState)
{
case kParentIdle:
case kAttachStateIdle:
assert(false);
break;
case kParentSynchronize:
case kAttachStateSynchronize:
SendChildUpdateRequest();
break;
case kParentRequestStart:
mParentRequestState = kParentRequestRouter;
case kAttachStateStart:
mAttachState = kAttachStateParentRequestRouter;
mParentCandidate.SetState(Neighbor::kStateInvalid);
mReceivedResponseFromParent = false;
SendParentRequest();
if (mParentRequestMode == kAttachSame1 || mParentRequestMode == kAttachSame2)
{
SendParentRequest(kParentRequestTypeRoutersAndReeds);
delay = kParentRequestReedTimeout;
}
else
{
SendParentRequest(kParentRequestTypeRouters);
delay = kParentRequestRouterTimeout;
}
break;
case kParentRequestRouter:
mParentRequestState = kParentRequestChild;
case kAttachStateParentRequestRouter:
mAttachState = kAttachStateParentRequestReed;
if (mParentCandidate.GetState() != Neighbor::kStateParentResponse)
{
SendParentRequest();
SendParentRequest(kParentRequestTypeRoutersAndReeds);
delay = kParentRequestReedTimeout;
break;
}
// fall through
case kParentRequestChild:
case kAttachStateParentRequestReed:
if (mParentCandidate.GetState() == Neighbor::kStateParentResponse &&
(mRole != OT_DEVICE_ROLE_CHILD || mReceivedResponseFromParent || mParentRequestMode == kAttachBetter) &&
SendChildIdRequest() == OT_ERROR_NONE)
{
mParentRequestState = kChildIdRequest;
mParentRequestTimer.Start(kParentRequestChildTimeout);
mAttachState = kAttachStateChildIdRequest;
delay = kParentRequestReedTimeout;
break;
}
// fall through
case kChildIdRequest:
mParentRequestState = kParentIdle;
case kAttachStateChildIdRequest:
mAttachState = kAttachStateIdle;
ResetParentCandidate();
delay = Reattach();
break;
}
if (mReattachState == kReattachActive)
if (delay != 0)
{
mAttachTimer.Start(delay);
}
}
uint32_t Mle::Reattach(void)
{
ThreadNetif &netif = GetNetif();
uint32_t delay = 0;
if (mReattachState == kReattachActive)
{
if (netif.GetPendingDataset().Restore() == OT_ERROR_NONE)
{
if (netif.GetPendingDataset().Restore() == OT_ERROR_NONE)
{
netif.GetPendingDataset().ApplyConfiguration();
mReattachState = kReattachPending;
mParentRequestState = kParentRequestStart;
mParentRequestTimer.Start(kParentRequestRouterTimeout);
}
else
{
mReattachState = kReattachStop;
}
netif.GetPendingDataset().ApplyConfiguration();
mReattachState = kReattachPending;
mAttachState = kAttachStateStart;
delay = kParentRequestRouterTimeout;
}
else if (mReattachState == kReattachPending)
else
{
mReattachState = kReattachStop;
netif.GetActiveDataset().Restore();
}
}
else if (mReattachState == kReattachPending)
{
mReattachState = kReattachStop;
netif.GetActiveDataset().Restore();
}
if (mReattachState == kReattachStop)
VerifyOrExit(mReattachState == kReattachStop);
switch (mParentRequestMode)
{
case kAttachAny:
if (mRole != OT_DEVICE_ROLE_CHILD)
{
switch (mParentRequestMode)
if (mPreviousPanId != Mac::kPanIdBroadcast)
{
case kAttachAny:
if (mRole != OT_DEVICE_ROLE_CHILD)
{
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::kModeRxOnWhenIdle) == 0)
{
// return to sleepy operation
netif.GetMeshForwarder().GetDataPollManager().SetAttachMode(false);
netif.GetMeshForwarder().SetRxOnWhenIdle(false);
}
break;
case kAttachSame1:
BecomeChild(kAttachSame2);
break;
case kAttachSame2:
BecomeChild(kAttachAny);
break;
case kAttachBetter:
break;
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::kModeRxOnWhenIdle) == 0)
{
// return to sleepy operation
netif.GetMeshForwarder().GetDataPollManager().SetAttachMode(false);
netif.GetMeshForwarder().SetRxOnWhenIdle(false);
}
break;
case kAttachSame1:
BecomeChild(kAttachSame2);
break;
case kAttachSame2:
BecomeChild(kAttachAny);
break;
case kAttachBetter:
break;
}
exit:
return delay;
}
void Mle::HandleDelayedResponseTimer(Timer &aTimer)
@@ -1630,7 +1655,7 @@ void Mle::RemoveDelayedDataResponseMessage(void)
}
}
otError Mle::SendParentRequest(void)
otError Mle::SendParentRequest(ParentRequestType aType)
{
otError error = OT_ERROR_NONE;
Message * message;
@@ -1639,25 +1664,15 @@ otError Mle::SendParentRequest(void)
Random::FillBuffer(mParentRequest.mChallenge, sizeof(mParentRequest.mChallenge));
switch (mParentRequestState)
switch (aType)
{
case kParentRequestRouter:
case kParentRequestTypeRouters:
scanMask = ScanMaskTlv::kRouterFlag;
if (mParentRequestMode == kAttachSame1 || mParentRequestMode == kAttachSame2)
{
scanMask |= ScanMaskTlv::kEndDeviceFlag;
}
break;
case kParentRequestChild:
case kParentRequestTypeRoutersAndReeds:
scanMask = ScanMaskTlv::kRouterFlag | ScanMaskTlv::kEndDeviceFlag;
break;
default:
assert(false);
break;
}
VerifyOrExit((message = NewMleMessage()) != NULL, error = OT_ERROR_NO_BUFS);
@@ -1672,32 +1687,25 @@ otError Mle::SendParentRequest(void)
destination.mFields.m16[7] = HostSwap16(0x0002);
SuccessOrExit(error = SendMessage(*message, destination));
if ((scanMask & ScanMaskTlv::kEndDeviceFlag) == 0)
switch (aType)
{
case kParentRequestTypeRouters:
LogMleMessage("Send Parent Request to routers", destination);
}
else
{
break;
case kParentRequestTypeRoutersAndReeds:
LogMleMessage("Send Parent Request to routers and REEDs", destination);
break;
}
exit:
if ((scanMask & ScanMaskTlv::kEndDeviceFlag) == 0)
{
mParentRequestTimer.Start(kParentRequestRouterTimeout);
}
else
{
mParentRequestTimer.Start(kParentRequestChildTimeout);
}
if (error != OT_ERROR_NONE && message != NULL)
{
message->Free();
}
return OT_ERROR_NONE;
return error;
}
otError Mle::SendChildIdRequest(void)
@@ -2800,7 +2808,7 @@ otError Mle::HandleParentResponse(const Message &aMessage, const Ip6::MessageInf
linkQuality = LinkQualityInfo::ConvertLinkMarginToLinkQuality(linkMargin);
VerifyOrExit(mParentRequestState != kParentRequestRouter || linkQuality == 3);
VerifyOrExit(mAttachState != kAttachStateParentRequestRouter || linkQuality == 3);
// Connectivity
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kConnectivity, sizeof(connectivity), connectivity));
@@ -2921,7 +2929,7 @@ otError Mle::HandleChildIdResponse(const Message &aMessage, const Ip6::MessageIn
LogMleMessage("Receive Child ID Response", aMessageInfo.GetPeerAddr(), sourceAddress.GetRloc16());
VerifyOrExit(mParentRequestState == kChildIdRequest);
VerifyOrExit(mAttachState == kAttachStateChildIdRequest);
// Leader Data
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kLeaderData, sizeof(leaderData), leaderData));
@@ -2972,7 +2980,7 @@ otError Mle::HandleChildIdResponse(const Message &aMessage, const Ip6::MessageIn
}
// Parent Attach Success
mParentRequestTimer.Stop();
mAttachTimer.Stop();
SetStateDetached();
SetLeaderData(leaderData.GetPartitionId(), leaderData.GetWeighting(), leaderData.GetLeaderRouterId());
+23 -16
View File
@@ -1406,19 +1406,19 @@ protected:
uint8_t mDeviceMode; ///< Device mode setting.
/**
* States when searching for a parent.
* States during attach (when searching for a parent).
*
*/
enum ParentRequestState
enum AttachState
{
kParentIdle, ///< Not currently searching for a parent.
kParentSynchronize, ///< Looking to synchronize with a parent (after reset).
kParentRequestStart, ///< Starting to look for a parent.
kParentRequestRouter, ///< Searching for a Router to attach to.
kParentRequestChild, ///< Searching for Routers or REEDs to attach to.
kChildIdRequest, ///< Sending a Child ID Request message.
kAttachStateIdle, ///< Not currently searching for a parent.
kAttachStateSynchronize, ///< Looking to synchronize with a parent (after reset).
kAttachStateStart, ///< Starting to look for a parent.
kAttachStateParentRequestRouter, ///< Searching for a Router to attach to.
kAttachStateParentRequestReed, ///< Searching for Routers or REEDs to attach to.
kAttachStateChildIdRequest, ///< Sending a Child ID Request message.
};
ParentRequestState mParentRequestState; ///< The parent request state.
AttachState mAttachState; ///< The parent request state.
/**
* States when reattaching network using stored dataset
@@ -1433,7 +1433,7 @@ protected:
};
ReattachState mReattachState;
TimerMilli mParentRequestTimer; ///< The timer for driving the Parent Request process.
TimerMilli mAttachTimer; ///< The timer for driving the attach process.
TimerMilli mDelayedResponseTimer; ///< The timer to delay MLE responses.
TimerMilli mChildUpdateRequestTimer; ///< The timer for sending MLE Child Update Request messages.
uint32_t mLastPartitionId; ///< The partition ID of the previous Thread partition
@@ -1449,6 +1449,12 @@ private:
kMleHopLimit = 255,
};
enum ParentRequestType
{
kParentRequestTypeRouters, ///< Parent Request to all routers.
kParentRequestTypeRoutersAndReeds, ///< Parent Request to all routers and REEDs.
};
#if OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH
enum
{
@@ -1467,8 +1473,8 @@ private:
static void HandleStateChanged(Notifier::Callback &aCallback, uint32_t aFlags);
void HandleStateChanged(uint32_t aFlags);
static void HandleParentRequestTimer(Timer &aTimer);
void HandleParentRequestTimer(void);
static void HandleAttachTimer(Timer &aTimer);
void HandleAttachTimer(void);
static void HandleDelayedResponseTimer(Timer &aTimer);
void HandleDelayedResponseTimer(void);
static void HandleChildUpdateRequestTimer(Timer &aTimer);
@@ -1488,10 +1494,11 @@ private:
otError HandleDiscoveryResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
otError HandleLeaderData(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
otError SendParentRequest(void);
otError SendChildIdRequest(void);
void SendOrphanAnnounce(void);
otError SendAnnounce(uint8_t aChannel, bool aOrphanAnnounce, const Ip6::Address &aDestination);
otError SendParentRequest(ParentRequestType aType);
otError SendChildIdRequest(void);
void SendOrphanAnnounce(void);
otError SendAnnounce(uint8_t aChannel, bool aOrphanAnnounce, const Ip6::Address &aDestination);
uint32_t Reattach(void);
bool IsBetterParent(uint16_t aRloc16, uint8_t aLinkQuality, uint8_t aLinkMargin, ConnectivityTlv &aConnectivityTlv);
void ResetParentCandidate(void);
+2 -2
View File
@@ -59,8 +59,8 @@ enum
{
kVersion = 2, ///< MLE Version
kUdpPort = 19788, ///< MLE UDP Port
kParentRequestRouterTimeout = 750, ///< Router Request timeout
kParentRequestChildTimeout = 1250, ///< End Device Request timeout
kParentRequestRouterTimeout = 750, ///< Router Parent Request timeout
kParentRequestReedTimeout = 1250, ///< Router and REEDs Parent Request timeout
kParentResponseMaxDelayRouters = 500, ///< Maximum delay for response for Parent Request sent to routers only
kParentResponseMaxDelayAll = 1000, ///< Maximum delay for response for Parent Request sent to all devices
kUnicastRetransmissionDelay = 1000, ///< Base delay before retransmitting an MLE unicast.
+9 -7
View File
@@ -417,9 +417,10 @@ otError MleRouter::SetStateRouter(uint16_t aRloc16)
ThreadNetif &netif = GetNetif();
SetRloc16(aRloc16);
SetRole(OT_DEVICE_ROLE_ROUTER);
mParentRequestState = kParentIdle;
mParentRequestTimer.Stop();
mAttachState = kAttachStateIdle;
mAttachTimer.Stop();
mChildUpdateRequestTimer.Stop();
mAdvertiseTimer.Stop();
ResetAdvertiseInterval();
@@ -458,9 +459,10 @@ otError MleRouter::SetStateLeader(uint16_t aRloc16)
ThreadNetif &netif = GetNetif();
SetRloc16(aRloc16);
SetRole(OT_DEVICE_ROLE_LEADER);
mParentRequestState = kParentIdle;
mParentRequestTimer.Stop();
mAttachState = kAttachStateIdle;
mAttachTimer.Stop();
mChildUpdateRequestTimer.Stop();
mAdvertiseTimer.Stop();
ResetAdvertiseInterval();
@@ -545,7 +547,7 @@ otError MleRouter::SendAdvertisement(void)
// Without this suppression, a device may send an MLE Advertisement before receiving the MLE Child ID Response.
// The candidate parent then removes the attaching device because the Source Address TLV includes an RLOC16 that
// indicates a Router role (i.e. a Child ID equal to zero).
VerifyOrExit(mParentRequestState == kParentIdle);
VerifyOrExit(mAttachState == kAttachStateIdle);
// Suppress MLE Advertisements when transitioning to the router role.
//
@@ -697,7 +699,7 @@ otError MleRouter::HandleLinkRequest(const Message &aMessage, const Ip6::Message
VerifyOrExit(mRole == OT_DEVICE_ROLE_ROUTER || mRole == OT_DEVICE_ROLE_LEADER, error = OT_ERROR_INVALID_STATE);
VerifyOrExit(mParentRequestState == kParentIdle, error = OT_ERROR_INVALID_STATE);
VerifyOrExit(mAttachState == kAttachStateIdle, error = OT_ERROR_INVALID_STATE);
aMessageInfo.GetPeerAddr().ToExtAddress(macAddr);
@@ -3317,7 +3319,7 @@ Neighbor *MleRouter::GetNeighbor(const Mac::ExtAddress &aAddress)
}
}
if (mParentRequestState != kParentIdle)
if (mAttachState != kAttachStateIdle)
{
rval = Mle::GetNeighbor(aAddress);
}