mirror of
https://github.com/espressif/openthread.git
synced 2026-08-13 06:07:48 +00:00
[mle] change the attach MLE Announcement transmissions (#2692)
This commit changes the attach state machine and how the MLE Announce messages are sent as part of the attach process. A new attach state `kAttachStateAnnounce` is added where the device sends MLE Announce on all channels (in Active Dataset's channel mask). This commit also adds a new `toranj` test-case which tests the situation where a device misses a channel change and then reattaches by sending MLE Announce messages.
This commit is contained in:
committed by
Jonathan Hui
parent
7e2caa5f16
commit
4d6f5a7c4f
+211
-52
@@ -68,6 +68,8 @@ Mle::Mle(Instance &aInstance)
|
||||
, mDeviceMode(ModeTlv::kModeRxOnWhenIdle | ModeTlv::kModeSecureDataRequest)
|
||||
, mAttachState(kAttachStateIdle)
|
||||
, mReattachState(kReattachStop)
|
||||
, mAttachCounter(0)
|
||||
, mAnnounceDelay(kAnnounceTimeout)
|
||||
, mAttachTimer(aInstance, &Mle::HandleAttachTimer, this)
|
||||
, mDelayedResponseTimer(aInstance, &Mle::HandleDelayedResponseTimer, this)
|
||||
, mChildUpdateRequestTimer(aInstance, &Mle::HandleChildUpdateRequestTimer, this)
|
||||
@@ -236,6 +238,7 @@ otError Mle::Start(bool aEnableReattach, bool aAnnounceAttach)
|
||||
VerifyOrExit(netif.IsUp(), error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
SetStateDetached();
|
||||
mAttachCounter = 0;
|
||||
|
||||
netif.GetKeyManager().Start();
|
||||
|
||||
@@ -257,7 +260,7 @@ otError Mle::Start(bool aEnableReattach, bool aAnnounceAttach)
|
||||
}
|
||||
else
|
||||
{
|
||||
mAttachState = kAttachStateSynchronize;
|
||||
SetAttachState(kAttachStateSynchronize);
|
||||
mChildUpdateAttempts = 0;
|
||||
SendChildUpdateRequest();
|
||||
}
|
||||
@@ -301,6 +304,16 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Mle::SetAttachState(AttachState aState)
|
||||
{
|
||||
VerifyOrExit(aState != mAttachState);
|
||||
otLogInfoMle(GetInstance(), "AttachState %s -> %s", AttachStateToString(mAttachState), AttachStateToString(aState));
|
||||
mAttachState = aState;
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
otError Mle::Restore(void)
|
||||
{
|
||||
ThreadNetif & netif = GetNetif();
|
||||
@@ -533,8 +546,6 @@ otError Mle::BecomeChild(AttachMode aMode)
|
||||
VerifyOrExit(mRole != OT_DEVICE_ROLE_DISABLED, error = OT_ERROR_INVALID_STATE);
|
||||
VerifyOrExit(mAttachState == kAttachStateIdle, error = OT_ERROR_BUSY);
|
||||
|
||||
otLogInfoMle(GetInstance(), "Attempt to attach");
|
||||
|
||||
if (mReattachState == kReattachStart)
|
||||
{
|
||||
if (netif.GetActiveDataset().Restore() == OT_ERROR_NONE)
|
||||
@@ -548,9 +559,13 @@ otError Mle::BecomeChild(AttachMode aMode)
|
||||
}
|
||||
|
||||
ResetParentCandidate();
|
||||
mAttachState = kAttachStateStart;
|
||||
SetAttachState(kAttachStateStart);
|
||||
mParentRequestMode = aMode;
|
||||
|
||||
mAttachCounter++;
|
||||
otLogInfoMle(GetInstance(), "Attempt to attach - attempt %d, %s %s", mAttachCounter, AttachModeToString(aMode),
|
||||
ReattachStateToString(mReattachState));
|
||||
|
||||
if (aMode != kAttachBetter)
|
||||
{
|
||||
if (mDeviceMode & ModeTlv::kModeFFD)
|
||||
@@ -559,9 +574,7 @@ otError Mle::BecomeChild(AttachMode aMode)
|
||||
}
|
||||
}
|
||||
|
||||
netif.GetMeshForwarder().SetRxOnWhenIdle(true);
|
||||
|
||||
mAttachTimer.Start(1 + Random::GetUint32InRange(0, kParentRequestRouterTimeout));
|
||||
mAttachTimer.Start(1 + ((mAttachCounter == 1) ? Random::GetUint32InRange(0, kParentRequestRouterTimeout) : 0));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
@@ -582,7 +595,7 @@ otError Mle::SetStateDetached(void)
|
||||
}
|
||||
|
||||
SetRole(OT_DEVICE_ROLE_DETACHED);
|
||||
mAttachState = kAttachStateIdle;
|
||||
SetAttachState(kAttachStateIdle);
|
||||
mAttachTimer.Stop();
|
||||
mChildUpdateRequestTimer.Stop();
|
||||
netif.GetMeshForwarder().SetRxOnWhenIdle(true);
|
||||
@@ -605,7 +618,8 @@ otError Mle::SetStateChild(uint16_t aRloc16)
|
||||
|
||||
SetRloc16(aRloc16);
|
||||
SetRole(OT_DEVICE_ROLE_CHILD);
|
||||
mAttachState = kAttachStateIdle;
|
||||
SetAttachState(kAttachStateIdle);
|
||||
mAttachCounter = 0;
|
||||
mReattachState = kReattachStop;
|
||||
mChildUpdateAttempts = 0;
|
||||
netif.GetMac().SetBeaconEnabled(false);
|
||||
@@ -1432,7 +1446,28 @@ void Mle::HandleAttachTimer(Timer &aTimer)
|
||||
|
||||
void Mle::HandleAttachTimer(void)
|
||||
{
|
||||
uint32_t delay = 0;
|
||||
uint32_t delay = 0;
|
||||
bool shouldAnnounce = true;
|
||||
|
||||
if (mAttachState == kAttachStateParentRequestRouter || mAttachState == kAttachStateParentRequestReed ||
|
||||
mAttachState == kAttachStateAnnounce)
|
||||
{
|
||||
// If already attached, accept the parent candidate if
|
||||
// we are trying to attach to a better partition or if a
|
||||
// Parent Response was also received from the current parent
|
||||
// to which the device is attached. This ensures that the
|
||||
// new parent candidate is compared with the current parent
|
||||
// and that it is indeed preferred over the current one.
|
||||
|
||||
if (mParentCandidate.GetState() == Neighbor::kStateParentResponse &&
|
||||
(mRole != OT_DEVICE_ROLE_CHILD || mReceivedResponseFromParent || mParentRequestMode == kAttachBetter) &&
|
||||
SendChildIdRequest() == OT_ERROR_NONE)
|
||||
{
|
||||
SetAttachState(kAttachStateChildIdRequest);
|
||||
delay = kParentRequestReedTimeout;
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
|
||||
switch (mAttachState)
|
||||
{
|
||||
@@ -1445,9 +1480,10 @@ void Mle::HandleAttachTimer(void)
|
||||
break;
|
||||
|
||||
case kAttachStateStart:
|
||||
mAttachState = kAttachStateParentRequestRouter;
|
||||
SetAttachState(kAttachStateParentRequestRouter);
|
||||
mParentCandidate.SetState(Neighbor::kStateInvalid);
|
||||
mReceivedResponseFromParent = false;
|
||||
GetNetif().GetMeshForwarder().SetRxOnWhenIdle(true);
|
||||
|
||||
if (mParentRequestMode == kAttachSame1 || mParentRequestMode == kAttachSame2)
|
||||
{
|
||||
@@ -1463,42 +1499,88 @@ void Mle::HandleAttachTimer(void)
|
||||
break;
|
||||
|
||||
case kAttachStateParentRequestRouter:
|
||||
mAttachState = kAttachStateParentRequestReed;
|
||||
SetAttachState(kAttachStateParentRequestReed);
|
||||
SendParentRequest(kParentRequestTypeRoutersAndReeds);
|
||||
delay = kParentRequestReedTimeout;
|
||||
break;
|
||||
|
||||
if (mParentCandidate.GetState() != Neighbor::kStateParentResponse)
|
||||
case kAttachStateParentRequestReed:
|
||||
shouldAnnounce = PrepareAnnounceState();
|
||||
|
||||
if (shouldAnnounce)
|
||||
{
|
||||
SetAttachState(kAttachStateAnnounce);
|
||||
SendParentRequest(kParentRequestTypeRoutersAndReeds);
|
||||
delay = kParentRequestReedTimeout;
|
||||
mAnnounceChannel = OT_RADIO_CHANNEL_MIN;
|
||||
delay = mAnnounceDelay;
|
||||
break;
|
||||
}
|
||||
|
||||
// fall through
|
||||
|
||||
case kAttachStateParentRequestReed:
|
||||
if (mParentCandidate.GetState() == Neighbor::kStateParentResponse &&
|
||||
(mRole != OT_DEVICE_ROLE_CHILD || mReceivedResponseFromParent || mParentRequestMode == kAttachBetter) &&
|
||||
SendChildIdRequest() == OT_ERROR_NONE)
|
||||
case kAttachStateAnnounce:
|
||||
if (shouldAnnounce)
|
||||
{
|
||||
mAttachState = kAttachStateChildIdRequest;
|
||||
delay = kParentRequestReedTimeout;
|
||||
break;
|
||||
if (SendOrphanAnnounce() == OT_ERROR_NONE)
|
||||
{
|
||||
delay = mAnnounceDelay;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// fall through
|
||||
|
||||
case kAttachStateChildIdRequest:
|
||||
mAttachState = kAttachStateIdle;
|
||||
SetAttachState(kAttachStateIdle);
|
||||
ResetParentCandidate();
|
||||
delay = Reattach();
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
if (delay != 0)
|
||||
{
|
||||
mAttachTimer.Start(delay);
|
||||
}
|
||||
}
|
||||
|
||||
bool Mle::PrepareAnnounceState(void)
|
||||
{
|
||||
bool shouldAnnounce = false;
|
||||
uint16_t numChannels = 0;
|
||||
const MeshCoP::ChannelMask0Tlv *channelMask;
|
||||
MeshCoP::Dataset dataset(MeshCoP::Tlv::kActiveTimestamp);
|
||||
|
||||
VerifyOrExit((mRole != OT_DEVICE_ROLE_CHILD) && ((mDeviceMode & ModeTlv::kModeFFD) == 0) &&
|
||||
(mReattachState == kReattachStop));
|
||||
|
||||
SuccessOrExit(GetNetif().GetActiveDataset().Get(dataset));
|
||||
channelMask = static_cast<const MeshCoP::ChannelMask0Tlv *>(dataset.Get(MeshCoP::Tlv::kChannelMask));
|
||||
|
||||
VerifyOrExit(channelMask != NULL);
|
||||
|
||||
for (uint8_t channel = OT_RADIO_CHANNEL_MIN; channel <= OT_RADIO_CHANNEL_MAX; channel++)
|
||||
{
|
||||
if (channelMask->IsChannelSet(channel))
|
||||
{
|
||||
numChannels++;
|
||||
}
|
||||
}
|
||||
|
||||
mAnnounceDelay = kAnnounceTimeout / (numChannels + 1);
|
||||
|
||||
if (mAnnounceDelay < kMinAnnounceDelay)
|
||||
{
|
||||
mAnnounceDelay = kMinAnnounceDelay;
|
||||
}
|
||||
|
||||
shouldAnnounce = true;
|
||||
|
||||
exit:
|
||||
return shouldAnnounce;
|
||||
}
|
||||
|
||||
uint32_t Mle::Reattach(void)
|
||||
{
|
||||
ThreadNetif &netif = GetNetif();
|
||||
@@ -1510,8 +1592,8 @@ uint32_t Mle::Reattach(void)
|
||||
{
|
||||
netif.GetPendingDataset().ApplyConfiguration();
|
||||
mReattachState = kReattachPending;
|
||||
mAttachState = kAttachStateStart;
|
||||
delay = kParentRequestRouterTimeout;
|
||||
SetAttachState(kAttachStateStart);
|
||||
delay = 1 + Random::GetUint32InRange(0, kParentRequestJitter);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1540,7 +1622,6 @@ uint32_t Mle::Reattach(void)
|
||||
}
|
||||
else if ((mDeviceMode & ModeTlv::kModeFFD) == 0)
|
||||
{
|
||||
SendOrphanAnnounce();
|
||||
BecomeDetached();
|
||||
}
|
||||
else if (netif.GetMle().BecomeLeader() != OT_ERROR_NONE)
|
||||
@@ -2044,45 +2125,30 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Mle::SendOrphanAnnounce(void)
|
||||
otError Mle::SendOrphanAnnounce(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
const MeshCoP::ChannelMask0Tlv *channelMask;
|
||||
uint8_t channel;
|
||||
MeshCoP::Dataset dataset(MeshCoP::Tlv::kActiveTimestamp);
|
||||
|
||||
GetNetif().GetActiveDataset().Get(dataset);
|
||||
SuccessOrExit(error = GetNetif().GetActiveDataset().Get(dataset));
|
||||
|
||||
channelMask = static_cast<const MeshCoP::ChannelMask0Tlv *>(dataset.Get(MeshCoP::Tlv::kChannelMask));
|
||||
VerifyOrExit(channelMask != NULL, error = OT_ERROR_NOT_FOUND);
|
||||
|
||||
VerifyOrExit(channelMask != NULL);
|
||||
VerifyOrExit(mAnnounceChannel <= OT_RADIO_CHANNEL_MAX, error = OT_ERROR_NOT_FOUND);
|
||||
|
||||
// find next channel in the Active Operational Dataset Channel Mask
|
||||
channel = mAnnounceChannel;
|
||||
|
||||
while (!channelMask->IsChannelSet(channel))
|
||||
while (!channelMask->IsChannelSet(mAnnounceChannel))
|
||||
{
|
||||
channel++;
|
||||
|
||||
if (channel > OT_RADIO_CHANNEL_MAX)
|
||||
{
|
||||
channel = OT_RADIO_CHANNEL_MIN;
|
||||
}
|
||||
|
||||
VerifyOrExit(channel != mAnnounceChannel);
|
||||
mAnnounceChannel++;
|
||||
VerifyOrExit(mAnnounceChannel <= OT_RADIO_CHANNEL_MAX, error = OT_ERROR_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Send Announce message
|
||||
SendAnnounce(channel, true);
|
||||
|
||||
// Move to next channel
|
||||
mAnnounceChannel = channel + 1;
|
||||
|
||||
if (mAnnounceChannel > OT_RADIO_CHANNEL_MAX)
|
||||
{
|
||||
mAnnounceChannel = OT_RADIO_CHANNEL_MIN;
|
||||
}
|
||||
SendAnnounce(mAnnounceChannel, true);
|
||||
mAnnounceChannel++;
|
||||
|
||||
exit:
|
||||
return;
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Mle::SendMessage(Message &aMessage, const Ip6::Address &aDestination)
|
||||
@@ -3709,5 +3775,98 @@ const char *Mle::RoleToString(otDeviceRole aRole)
|
||||
return roleString;
|
||||
}
|
||||
|
||||
#if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_MLE == 1)
|
||||
const char *Mle::AttachModeToString(AttachMode aMode)
|
||||
{
|
||||
const char *str = "unknown";
|
||||
|
||||
switch (aMode)
|
||||
{
|
||||
case kAttachAny:
|
||||
str = "any-partition";
|
||||
break;
|
||||
|
||||
case kAttachSame1:
|
||||
str = "same-partition-try-1";
|
||||
break;
|
||||
|
||||
case kAttachSame2:
|
||||
str = "same-partition-try-2";
|
||||
break;
|
||||
|
||||
case kAttachBetter:
|
||||
str = "better-partition";
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
const char *Mle::AttachStateToString(AttachState aState)
|
||||
{
|
||||
const char *str = "Unknown";
|
||||
|
||||
switch (aState)
|
||||
{
|
||||
case kAttachStateIdle:
|
||||
str = "Idle";
|
||||
break;
|
||||
|
||||
case kAttachStateSynchronize:
|
||||
str = "Sync";
|
||||
break;
|
||||
|
||||
case kAttachStateStart:
|
||||
str = "Start";
|
||||
break;
|
||||
|
||||
case kAttachStateParentRequestRouter:
|
||||
str = "ParentReqRouters";
|
||||
break;
|
||||
|
||||
case kAttachStateParentRequestReed:
|
||||
str = "ParentReqReeds";
|
||||
break;
|
||||
|
||||
case kAttachStateAnnounce:
|
||||
str = "Announce";
|
||||
break;
|
||||
|
||||
case kAttachStateChildIdRequest:
|
||||
str = "ChildIdReq";
|
||||
break;
|
||||
};
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
const char *Mle::ReattachStateToString(ReattachState aState)
|
||||
{
|
||||
const char *str = "unknown";
|
||||
|
||||
switch (aState)
|
||||
{
|
||||
case kReattachStop:
|
||||
str = "";
|
||||
break;
|
||||
|
||||
case kReattachStart:
|
||||
str = "reattaching";
|
||||
break;
|
||||
|
||||
case kReattachActive:
|
||||
str = "reattaching with Active Dataset";
|
||||
break;
|
||||
|
||||
case kReattachPending:
|
||||
str = "reattaching with Pending Dataset";
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
#endif // (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_MLE == 1)
|
||||
|
||||
} // namespace Mle
|
||||
} // namespace ot
|
||||
|
||||
+76
-32
@@ -958,6 +958,33 @@ public:
|
||||
static const char *RoleToString(otDeviceRole aRole);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* States during attach (when searching for a parent).
|
||||
*
|
||||
*/
|
||||
enum AttachState
|
||||
{
|
||||
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.
|
||||
kAttachStateAnnounce, ///< Send Announce messages
|
||||
kAttachStateChildIdRequest, ///< Sending a Child ID Request message.
|
||||
};
|
||||
|
||||
/**
|
||||
* States when reattaching network using stored dataset
|
||||
*
|
||||
*/
|
||||
enum ReattachState
|
||||
{
|
||||
kReattachStop = 0, ///< Reattach process is disabled or finished
|
||||
kReattachStart = 1, ///< Start reattach process
|
||||
kReattachActive = 2, ///< Reattach using stored Active Dataset
|
||||
kReattachPending = 3, ///< Reattach using stored Pending Dataset
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kMleMaxResponseDelay = 1000u, ///< Maximum delay before responding to a multicast request.
|
||||
@@ -979,6 +1006,14 @@ protected:
|
||||
*/
|
||||
void SetRole(otDeviceRole aRole);
|
||||
|
||||
/**
|
||||
* This method sets the attach state
|
||||
*
|
||||
* @param[in] aState An attach state
|
||||
*
|
||||
*/
|
||||
void SetAttachState(AttachState aState);
|
||||
|
||||
/**
|
||||
* This method appends an MLE header to a message.
|
||||
*
|
||||
@@ -1398,46 +1433,54 @@ protected:
|
||||
*/
|
||||
void InformPreviousChannel(void);
|
||||
|
||||
LeaderDataTlv mLeaderData; ///< Last received Leader Data TLV.
|
||||
bool mRetrieveNewNetworkData; ///< Indicating new Network Data is needed if set.
|
||||
|
||||
otDeviceRole mRole; ///< Current Thread role.
|
||||
Router mParent; ///< Parent information.
|
||||
uint8_t mDeviceMode; ///< Device mode setting.
|
||||
|
||||
#if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_MLE == 1)
|
||||
/**
|
||||
* States during attach (when searching for a parent).
|
||||
* This method converts an `AttachMode` enumeration value into a human-readable string.
|
||||
*
|
||||
* @param[in] aMode An attach mode
|
||||
*
|
||||
* @returns A human-readable string corresponding to the attach mode.
|
||||
*
|
||||
*/
|
||||
enum AttachState
|
||||
{
|
||||
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.
|
||||
};
|
||||
AttachState mAttachState; ///< The parent request state.
|
||||
static const char *AttachModeToString(AttachMode aMode);
|
||||
|
||||
/**
|
||||
* States when reattaching network using stored dataset
|
||||
* This method converts an `AttachState` enumeration value into a human-readable string.
|
||||
*
|
||||
* @param[in] aState An attach state
|
||||
*
|
||||
* @returns A human-readable string corresponding to the attach state.
|
||||
*
|
||||
*/
|
||||
enum ReattachState
|
||||
{
|
||||
kReattachStop = 0, ///< Reattach process is disabled or finished
|
||||
kReattachStart = 1, ///< Start reattach process
|
||||
kReattachActive = 2, ///< Reattach using stored Active Dataset
|
||||
kReattachPending = 3, ///< Reattach using stored Pending Dataset
|
||||
};
|
||||
ReattachState mReattachState;
|
||||
static const char *AttachStateToString(AttachState aState);
|
||||
|
||||
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.
|
||||
/**
|
||||
* This method converts a `ReattachState` enumeration value into a human-readable string.
|
||||
*
|
||||
* @param[in] aState A reattach state
|
||||
*
|
||||
* @returns A human-readable string corresponding to the reattach state.
|
||||
*
|
||||
*/
|
||||
static const char *ReattachStateToString(ReattachState aState);
|
||||
#endif
|
||||
|
||||
uint8_t mParentLeaderCost;
|
||||
LeaderDataTlv mLeaderData; ///< Last received Leader Data TLV.
|
||||
bool mRetrieveNewNetworkData; ///< Indicating new Network Data is needed if set.
|
||||
otDeviceRole mRole; ///< Current Thread role.
|
||||
Router mParent; ///< Parent information.
|
||||
uint8_t mDeviceMode; ///< Device mode setting.
|
||||
AttachState mAttachState; ///< The parent request state.
|
||||
ReattachState mReattachState; ///< Reattach state
|
||||
uint16_t mAttachCounter; ///< Attach attempt counter.
|
||||
uint16_t mAnnounceDelay; ///< Delay in between sending Announce messages during attach.
|
||||
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
|
||||
uint8_t mLastPartitionRouterIdSequence; ///< The router ID sequence from the previous Thread partition
|
||||
uint8_t mLastPartitionIdTimeout; ///< The time remaining to avoid the previous Thread partition
|
||||
uint8_t mParentLeaderCost;
|
||||
|
||||
private:
|
||||
enum
|
||||
@@ -1493,7 +1536,8 @@ private:
|
||||
|
||||
otError SendParentRequest(ParentRequestType aType);
|
||||
otError SendChildIdRequest(void);
|
||||
void SendOrphanAnnounce(void);
|
||||
otError SendOrphanAnnounce(void);
|
||||
bool PrepareAnnounceState(void);
|
||||
otError SendAnnounce(uint8_t aChannel, bool aOrphanAnnounce, const Ip6::Address &aDestination);
|
||||
uint32_t Reattach(void);
|
||||
|
||||
|
||||
@@ -61,6 +61,9 @@ enum
|
||||
kUdpPort = 19788, ///< MLE UDP Port
|
||||
kParentRequestRouterTimeout = 750, ///< Router Parent Request timeout
|
||||
kParentRequestReedTimeout = 1250, ///< Router and REEDs Parent Request timeout
|
||||
kParentRequestJitter = 50, ///< Maximum jitter time added to Parent Request timeout
|
||||
kAnnounceTimeout = 1400, ///< Total timeout used for sending Announcement messages
|
||||
kMinAnnounceDelay = 80, ///< Minimum delay between Announcement messages
|
||||
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.
|
||||
|
||||
@@ -296,7 +296,8 @@ otError MleRouter::SetStateRouter(uint16_t aRloc16)
|
||||
SetRloc16(aRloc16);
|
||||
|
||||
SetRole(OT_DEVICE_ROLE_ROUTER);
|
||||
mAttachState = kAttachStateIdle;
|
||||
SetAttachState(kAttachStateIdle);
|
||||
mAttachCounter = 0;
|
||||
mAttachTimer.Stop();
|
||||
mChildUpdateRequestTimer.Stop();
|
||||
mAdvertiseTimer.Stop();
|
||||
@@ -330,7 +331,8 @@ otError MleRouter::SetStateLeader(uint16_t aRloc16)
|
||||
SetRloc16(aRloc16);
|
||||
|
||||
SetRole(OT_DEVICE_ROLE_LEADER);
|
||||
mAttachState = kAttachStateIdle;
|
||||
SetAttachState(kAttachStateIdle);
|
||||
mAttachCounter = 0;
|
||||
mAttachTimer.Stop();
|
||||
mChildUpdateRequestTimer.Stop();
|
||||
mAdvertiseTimer.Stop();
|
||||
|
||||
@@ -127,5 +127,6 @@ run test-100-mcu-power-state.py
|
||||
run test-600-channel-manager-properties.py
|
||||
run test-601-channel-manager-channel-change.py
|
||||
run test-602-channel-manager-channel-select.py
|
||||
run test-603-channel-manager-announce-recovery.py
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (c) 2018, The OpenThread Authors.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the copyright holder nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from wpan import verify
|
||||
import wpan
|
||||
import time
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Test description: Orphaned node attach through MLE Announcement
|
||||
|
||||
test_name = __file__[:-3] if __file__.endswith('.py') else __file__
|
||||
print '-' * 120
|
||||
print 'Starting \'{}\''.format(test_name)
|
||||
|
||||
def verify_channel(nodes, new_channel, wait_time=20):
|
||||
"""
|
||||
This function checks the channel on a given list of `nodes` and verifies that all nodes
|
||||
switch to a given `new_channel` (as int) within certain `wait_time` (int and in seconds)
|
||||
"""
|
||||
start_time = time.time()
|
||||
|
||||
while not all([ (new_channel == int(node.get(wpan.WPAN_CHANNEL), 0)) for node in nodes ]):
|
||||
if time.time() - start_time > wait_time:
|
||||
print 'Took too long to switch to channel {} ({}>{} sec)'.format(new_channel, time.time() - start_time,
|
||||
wait_time)
|
||||
exit(1)
|
||||
time.sleep(0.1)
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Creating `wpan.Nodes` instances
|
||||
|
||||
router = wpan.Node()
|
||||
c1 = wpan.Node()
|
||||
c2 = wpan.Node()
|
||||
|
||||
all_nodes = [router, c1, c2]
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Init all nodes
|
||||
|
||||
wpan.Node.init_all_nodes()
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Build network topology
|
||||
|
||||
for node in all_nodes:
|
||||
node.set(wpan.WPAN_OT_LOG_LEVEL, '0')
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Test implementation
|
||||
|
||||
router.form('announce-tst', channel=11)
|
||||
|
||||
c1.join_node(router, node_type=wpan.JOIN_TYPE_SLEEPY_END_DEVICE)
|
||||
c2.join_node(router, node_type=wpan.JOIN_TYPE_SLEEPY_END_DEVICE)
|
||||
|
||||
c1.set(wpan.WPAN_POLL_INTERVAL, '500')
|
||||
c2.set(wpan.WPAN_POLL_INTERVAL, '500')
|
||||
|
||||
c1.set(wpan.WPAN_THREAD_DEVICE_MODE,'5')
|
||||
c2.set(wpan.WPAN_THREAD_DEVICE_MODE,'5')
|
||||
|
||||
# Reset c2 and keep it in detached state
|
||||
c2.set('Daemon:AutoAssociateAfterReset', 'false')
|
||||
c2.reset();
|
||||
|
||||
# Switch the rest of network to channel 26
|
||||
router.set(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL, '26')
|
||||
verify_channel([router, c1], 26)
|
||||
|
||||
# Now re-enable c2 and verify that it does attach to router and is on channel 26
|
||||
# c2 would go through the ML Announce recovery.
|
||||
|
||||
c2.set('Daemon:AutoAssociateAfterReset', 'true')
|
||||
c2.reset();
|
||||
verify(int(c2.get(wpan.WPAN_CHANNEL), 0) == 11)
|
||||
|
||||
# wait for 20s for c2 to be attached/associated
|
||||
start_time = time.time()
|
||||
wait_time = 20
|
||||
|
||||
while not c2.is_associated():
|
||||
if time.time() - start_time > wait_time:
|
||||
print 'Took too long to recover through ML Announce ({}>{} sec)'.format(time.time() - start_time, wait_time)
|
||||
exit(1)
|
||||
time.sleep(0.1)
|
||||
|
||||
# Check that c2 did attach and is on channel 26.
|
||||
verify(int(c2.get(wpan.WPAN_CHANNEL), 0) == 26)
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Test finished
|
||||
|
||||
print '\'{}\' passed.'.format(test_name)
|
||||
|
||||
Reference in New Issue
Block a user