blob: 1ca1645ece645081315f6066a627cebc51168235 [file] [log] [blame]
/*
* Copyright (c) 2016, 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.
*/
/**
* @file
* This file includes definitions for MLE functionality required by the Thread Child, Router, and Leader roles.
*/
#ifndef MLE_HPP_
#define MLE_HPP_
#include "openthread-core-config.h"
#include "common/callback.hpp"
#include "common/encoding.hpp"
#include "common/locator.hpp"
#include "common/log.hpp"
#include "common/non_copyable.hpp"
#include "common/notifier.hpp"
#include "common/timer.hpp"
#include "crypto/aes_ccm.hpp"
#include "mac/mac.hpp"
#include "meshcop/joiner_router.hpp"
#include "meshcop/meshcop.hpp"
#include "net/udp6.hpp"
#include "thread/child.hpp"
#include "thread/link_metrics.hpp"
#include "thread/link_metrics_tlvs.hpp"
#include "thread/mle_tlvs.hpp"
#include "thread/mle_types.hpp"
#include "thread/neighbor_table.hpp"
#include "thread/network_data_types.hpp"
#include "thread/router.hpp"
namespace ot {
/**
* @addtogroup core-mle MLE
*
* @brief
* This module includes definitions for the MLE protocol.
*
* @{
*
* @defgroup core-mle-core Core
* @defgroup core-mle-router Router
* @defgroup core-mle-tlvs TLVs
*
* @}
*/
class SupervisionListener;
class UnitTester;
/**
* @namespace ot::Mle
*
* @brief
* This namespace includes definitions for the MLE protocol.
*/
namespace Mle {
/**
* @addtogroup core-mle-core
*
* @brief
* This module includes definitions for MLE functionality required by the Thread Child, Router, and Leader roles.
*
* @{
*
*/
class MleRouter;
/**
* Implements MLE functionality required by the Thread EndDevices, Router, and Leader roles.
*
*/
class Mle : public InstanceLocator, private NonCopyable
{
friend class MleRouter;
friend class DiscoverScanner;
friend class ot::Instance;
friend class ot::Notifier;
friend class ot::SupervisionListener;
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
friend class ot::LinkMetrics::Initiator;
#endif
friend class ot::UnitTester;
public:
/**
* Initializes the MLE object.
*
* @param[in] aInstance A reference to the OpenThread instance.
*
*/
explicit Mle(Instance &aInstance);
/**
* Enables MLE.
*
* @retval kErrorNone Successfully enabled MLE.
* @retval kErrorAlready MLE was already enabled.
*
*/
Error Enable(void);
/**
* Disables MLE.
*
* @retval kErrorNone Successfully disabled MLE.
*
*/
Error Disable(void);
/**
* Starts the MLE protocol operation.
*
* @retval kErrorNone Successfully started the protocol operation.
* @retval kErrorInvalidState IPv6 interface is down or device is in raw-link mode.
*
*/
Error Start(void) { return Start(kNormalAttach); }
/**
* Stops the MLE protocol operation.
*
*/
void Stop(void) { Stop(kUpdateNetworkDatasets); }
/**
* Restores network information from non-volatile memory (if any).
*
*/
void Restore(void);
/**
* Stores network information into non-volatile memory.
*
* @retval kErrorNone Successfully store the network information.
* @retval kErrorNoBufs Could not store the network information due to insufficient memory space.
*
*/
Error Store(void);
/**
* Generates an MLE Announce message.
*
* @param[in] aChannel The channel to use when transmitting.
*
*/
void SendAnnounce(uint8_t aChannel) { SendAnnounce(aChannel, kNormalAnnounce); }
/**
* Causes the Thread interface to detach from the Thread network.
*
* @retval kErrorNone Successfully detached from the Thread network.
* @retval kErrorInvalidState MLE is Disabled.
*
*/
Error BecomeDetached(void);
/**
* Causes the Thread interface to attempt an MLE attach.
*
* @retval kErrorNone Successfully began the attach process.
* @retval kErrorInvalidState MLE is Disabled.
* @retval kErrorBusy An attach process is in progress.
*
*/
Error BecomeChild(void);
/**
* Notifies other nodes in the network (if any) and then stops Thread protocol operation.
*
* It sends an Address Release if it's a router, or sets its child timeout to 0 if it's a child.
*
* @param[in] aCallback A pointer to a function that is called upon finishing detaching.
* @param[in] aContext A pointer to callback application-specific context.
*
* @retval kErrorNone Successfully started detaching.
* @retval kErrorBusy Detaching is already in progress.
*
*/
Error DetachGracefully(otDetachGracefullyCallback aCallback, void *aContext);
/**
* Indicates whether or not the Thread device is attached to a Thread network.
*
* @retval TRUE Attached to a Thread network.
* @retval FALSE Not attached to a Thread network.
*
*/
bool IsAttached(void) const;
/**
* Indicates whether device is currently attaching or not.
*
* Note that an already attached device may also be in attaching state. Examples of this include a leader/router
* trying to attach to a better partition, or a child trying to find a better parent (when feature
* `OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE` is enabled).
*
* @retval TRUE Device is currently trying to attach.
* @retval FALSE Device is not in middle of attach process.
*
*/
bool IsAttaching(void) const { return (mAttachState != kAttachStateIdle); }
/**
* Returns the current Thread device role.
*
* @returns The current Thread device role.
*
*/
DeviceRole GetRole(void) const { return mRole; }
/**
* Indicates whether device role is disabled.
*
* @retval TRUE Device role is disabled.
* @retval FALSE Device role is not disabled.
*
*/
bool IsDisabled(void) const { return (mRole == kRoleDisabled); }
/**
* Indicates whether device role is detached.
*
* @retval TRUE Device role is detached.
* @retval FALSE Device role is not detached.
*
*/
bool IsDetached(void) const { return (mRole == kRoleDetached); }
/**
* Indicates whether device role is child.
*
* @retval TRUE Device role is child.
* @retval FALSE Device role is not child.
*
*/
bool IsChild(void) const { return (mRole == kRoleChild); }
/**
* Indicates whether device role is router.
*
* @retval TRUE Device role is router.
* @retval FALSE Device role is not router.
*
*/
bool IsRouter(void) const { return (mRole == kRoleRouter); }
/**
* Indicates whether device role is leader.
*
* @retval TRUE Device role is leader.
* @retval FALSE Device role is not leader.
*
*/
bool IsLeader(void) const { return (mRole == kRoleLeader); }
/**
* Indicates whether device role is either router or leader.
*
* @retval TRUE Device role is either router or leader.
* @retval FALSE Device role is neither router nor leader.
*
*/
bool IsRouterOrLeader(void) const;
/**
* Returns the Device Mode as reported in the Mode TLV.
*
* @returns The Device Mode as reported in the Mode TLV.
*
*/
DeviceMode GetDeviceMode(void) const { return mDeviceMode; }
/**
* Sets the Device Mode as reported in the Mode TLV.
*
* @param[in] aDeviceMode The device mode to set.
*
* @retval kErrorNone Successfully set the Mode TLV.
* @retval kErrorInvalidArgs The mode combination specified in @p aMode is invalid.
*
*/
Error SetDeviceMode(DeviceMode aDeviceMode);
/**
* Indicates whether or not the device is rx-on-when-idle.
*
* @returns TRUE if rx-on-when-idle, FALSE otherwise.
*
*/
bool IsRxOnWhenIdle(void) const { return mDeviceMode.IsRxOnWhenIdle(); }
/**
* Indicates whether or not the device is a Full Thread Device.
*
* @returns TRUE if a Full Thread Device, FALSE otherwise.
*
*/
bool IsFullThreadDevice(void) const { return mDeviceMode.IsFullThreadDevice(); }
/**
* Indicates whether or not the device is a Minimal End Device.
*
* @returns TRUE if the device is a Minimal End Device, FALSE otherwise.
*
*/
bool IsMinimalEndDevice(void) const { return mDeviceMode.IsMinimalEndDevice(); }
/**
* Gets the Network Data type (full set or stable subset) that this device requests.
*
* @returns The Network Data type requested by this device.
*
*/
NetworkData::Type GetNetworkDataType(void) const { return mDeviceMode.GetNetworkDataType(); }
/**
* Returns a pointer to the Mesh Local Prefix.
*
* @returns A reference to the Mesh Local Prefix.
*
*/
const Ip6::NetworkPrefix &GetMeshLocalPrefix(void) const { return mMeshLocal16.GetAddress().GetPrefix(); }
/**
* Sets the Mesh Local Prefix.
*
* @param[in] aMeshLocalPrefix A reference to the Mesh Local Prefix.
*
*/
void SetMeshLocalPrefix(const Ip6::NetworkPrefix &aMeshLocalPrefix);
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
/**
* Sets the Mesh Local IID.
*
* Available only when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled.
*
* @param[in] aMlIid The Mesh Local IID.
*
* @retval kErrorNone Successfully configured Mesh Local IID.
* @retval kErrorInvalidState If the Thread stack is already enabled.
*
*/
Error SetMeshLocalIid(const Ip6::InterfaceIdentifier &aMlIid);
#endif
/**
* Applies the Mesh Local Prefix.
*
*/
void ApplyMeshLocalPrefix(void);
/**
* Returns a reference to the Thread link-local address.
*
* The Thread link local address is derived using IEEE802.15.4 Extended Address as Interface Identifier.
*
* @returns A reference to the Thread link local address.
*
*/
const Ip6::Address &GetLinkLocalAddress(void) const { return mLinkLocal64.GetAddress(); }
/**
* Updates the link local address.
*
* Call this method when the IEEE 802.15.4 Extended Address has changed.
*
*/
void UpdateLinkLocalAddress(void);
/**
* Returns a reference to the link-local all Thread nodes multicast address.
*
* @returns A reference to the link-local all Thread nodes multicast address.
*
*/
const Ip6::Address &GetLinkLocalAllThreadNodesAddress(void) const { return mLinkLocalAllThreadNodes.GetAddress(); }
/**
* Returns a reference to the realm-local all Thread nodes multicast address.
*
* @returns A reference to the realm-local all Thread nodes multicast address.
*
*/
const Ip6::Address &GetRealmLocalAllThreadNodesAddress(void) const
{
return mRealmLocalAllThreadNodes.GetAddress();
}
/**
* Gets the parent when operating in End Device mode.
*
* @returns A reference to the parent.
*
*/
Parent &GetParent(void) { return mParent; }
/**
* Gets the parent when operating in End Device mode.
*
* @returns A reference to the parent.
*
*/
const Parent &GetParent(void) const { return mParent; }
/**
* The method retrieves information about the parent.
*
* @param[out] aParentInfo Reference to a parent information structure.
*
* @retval kErrorNone Successfully retrieved the parent info and updated @p aParentInfo.
* @retval kErrorInvalidState Device role is not child.
*
*/
Error GetParentInfo(Router::Info &aParentInfo) const;
/**
* Get the parent candidate.
*
* The parent candidate is valid when attempting to attach to a new parent.
*
*/
Parent &GetParentCandidate(void) { return mParentCandidate; }
/**
* Starts the process for child to search for a better parent while staying attached to its current
* parent
*
* @retval kErrorNone Successfully started the process to search for a better parent.
* @retval kErrorInvalidState Device role is not child.
*
*/
Error SearchForBetterParent(void);
/**
* Indicates whether or not an IPv6 address is an RLOC.
*
* @retval TRUE If @p aAddress is an RLOC.
* @retval FALSE If @p aAddress is not an RLOC.
*
*/
bool IsRoutingLocator(const Ip6::Address &aAddress) const;
/**
* Indicates whether or not an IPv6 address is an ALOC.
*
* @retval TRUE If @p aAddress is an ALOC.
* @retval FALSE If @p aAddress is not an ALOC.
*
*/
bool IsAnycastLocator(const Ip6::Address &aAddress) const;
/**
* Indicates whether or not an IPv6 address is a Mesh Local Address.
*
* @retval TRUE If @p aAddress is a Mesh Local Address.
* @retval FALSE If @p aAddress is not a Mesh Local Address.
*
*/
bool IsMeshLocalAddress(const Ip6::Address &aAddress) const;
/**
* Returns the MLE Timeout value.
*
* @returns The MLE Timeout value in seconds.
*
*/
uint32_t GetTimeout(void) const { return mTimeout; }
/**
* Sets the MLE Timeout value.
*
* @param[in] aTimeout The Timeout value in seconds.
*
*/
void SetTimeout(uint32_t aTimeout);
/**
* Returns the RLOC16 assigned to the Thread interface.
*
* @returns The RLOC16 assigned to the Thread interface.
*
*/
uint16_t GetRloc16(void) const { return mRloc16; }
/**
* Returns a reference to the RLOC assigned to the Thread interface.
*
* @returns A reference to the RLOC assigned to the Thread interface.
*
*/
const Ip6::Address &GetMeshLocal16(void) const { return mMeshLocal16.GetAddress(); }
/**
* Returns a reference to the ML-EID assigned to the Thread interface.
*
* @returns A reference to the ML-EID assigned to the Thread interface.
*
*/
const Ip6::Address &GetMeshLocal64(void) const { return mMeshLocal64.GetAddress(); }
/**
* Returns the Router ID of the Leader.
*
* @returns The Router ID of the Leader.
*
*/
uint8_t GetLeaderId(void) const { return mLeaderData.GetLeaderRouterId(); }
/**
* Retrieves the Leader's RLOC.
*
* @param[out] aAddress A reference to the Leader's RLOC.
*
* @retval kErrorNone Successfully retrieved the Leader's RLOC.
* @retval kErrorDetached The Thread interface is not currently attached to a Thread Partition.
*
*/
Error GetLeaderAddress(Ip6::Address &aAddress) const;
/**
* Retrieves the Leader's ALOC.
*
* @param[out] aAddress A reference to the Leader's ALOC.
*
* @retval kErrorNone Successfully retrieved the Leader's ALOC.
* @retval kErrorDetached The Thread interface is not currently attached to a Thread Partition.
*
*/
Error GetLeaderAloc(Ip6::Address &aAddress) const { return GetLocatorAddress(aAddress, kAloc16Leader); }
/**
* Computes the Commissioner's ALOC.
*
* @param[out] aAddress A reference to the Commissioner's ALOC.
* @param[in] aSessionId Commissioner session id.
*
* @retval kErrorNone Successfully retrieved the Commissioner's ALOC.
* @retval kErrorDetached The Thread interface is not currently attached to a Thread Partition.
*
*/
Error GetCommissionerAloc(Ip6::Address &aAddress, uint16_t aSessionId) const
{
return GetLocatorAddress(aAddress, CommissionerAloc16FromId(aSessionId));
}
/**
* Retrieves the Service ALOC for given Service ID.
*
* @param[in] aServiceId Service ID to get ALOC for.
* @param[out] aAddress A reference to the Service ALOC.
*
* @retval kErrorNone Successfully retrieved the Service ALOC.
* @retval kErrorDetached The Thread interface is not currently attached to a Thread Partition.
*
*/
Error GetServiceAloc(uint8_t aServiceId, Ip6::Address &aAddress) const;
/**
* Returns the most recently received Leader Data.
*
* @returns A reference to the most recently received Leader Data.
*
*/
const LeaderData &GetLeaderData(void);
/**
* Returns a reference to the send queue.
*
* @returns A reference to the send queue.
*
*/
const MessageQueue &GetMessageQueue(void) const { return mDelayedResponses; }
/**
* Frees multicast MLE Data Response from Delayed Message Queue if any.
*
*/
void RemoveDelayedDataResponseMessage(void);
/**
* Gets the MLE counters.
*
* @returns A reference to the MLE counters.
*
*/
const Counters &GetCounters(void)
{
#if OPENTHREAD_CONFIG_UPTIME_ENABLE
UpdateRoleTimeCounters(mRole);
#endif
return mCounters;
}
/**
* Resets the MLE counters.
*
*/
void ResetCounters(void);
#if OPENTHREAD_CONFIG_MLE_PARENT_RESPONSE_CALLBACK_API_ENABLE
/**
* Registers the client callback that is called when processing an MLE Parent Response message.
*
* @param[in] aCallback A pointer to a function that is called to deliver MLE Parent Response data.
* @param[in] aContext A pointer to application-specific context.
*
*/
void RegisterParentResponseStatsCallback(otThreadParentResponseCallback aCallback, void *aContext)
{
mParentResponseCallback.Set(aCallback, aContext);
}
#endif
/**
* Notifies MLE whether the Child ID Request message was transmitted successfully.
*
* @param[in] aMessage The transmitted message.
*
*/
void HandleChildIdRequestTxDone(Message &aMessage);
/**
* Requests MLE layer to prepare and send a shorter version of Child ID Request message by only
* including the mesh-local IPv6 address in the Address Registration TLV.
*
* Should be called when a previous MLE Child ID Request message would require fragmentation at 6LoWPAN
* layer.
*
*/
void RequestShorterChildIdRequest(void);
/**
* Gets the RLOC or ALOC of a given RLOC16 or ALOC16.
*
* @param[out] aAddress A reference to the RLOC or ALOC.
* @param[in] aLocator RLOC16 or ALOC16.
*
* @retval kErrorNone If got the RLOC or ALOC successfully.
* @retval kErrorDetached If device is detached.
*
*/
Error GetLocatorAddress(Ip6::Address &aAddress, uint16_t aLocator) const;
/**
* Schedules a Child Update Request.
*
*/
void ScheduleChildUpdateRequest(void);
/*
* Indicates whether or not the device has restored the network information from
* non-volatile settings after boot.
*
* @retval true Successfully restored the network information.
* @retval false No valid network information was found.
*
*/
bool HasRestored(void) const { return mHasRestored; }
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
/**
* Gets the CSL timeout.
*
* @returns CSL timeout
*
*/
uint32_t GetCslTimeout(void) const { return mCslTimeout; }
/**
* Sets the CSL timeout.
*
* @param[in] aTimeout The CSL timeout in seconds.
*
*/
void SetCslTimeout(uint32_t aTimeout);
/**
* Calculates CSL metric of parent.
*
* @param[in] aCslAccuracy The CSL accuracy.
*
* @returns CSL metric.
*
*/
uint64_t CalcParentCslMetric(const Mac::CslAccuracy &aCslAccuracy) const;
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
private:
//------------------------------------------------------------------------------------------------------------------
// Constants
// All time intervals are in milliseconds
static constexpr uint32_t kParentRequestRouterTimeout = 750; // Wait time after tx of Parent Req to routers
static constexpr uint32_t kParentRequestReedTimeout = 1250; // Wait timer after tx of Parent Req to REEDs
static constexpr uint32_t kParentRequestDuplicateMargin = 50; // Margin to detect duplicate received Parent Req
static constexpr uint32_t kChildIdResponseTimeout = 1250; // Wait time to receive Child ID Response
static constexpr uint32_t kAttachStartJitter = 50; // Max jitter time added to start of attach
static constexpr uint32_t kAnnounceProcessTimeout = 250; // Delay after Announce rx before processing
static constexpr uint32_t kAnnounceTimeout = 1400; // Total timeout for sending Announce messages
static constexpr uint16_t kMinAnnounceDelay = 80; // Min delay between Announcement messages
static constexpr uint32_t kParentResponseMaxDelayRouters = 500; // Max response delay for Parent Req to routers
static constexpr uint32_t kParentResponseMaxDelayAll = 1000; // Max response delay for Parent Req to all
static constexpr uint32_t kChildUpdateRequestPendingDelay = 100; // Delay for aggregating Child Update Req
static constexpr uint32_t kMaxLinkAcceptDelay = 1000; // Max delay to tx Link Accept for multicast Req
static constexpr uint32_t kChildIdRequestTimeout = 5000; // Max delay to rx a Child ID Req after Parent Res
static constexpr uint32_t kLinkRequestTimeout = 2000; // Max delay to rx a Link Accept
static constexpr uint32_t kDetachGracefullyTimeout = 1000; // Timeout for graceful detach
static constexpr uint32_t kUnicastRetxDelay = 1000; // Base delay for MLE unicast retx
static constexpr uint32_t kMulticastRetxDelay = 5000; // Base delay for MLE multicast retx
static constexpr uint32_t kMulticastRetxDelayMin = kMulticastRetxDelay * 9 / 10; // 0.9 * base delay
static constexpr uint32_t kMulticastRetxDelayMax = kMulticastRetxDelay * 11 / 10; // 1.1 * base delay
static constexpr uint8_t kMaxTxCount = 3; // Max tx count for MLE message
static constexpr uint8_t kMaxCriticalTxCount = 6; // Max tx count for critical MLE message
static constexpr uint8_t kMaxChildKeepAliveAttempts = 4; // Max keep alive attempts before reattach
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Attach backoff feature (CONFIG_ENABLE_ATTACH_BACKOFF) - Intervals are in milliseconds.
static constexpr uint32_t kAttachBackoffMinInterval = OPENTHREAD_CONFIG_MLE_ATTACH_BACKOFF_MINIMUM_INTERVAL;
static constexpr uint32_t kAttachBackoffMaxInterval = OPENTHREAD_CONFIG_MLE_ATTACH_BACKOFF_MAXIMUM_INTERVAL;
static constexpr uint32_t kAttachBackoffJitter = OPENTHREAD_CONFIG_MLE_ATTACH_BACKOFF_JITTER_INTERVAL;
static constexpr uint32_t kAttachBackoffDelayToResetCounter =
OPENTHREAD_CONFIG_MLE_ATTACH_BACKOFF_DELAY_TO_RESET_BACKOFF_INTERVAL;
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Number of Parent Requests in first and next attach cycles
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_3
// First attach cycle includes two Parent Requests to routers, followed by four to routers and REEDs.
static constexpr uint8_t kFirstAttachCycleTotalParentRequests = 6;
static constexpr uint8_t kFirstAttachCycleNumParentRequestToRouters = 2;
#else
// First attach cycle in Thread 1.1/1.2 includes a Parent Requests to routers, followed by one to routers and REEDs.
static constexpr uint8_t kFirstAttachCycleTotalParentRequests = 2;
static constexpr uint8_t kFirstAttachCycleNumParentRequestToRouters = 1;
#endif
// Next attach cycles includes one Parent Request to routers, followed by one to routers and REEDs.
static constexpr uint8_t kNextAttachCycleTotalParentRequests = 2;
static constexpr uint8_t kNextAttachCycleNumParentRequestToRouters = 1;
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
static constexpr uint8_t kMaxServiceAlocs = OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_MAX_ALOCS + 1;
#else
static constexpr uint8_t kMaxServiceAlocs = OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_MAX_ALOCS;
#endif
static constexpr uint8_t kMleHopLimit = 255;
static constexpr uint8_t kMleSecurityTagSize = 4;
static constexpr uint32_t kStoreFrameCounterAhead = OPENTHREAD_CONFIG_STORE_FRAME_COUNTER_AHEAD;
static constexpr uint8_t kMaxIpAddressesToRegister = OPENTHREAD_CONFIG_MLE_IP_ADDRS_TO_REGISTER;
static constexpr uint32_t kDefaultChildTimeout = OPENTHREAD_CONFIG_MLE_CHILD_TIMEOUT_DEFAULT;
static constexpr uint32_t kDefaultCslTimeout = OPENTHREAD_CONFIG_CSL_TIMEOUT;
//------------------------------------------------------------------------------------------------------------------
// Enumerations
enum Command : uint8_t
{
kCommandLinkRequest = 0,
kCommandLinkAccept = 1,
kCommandLinkAcceptAndRequest = 2,
kCommandLinkReject = 3,
kCommandAdvertisement = 4,
kCommandUpdate = 5,
kCommandUpdateRequest = 6,
kCommandDataRequest = 7,
kCommandDataResponse = 8,
kCommandParentRequest = 9,
kCommandParentResponse = 10,
kCommandChildIdRequest = 11,
kCommandChildIdResponse = 12,
kCommandChildUpdateRequest = 13,
kCommandChildUpdateResponse = 14,
kCommandAnnounce = 15,
kCommandDiscoveryRequest = 16,
kCommandDiscoveryResponse = 17,
kCommandLinkMetricsManagementRequest = 18,
kCommandLinkMetricsManagementResponse = 19,
kCommandLinkProbe = 20,
kCommandTimeSync = 99,
};
enum AttachMode : uint8_t
{
kAnyPartition, // Attach to any Thread partition.
kSamePartition, // Attach to the same Thread partition (when losing connectivity).
kBetterPartition, // Attach to a better (i.e. higher weight/partition id) Thread partition.
kDowngradeToReed, // Attach to the same Thread partition during downgrade process.
kBetterParent, // Attach to a better parent.
};
enum AttachState : uint8_t
{
kAttachStateIdle, // Not currently searching for a parent.
kAttachStateProcessAnnounce, // Waiting to process a received Announce (to switch channel/pan-id).
kAttachStateStart, // Starting to look for a parent.
kAttachStateParentRequest, // Send Parent Request (current number tracked by `mParentRequestCounter`).
kAttachStateAnnounce, // Send Announce messages
kAttachStateChildIdRequest, // Sending a Child ID Request message.
};
enum ReattachState : uint8_t
{
kReattachStop, // Reattach process is disabled or finished
kReattachStart, // Start reattach process
kReattachActive, // Reattach using stored Active Dataset
kReattachPending, // Reattach using stored Pending Dataset
};
static constexpr uint16_t kMleMaxResponseDelay = 1000u; // Max delay before responding to a multicast request.
enum AddressRegistrationMode : uint8_t // Used by `AppendAddressRegistrationTlv()`
{
kAppendAllAddresses, // Append all addresses (unicast/multicast) in Address Registration TLV.
kAppendMeshLocalOnly, // Only append the Mesh Local (ML-EID) address in Address Registration TLV.
};
enum StartMode : uint8_t // Used in `Start()`.
{
kNormalAttach,
kAnnounceAttach, // Try to attach on the announced thread network with newer active timestamp.
};
enum StopMode : uint8_t // Used in `Stop()`.
{
kKeepNetworkDatasets,
kUpdateNetworkDatasets,
};
enum AnnounceMode : uint8_t // Used in `SendAnnounce()`
{
kNormalAnnounce,
kOrphanAnnounce,
};
enum ParentRequestType : uint8_t
{
kToRouters, // Parent Request to routers only.
kToRoutersAndReeds, // Parent Request to all routers and REEDs.
};
enum ChildUpdateRequestState : uint8_t
{
kChildUpdateRequestNone, // No pending or active Child Update Request.
kChildUpdateRequestPending, // Pending Child Update Request due to relative OT_CHANGED event.
kChildUpdateRequestActive, // Child Update Request has been sent and Child Update Response is expected.
};
enum ChildUpdateRequestMode : uint8_t // Used in `SendChildUpdateRequest()`
{
kNormalChildUpdateRequest, // Normal Child Update Request.
kAppendChallengeTlv, // Append Challenge TLV to Child Update Request even if currently attached.
kAppendZeroTimeout, // Use zero timeout when appending Timeout TLV (used for graceful detach).
};
enum DataRequestState : uint8_t
{
kDataRequestNone, // Not waiting for a Data Response.
kDataRequestActive, // Data Request has been sent, Data Response is expected.
};
enum SecuritySuite : uint8_t
{
k154Security = 0, // Security suite value indicating that MLE message is not secured.
kNoSecurity = 255, // Security suite value indicating that MLE message is secured.
};
enum MessageAction : uint8_t
{
kMessageSend,
kMessageReceive,
kMessageDelay,
kMessageRemoveDelayed,
};
enum MessageType : uint8_t
{
kTypeAdvertisement,
kTypeAnnounce,
kTypeChildIdRequest,
kTypeChildIdRequestShort,
kTypeChildIdResponse,
kTypeChildUpdateRequestOfParent,
kTypeChildUpdateResponseOfParent,
kTypeDataRequest,
kTypeDataResponse,
kTypeDiscoveryRequest,
kTypeDiscoveryResponse,
kTypeGenericDelayed,
kTypeGenericUdp,
kTypeParentRequestToRouters,
kTypeParentRequestToRoutersReeds,
kTypeParentResponse,
#if OPENTHREAD_FTD
kTypeAddressRelease,
kTypeAddressReleaseReply,
kTypeAddressReply,
kTypeAddressSolicit,
kTypeChildUpdateRequestOfChild,
kTypeChildUpdateResponseOfChild,
kTypeChildUpdateResponseOfUnknownChild,
kTypeLinkAccept,
kTypeLinkAcceptAndRequest,
kTypeLinkReject,
kTypeLinkRequest,
kTypeParentRequest,
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
kTypeTimeSync,
#endif
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
kTypeLinkMetricsManagementRequest,
kTypeLinkMetricsManagementResponse,
kTypeLinkProbe,
#endif
};
//------------------------------------------------------------------------------------------------------------------
// Nested types
static constexpr uint8_t kMaxTlvListSize = 32; // Maximum number of TLVs in a `TlvList`.
class TlvList : public Array<uint8_t, kMaxTlvListSize>
{
public:
TlvList(void) = default;
void Add(uint8_t aTlvType);
void AddElementsFrom(const TlvList &aTlvList);
};
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class TxMessage : public Message
{
public:
Error AppendSourceAddressTlv(void);
Error AppendModeTlv(DeviceMode aMode);
Error AppendTimeoutTlv(uint32_t aTimeout);
Error AppendChallengeTlv(const TxChallenge &aChallenge);
Error AppendResponseTlv(const RxChallenge &aResponse);
Error AppendLinkFrameCounterTlv(void);
Error AppendMleFrameCounterTlv(void);
Error AppendAddress16Tlv(uint16_t aRloc16);
Error AppendNetworkDataTlv(NetworkData::Type aType);
Error AppendTlvRequestTlv(const uint8_t *aTlvs, uint8_t aTlvsLength);
Error AppendLeaderDataTlv(void);
Error AppendScanMaskTlv(uint8_t aScanMask);
Error AppendStatusTlv(StatusTlv::Status aStatus);
Error AppendLinkMarginTlv(uint8_t aLinkMargin);
Error AppendVersionTlv(void);
Error AppendAddressRegistrationTlv(AddressRegistrationMode aMode = kAppendAllAddresses);
Error AppendSupervisionIntervalTlv(uint16_t aInterval);
Error AppendXtalAccuracyTlv(void);
Error AppendActiveTimestampTlv(void);
Error AppendPendingTimestampTlv(void);
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
Error AppendTimeRequestTlv(void);
Error AppendTimeParameterTlv(void);
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
Error AppendCslChannelTlv(void);
Error AppendCslTimeoutTlv(void);
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
Error AppendCslClockAccuracyTlv(void);
#endif
#if OPENTHREAD_FTD
Error AppendRouteTlv(Neighbor *aNeighbor = nullptr);
Error AppendActiveDatasetTlv(void);
Error AppendPendingDatasetTlv(void);
Error AppendConnectivityTlv(void);
Error AppendAddressRegistrationTlv(Child &aChild);
#endif
template <uint8_t kArrayLength> Error AppendTlvRequestTlv(const uint8_t (&aTlvArray)[kArrayLength])
{
return AppendTlvRequestTlv(aTlvArray, kArrayLength);
}
Error SendTo(const Ip6::Address &aDestination);
Error SendAfterDelay(const Ip6::Address &aDestination, uint16_t aDelay);
private:
Error AppendCompressedAddressEntry(uint8_t aContextId, const Ip6::Address &aAddress);
Error AppendAddressEntry(const Ip6::Address &aAddress);
};
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class RxMessage : public Message
{
public:
Error ReadChallengeTlv(RxChallenge &aChallenge) const;
Error ReadResponseTlv(RxChallenge &aResponse) const;
Error ReadFrameCounterTlvs(uint32_t &aLinkFrameCounter, uint32_t &aMleFrameCounter) const;
Error ReadTlvRequestTlv(TlvList &aTlvList) const;
Error ReadLeaderDataTlv(LeaderData &aLeaderData) const;
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
Error ReadCslClockAccuracyTlv(Mac::CslAccuracy &aCslAccuracy) const;
#endif
#if OPENTHREAD_FTD
Error ReadRouteTlv(RouteTlv &aRouteTlv) const;
#endif
private:
Error ReadChallengeOrResponse(uint8_t aTlvType, RxChallenge &aRxChallenge) const;
};
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
struct RxInfo
{
enum Class : uint8_t
{
kUnknown, // Unknown (default value, also indicates MLE message parse error).
kAuthoritativeMessage, // Authoritative message (larger received key seq MUST be adopted).
kPeerMessage, // Peer message (adopt only if from a known neighbor and is greater by one).
};
RxInfo(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
: mMessage(static_cast<RxMessage &>(aMessage))
, mMessageInfo(aMessageInfo)
, mFrameCounter(0)
, mKeySequence(0)
, mNeighbor(nullptr)
, mClass(kUnknown)
{
}
bool IsNeighborStateValid(void) const { return (mNeighbor != nullptr) && mNeighbor->IsStateValid(); }
RxMessage &mMessage; // The MLE message.
const Ip6::MessageInfo &mMessageInfo; // The `MessageInfo` associated with the message.
uint32_t mFrameCounter; // The frame counter from aux security header.
uint32_t mKeySequence; // The key sequence from aux security header.
Neighbor *mNeighbor; // Neighbor from which message was received (can be `nullptr`).
Class mClass; // The message class (authoritative, peer, or unknown).
};
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
struct DelayedResponseMetadata
{
Error AppendTo(Message &aMessage) const { return aMessage.Append(*this); }
void ReadFrom(const Message &aMessage);
void RemoveFrom(Message &aMessage) const;
Ip6::Address mDestination; // IPv6 address of the message destination.
TimeMilli mSendTime; // Time when the message shall be sent.
};
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OT_TOOL_PACKED_BEGIN
class SecurityHeader
{
public:
void InitSecurityControl(void) { mSecurityControl = kKeyIdMode2Mic32; }
bool IsSecurityControlValid(void) const { return (mSecurityControl == kKeyIdMode2Mic32); }
uint32_t GetFrameCounter(void) const { return Encoding::LittleEndian::HostSwap32(mFrameCounter); }
void SetFrameCounter(uint32_t aCounter) { mFrameCounter = Encoding::LittleEndian::HostSwap32(aCounter); }
uint32_t GetKeyId(void) const { return Encoding::BigEndian::HostSwap32(mKeySource); }
void SetKeyId(uint32_t aKeySequence)
{
mKeySource = Encoding::BigEndian::HostSwap32(aKeySequence);
mKeyIndex = (aKeySequence & 0x7f) + 1;
}
private:
static constexpr uint8_t kKeyIdMode2Mic32 =
static_cast<uint8_t>(Mac::Frame::kKeyIdMode2) | static_cast<uint8_t>(Mac::Frame::kSecurityEncMic32);
uint8_t mSecurityControl;
uint32_t mFrameCounter;
uint32_t mKeySource;
uint8_t mKeyIndex;
} OT_TOOL_PACKED_END;
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class ParentCandidate : public Parent
{
public:
void Init(Instance &aInstance) { Parent::Init(aInstance); }
void Clear(void);
void CopyTo(Parent &aParent) const;
RxChallenge mRxChallenge;
int8_t mPriority;
uint8_t mLinkQuality3;
uint8_t mLinkQuality2;
uint8_t mLinkQuality1;
uint16_t mSedBufferSize;
uint8_t mSedDatagramCount;
uint8_t mLinkMargin;
LeaderData mLeaderData;
bool mIsSingleton;
};
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
class ServiceAloc : public Ip6::Netif::UnicastAddress
{
public:
static constexpr uint16_t kNotInUse = Mac::kShortAddrInvalid;
ServiceAloc(void);
bool IsInUse(void) const { return GetAloc16() != kNotInUse; }
void MarkAsNotInUse(void) { SetAloc16(kNotInUse); }
uint16_t GetAloc16(void) const { return GetAddress().GetIid().GetLocator(); }
void SetAloc16(uint16_t aAloc16) { GetAddress().GetIid().SetLocator(aAloc16); }
void ApplyMeshLocalPrefix(const Ip6::NetworkPrefix &aPrefix) { GetAddress().SetPrefix(aPrefix); }
};
#endif
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
void HandleParentSearchTimer(void) { mParentSearch.HandleTimer(); }
class ParentSearch : public InstanceLocator
{
public:
explicit ParentSearch(Instance &aInstance)
: InstanceLocator(aInstance)
, mIsInBackoff(false)
, mBackoffWasCanceled(false)
, mRecentlyDetached(false)
, mBackoffCancelTime(0)
, mTimer(aInstance)
{
}
void StartTimer(void);
void UpdateState(void);
void SetRecentlyDetached(void) { mRecentlyDetached = true; }
void HandleTimer(void);
private:
// All timer intervals are converted to milliseconds.
static constexpr uint32_t kCheckInterval = (OPENTHREAD_CONFIG_PARENT_SEARCH_CHECK_INTERVAL * 1000u);
static constexpr uint32_t kBackoffInterval = (OPENTHREAD_CONFIG_PARENT_SEARCH_BACKOFF_INTERVAL * 1000u);
static constexpr uint32_t kJitterInterval = (15 * 1000u);
static constexpr int8_t kRssThreshold = OPENTHREAD_CONFIG_PARENT_SEARCH_RSS_THRESHOLD;
using SearchTimer = TimerMilliIn<Mle, &Mle::HandleParentSearchTimer>;
bool mIsInBackoff : 1;
bool mBackoffWasCanceled : 1;
bool mRecentlyDetached : 1;
TimeMilli mBackoffCancelTime;
SearchTimer mTimer;
};
#endif // OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
//------------------------------------------------------------------------------------------------------------------
// Methods
static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
static void HandleDetachGracefullyTimer(Timer &aTimer);
Error Start(StartMode aMode);
void Stop(StopMode aMode);
TxMessage *NewMleMessage(Command aCommand);
void SetRole(DeviceRole aRole);
void Attach(AttachMode aMode);
void SetAttachState(AttachState aState);
void InitNeighbor(Neighbor &aNeighbor, const RxInfo &aRxInfo);
void ClearParentCandidate(void) { mParentCandidate.Clear(); }
Error CheckReachability(uint16_t aMeshDest, const Ip6::Header &aIp6Header);
uint16_t GetNextHop(uint16_t aDestination) const;
Error SendDataRequest(const Ip6::Address &aDestination);
void HandleNotifierEvents(Events aEvents);
void SendDelayedResponse(TxMessage &aMessage, const DelayedResponseMetadata &aMetadata);
void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void ReestablishLinkWithNeighbor(Neighbor &aNeighbor);
void HandleDetachGracefullyTimer(void);
bool IsDetachingGracefully(void) { return mDetachGracefullyTimer.IsRunning(); }
Error SendChildUpdateRequest(ChildUpdateRequestMode aMode);
Error SendDataRequestAfterDelay(const Ip6::Address &aDestination, uint16_t aDelay);
Error SendChildUpdateRequest(void);
Error SendChildUpdateResponse(const TlvList &aTlvList, const RxChallenge &aChallenge);
void SetRloc16(uint16_t aRloc16);
void SetStateDetached(void);
void SetStateChild(uint16_t aRloc16);
void SetLeaderData(uint32_t aPartitionId, uint8_t aWeighting, uint8_t aLeaderRouterId);
void InformPreviousChannel(void);
bool IsAnnounceAttach(void) const { return mAlternatePanId != Mac::kPanIdBroadcast; }
void ScheduleMessageTransmissionTimer(void);
void HandleAttachTimer(void);
void HandleDelayedResponseTimer(void);
void HandleMessageTransmissionTimer(void);
void ProcessKeySequence(RxInfo &aRxInfo);
void HandleAdvertisement(RxInfo &aRxInfo);
void HandleChildIdResponse(RxInfo &aRxInfo);
void HandleChildUpdateRequest(RxInfo &aRxInfo);
void HandleChildUpdateResponse(RxInfo &aRxInfo);
void HandleDataResponse(RxInfo &aRxInfo);
void HandleParentResponse(RxInfo &aRxInfo);
void HandleAnnounce(RxInfo &aRxInfo);
Error HandleLeaderData(RxInfo &aRxInfo);
void ProcessAnnounce(void);
bool HasUnregisteredAddress(void);
uint32_t GetAttachStartDelay(void) const;
void SendParentRequest(ParentRequestType aType);
Error SendChildIdRequest(void);
Error GetNextAnnounceChannel(uint8_t &aChannel) const;
bool HasMoreChannelsToAnnounce(void) const;
bool PrepareAnnounceState(void);
void SendAnnounce(uint8_t aChannel, AnnounceMode aMode);
void SendAnnounce(uint8_t aChannel, const Ip6::Address &aDestination, AnnounceMode aMode = kNormalAnnounce);
uint32_t Reattach(void);
bool HasAcceptableParentCandidate(void) const;
Error DetermineParentRequestType(ParentRequestType &aType) const;
bool IsBetterParent(uint16_t aRloc16,
LinkQuality aLinkQuality,
uint8_t aLinkMargin,
const ConnectivityTlv &aConnectivityTlv,
uint16_t aVersion,
const Mac::CslAccuracy &aCslAccuracy);
bool IsNetworkDataNewer(const LeaderData &aLeaderData);
Error ProcessMessageSecurity(Crypto::AesCcm::Mode aMode,
Message &aMessage,
const Ip6::MessageInfo &aMessageInfo,
uint16_t aCmdOffset,
const SecurityHeader &aHeader);
void RemoveDelayedMessage(Message::SubType aSubType, MessageType aMessageType, const Ip6::Address *aDestination);
void RemoveDelayedDataRequestMessage(const Ip6::Address &aDestination);
#if OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH
void InformPreviousParent(void);
#endif
#if OPENTHREAD_CONFIG_UPTIME_ENABLE
void UpdateRoleTimeCounters(DeviceRole aRole);
#endif
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
ServiceAloc *FindInServiceAlocs(uint16_t aAloc16);
void UpdateServiceAlocs(void);
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
void HandleLinkMetricsManagementRequest(RxInfo &aRxInfo);
void HandleLinkProbe(RxInfo &aRxInfo);
Error SendLinkMetricsManagementResponse(const Ip6::Address &aDestination, LinkMetrics::Status aStatus);
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
void HandleLinkMetricsManagementResponse(RxInfo &aRxInfo);
Error SendDataRequestForLinkMetricsReport(const Ip6::Address &aDestination,
const LinkMetrics::Initiator::QueryInfo &aQueryInfo);
Error SendLinkMetricsManagementRequest(const Ip6::Address &aDestination, const ot::Tlv &aSubTlv);
Error SendLinkProbe(const Ip6::Address &aDestination, uint8_t aSeriesId, uint8_t *aBuf, uint8_t aLength);
Error SendDataRequest(const Ip6::Address &aDestination,
const uint8_t *aTlvs,
uint8_t aTlvsLength,
uint16_t aDelay,
const LinkMetrics::Initiator::QueryInfo *aQueryInfo = nullptr);
#else
Error SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength, uint16_t aDelay);
#endif
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
static void Log(MessageAction aAction, MessageType aType, const Ip6::Address &aAddress);
static void Log(MessageAction aAction, MessageType aType, const Ip6::Address &aAddress, uint16_t aRloc);
#else
static void Log(MessageAction, MessageType, const Ip6::Address &) {}
static void Log(MessageAction, MessageType, const Ip6::Address &, uint16_t) {}
#endif
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE)
static const char *AttachModeToString(AttachMode aMode);
static const char *AttachStateToString(AttachState aState);
static const char *ReattachStateToString(ReattachState aState);
#endif
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
static void LogError(MessageAction aAction, MessageType aType, Error aError);
static const char *MessageActionToString(MessageAction aAction);
static const char *MessageTypeToString(MessageType aType);
static const char *MessageTypeActionToSuffixString(MessageType aType, MessageAction aAction);
static void LogProcessError(MessageType aType, Error aError);
static void LogSendError(MessageType aType, Error aError);
#else
static void LogProcessError(MessageType, Error) {}
static void LogSendError(MessageType, Error) {}
#endif
//------------------------------------------------------------------------------------------------------------------
// Variables
using DetachGracefullyTimer = TimerMilliIn<Mle, &Mle::HandleDetachGracefullyTimer>;
using AttachTimer = TimerMilliIn<Mle, &Mle::HandleAttachTimer>;
using DelayTimer = TimerMilliIn<Mle, &Mle::HandleDelayedResponseTimer>;
using MsgTxTimer = TimerMilliIn<Mle, &Mle::HandleMessageTransmissionTimer>;
static const otMeshLocalPrefix kMeshLocalPrefixInit;
bool mRetrieveNewNetworkData : 1;
bool mRequestRouteTlv : 1;
bool mHasRestored : 1;
bool mReceivedResponseFromParent : 1;
bool mInitiallyAttachedAsSleepy : 1;
#if OPENTHREAD_FTD
bool mWasLeader : 1;
#endif
DeviceRole mRole;
DeviceMode mDeviceMode;
AttachState mAttachState;
ReattachState mReattachState;
AttachMode mAttachMode;
DataRequestState mDataRequestState;
AddressRegistrationMode mAddressRegistrationMode;
ChildUpdateRequestState mChildUpdateRequestState;
uint8_t mParentRequestCounter;
uint8_t mChildUpdateAttempts;
uint8_t mDataRequestAttempts;
uint8_t mAnnounceChannel;
uint8_t mAlternateChannel;
#if OPENTHREAD_FTD
uint8_t mLinkRequestAttempts;
#endif
uint16_t mRloc16;
uint16_t mPreviousParentRloc;
uint16_t mAttachCounter;
uint16_t mAnnounceDelay;
uint16_t mAlternatePanId;
uint32_t mTimeout;
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
uint32_t mCslTimeout;
#endif
uint64_t mAlternateTimestamp;
#if OPENTHREAD_CONFIG_UPTIME_ENABLE
uint64_t mLastUpdatedTimestamp;
#endif
LeaderData mLeaderData;
Parent mParent;
NeighborTable mNeighborTable;
MessageQueue mDelayedResponses;
TxChallenge mParentRequestChallenge;
ParentCandidate mParentCandidate;
Ip6::Udp::Socket mSocket;
Counters mCounters;
#if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
ParentSearch mParentSearch;
#endif
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
ServiceAloc mServiceAlocs[kMaxServiceAlocs];
#endif
Callback<otDetachGracefullyCallback> mDetachGracefullyCallback;
#if OPENTHREAD_CONFIG_MLE_PARENT_RESPONSE_CALLBACK_API_ENABLE
Callback<otThreadParentResponseCallback> mParentResponseCallback;
#endif
AttachTimer mAttachTimer;
DelayTimer mDelayedResponseTimer;
MsgTxTimer mMessageTransmissionTimer;
DetachGracefullyTimer mDetachGracefullyTimer;
Ip6::Netif::UnicastAddress mLinkLocal64;
Ip6::Netif::UnicastAddress mMeshLocal64;
Ip6::Netif::UnicastAddress mMeshLocal16;
Ip6::Netif::MulticastAddress mLinkLocalAllThreadNodes;
Ip6::Netif::MulticastAddress mRealmLocalAllThreadNodes;
Ip6::Netif::UnicastAddress mLeaderAloc;
};
} // namespace Mle
/**
* @}
*
*/
} // namespace ot
#endif // MLE_HPP_