From 927ac66735050cfd30bc542d5327ee8563aea7ae Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 8 Dec 2022 17:27:37 -0800 Subject: [PATCH] [mle] allow rx-on/off with no re-attach based on initial attach mode (#8498) This commit adds a new variable `mInitiallyAttachedAsSleepy` which tracks whether or not device was initially attached as a sleepy child. This is then used to determine whether or not we need to re-attach on mode changes between rx-on and sleepy (rx-off). If we initially attach as sleepy, then rx-on/off mode changes are allowed without re-attach (device sends "Child Update Request" to its parent to update its mode). Otherwise mode transition from rx-on to sleepy requires a re-attach. --- src/core/thread/mle.cpp | 56 ++++++++++++++++++++++++++++++++--------- src/core/thread/mle.hpp | 1 + 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 8a623c785..587af99fe 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -91,6 +91,7 @@ Mle::Mle(Instance &aInstance) , mAddressRegistrationMode(kAppendAllAddresses) , mHasRestored(false) , mReceivedResponseFromParent(false) + , mInitiallyAttachedAsSleepy(false) , mSocket(aInstance) , mTimeout(kMleEndDeviceTimeout) #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE @@ -329,6 +330,17 @@ void Mle::SetRole(DeviceRole aRole) mParent.SetState(Neighbor::kStateInvalid); } + if ((oldRole == kRoleDetached) && IsChild()) + { + // On transition from detached to child, we remember whether we + // attached as sleepy or not. This is then used to determine + // whether or not we need to re-attach on mode changes between + // rx-on and sleepy (rx-off). If we initially attach as sleepy, + // then rx-on/off mode changes are allowed without re-attach. + + mInitiallyAttachedAsSleepy = !GetDeviceMode().IsRxOnWhenIdle(); + } + exit: return; } @@ -682,10 +694,11 @@ void Mle::SetStateDetached(void) SetAttachState(kAttachStateIdle); mAttachTimer.Stop(); mMessageTransmissionTimer.Stop(); - mChildUpdateRequestState = kChildUpdateRequestNone; - mChildUpdateAttempts = 0; - mDataRequestState = kDataRequestNone; - mDataRequestAttempts = 0; + mChildUpdateRequestState = kChildUpdateRequestNone; + mChildUpdateAttempts = 0; + mDataRequestState = kDataRequestNone; + mDataRequestAttempts = 0; + mInitiallyAttachedAsSleepy = false; Get().SetRxOnWhenIdle(true); Get().SetBeaconEnabled(false); #if OPENTHREAD_FTD @@ -809,15 +822,34 @@ Error Mle::SetDeviceMode(DeviceMode aDeviceMode) IgnoreError(Store()); - // We need to re-attach on switching between MTD/FTD modes - // and also on switching from rx-on to sleepy (rx-off) mode. - - if (IsAttached() && ((oldMode.IsFullThreadDevice() != mDeviceMode.IsFullThreadDevice()) || - (oldMode.IsRxOnWhenIdle() && !mDeviceMode.IsRxOnWhenIdle()))) + if (IsAttached()) { - mAttachCounter = 0; - IgnoreError(BecomeDetached()); - ExitNow(); + bool shouldReattach = false; + + // We need to re-attach when switching between MTD/FTD modes. + + if (oldMode.IsFullThreadDevice() != mDeviceMode.IsFullThreadDevice()) + { + shouldReattach = true; + } + + // If we initially attached as sleepy we allow mode changes + // between rx-on/off without a re-attach (we send "Child Update + // Request" to update the parent). But if we initially attached + // as rx-on, we require a re-attach on switching from rx-on to + // sleepy (rx-off) mode. + + if (!mInitiallyAttachedAsSleepy && oldMode.IsRxOnWhenIdle() && !mDeviceMode.IsRxOnWhenIdle()) + { + shouldReattach = true; + } + + if (shouldReattach) + { + mAttachCounter = 0; + IgnoreError(BecomeDetached()); + ExitNow(); + } } if (IsDetached()) diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index ade084c9d..8ddf74151 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -2011,6 +2011,7 @@ private: bool mHasRestored; bool mReceivedResponseFromParent; + bool mInitiallyAttachedAsSleepy; Ip6::Udp::Socket mSocket; uint32_t mTimeout;