diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 15c0a64f7..b60d8900c 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (365) +#define OPENTHREAD_API_VERSION (366) /** * @addtogroup api-instance diff --git a/include/openthread/ip6.h b/include/openthread/ip6.h index 057373310..850c64c6b 100644 --- a/include/openthread/ip6.h +++ b/include/openthread/ip6.h @@ -188,6 +188,7 @@ typedef struct otNetifAddress bool mScopeOverrideValid : 1; ///< TRUE if the mScopeOverride value is valid, FALSE otherwise. unsigned int mScopeOverride : 4; ///< The IPv6 scope of this address. bool mRloc : 1; ///< TRUE if the address is an RLOC, FALSE otherwise. + bool mMeshLocal : 1; ///< TRUE if the address is mesh-local, FALSE otherwise. const struct otNetifAddress *mNext; ///< A pointer to the next network interface address. } otNetifAddress; diff --git a/src/core/backbone_router/bbr_local.cpp b/src/core/backbone_router/bbr_local.cpp index 7c1289b06..595355b8b 100644 --- a/src/core/backbone_router/bbr_local.cpp +++ b/src/core/backbone_router/bbr_local.cpp @@ -62,7 +62,7 @@ Local::Local(Instance &aInstance) mDomainPrefixConfig.GetPrefix().SetLength(0); // Primary Backbone Router Aloc - mBackboneRouterPrimaryAloc.InitAsThreadOriginRealmLocalScope(); + mBackboneRouterPrimaryAloc.InitAsThreadOriginMeshLocal(); mBackboneRouterPrimaryAloc.GetAddress().GetIid().SetToLocator(Mle::kAloc16BackboneRouterPrimary); // All Network Backbone Routers Multicast Address. @@ -364,7 +364,7 @@ exit: return error; } -void Local::ApplyMeshLocalPrefix(void) +void Local::ApplyNewMeshLocalPrefix(void) { VerifyOrExit(IsEnabled()); @@ -372,13 +372,6 @@ void Local::ApplyMeshLocalPrefix(void) mAllNetworkBackboneRouters.SetMulticastNetworkPrefix(Get().GetMeshLocalPrefix()); Get().SubscribeMulticast(mAllNetworkBackboneRouters); - if (IsPrimary()) - { - Get().RemoveUnicastAddress(mBackboneRouterPrimaryAloc); - mBackboneRouterPrimaryAloc.GetAddress().SetPrefix(Get().GetMeshLocalPrefix()); - Get().AddUnicastAddress(mBackboneRouterPrimaryAloc); - } - exit: return; } diff --git a/src/core/backbone_router/bbr_local.hpp b/src/core/backbone_router/bbr_local.hpp index 5578dc208..90b2d894d 100644 --- a/src/core/backbone_router/bbr_local.hpp +++ b/src/core/backbone_router/bbr_local.hpp @@ -256,7 +256,7 @@ public: * Applies the Mesh Local Prefix. * */ - void ApplyMeshLocalPrefix(void); + void ApplyNewMeshLocalPrefix(void); /** * Updates the subscription of All Domain Backbone Routers Multicast Address. diff --git a/src/core/meshcop/border_agent.cpp b/src/core/meshcop/border_agent.cpp index d38d78d8a..f73863c1d 100644 --- a/src/core/meshcop/border_agent.cpp +++ b/src/core/meshcop/border_agent.cpp @@ -240,7 +240,7 @@ BorderAgent::BorderAgent(Instance &aInstance) , mIdInitialized(false) #endif { - mCommissionerAloc.InitAsThreadOriginRealmLocalScope(); + mCommissionerAloc.InitAsThreadOriginMeshLocal(); } #if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE @@ -654,21 +654,6 @@ exit: return; } -void BorderAgent::ApplyMeshLocalPrefix(void) -{ - VerifyOrExit(mState == kStateActive); - - if (Get().HasUnicastAddress(mCommissionerAloc)) - { - Get().RemoveUnicastAddress(mCommissionerAloc); - mCommissionerAloc.GetAddress().SetPrefix(Get().GetMeshLocalPrefix()); - Get().AddUnicastAddress(mCommissionerAloc); - } - -exit: - return; -} - #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN) void BorderAgent::LogError(const char *aActionText, Error aError) { diff --git a/src/core/meshcop/border_agent.hpp b/src/core/meshcop/border_agent.hpp index dd96b450a..9f721d662 100644 --- a/src/core/meshcop/border_agent.hpp +++ b/src/core/meshcop/border_agent.hpp @@ -141,12 +141,6 @@ public: */ State GetState(void) const { return mState; } - /** - * Applies the Mesh Local Prefix. - * - */ - void ApplyMeshLocalPrefix(void); - /** * Returns the UDP Proxy port to which the commissioner is currently * bound. diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp index 1bc30b042..8b3aea95c 100644 --- a/src/core/meshcop/commissioner.cpp +++ b/src/core/meshcop/commissioner.cpp @@ -74,12 +74,8 @@ Commissioner::Commissioner(Instance &aInstance) { memset(reinterpret_cast(mJoiners), 0, sizeof(mJoiners)); - mCommissionerAloc.Clear(); - mCommissionerAloc.mPrefixLength = 64; - mCommissionerAloc.mPreferred = true; - mCommissionerAloc.mValid = true; - mCommissionerAloc.mScopeOverride = Ip6::Address::kRealmLocalScope; - mCommissionerAloc.mScopeOverrideValid = true; + mCommissionerAloc.InitAsThreadOriginMeshLocal(); + mCommissionerAloc.mPreferred = true; IgnoreError(SetId("OpenThread Commissioner")); @@ -1155,18 +1151,6 @@ exit: return error; } -void Commissioner::ApplyMeshLocalPrefix(void) -{ - VerifyOrExit(mState == kStateActive); - - Get().RemoveUnicastAddress(mCommissionerAloc); - mCommissionerAloc.GetAddress().SetPrefix(Get().GetMeshLocalPrefix()); - Get().AddUnicastAddress(mCommissionerAloc); - -exit: - return; -} - // LCOV_EXCL_START #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) diff --git a/src/core/meshcop/commissioner.hpp b/src/core/meshcop/commissioner.hpp index 74c910c9d..ee436c533 100644 --- a/src/core/meshcop/commissioner.hpp +++ b/src/core/meshcop/commissioner.hpp @@ -486,12 +486,6 @@ public: */ PanIdQueryClient &GetPanIdQueryClient(void) { return mPanIdQuery; } - /** - * Applies the Mesh Local Prefix. - * - */ - void ApplyMeshLocalPrefix(void); - private: static constexpr uint32_t kPetitionAttemptDelay = 5; // COMM_PET_ATTEMPT_DELAY (seconds) static constexpr uint8_t kPetitionRetryCount = 2; // COMM_PET_RETRY_COUNT diff --git a/src/core/net/dhcp6_server.cpp b/src/core/net/dhcp6_server.cpp index 826d5fefc..a8a8a595b 100644 --- a/src/core/net/dhcp6_server.cpp +++ b/src/core/net/dhcp6_server.cpp @@ -485,21 +485,6 @@ Error Server::AppendRapidCommit(Message &aMessage) return aMessage.Append(option); } -void Server::ApplyMeshLocalPrefix(void) -{ - for (PrefixAgent &prefixAgent : mPrefixAgents) - { - if (prefixAgent.IsValid()) - { - PrefixAgent *entry = &prefixAgent; - - Get().RemoveUnicastAddress(entry->GetAloc()); - entry->GetAloc().GetAddress().SetPrefix(Get().GetMeshLocalPrefix()); - Get().AddUnicastAddress(entry->GetAloc()); - } - } -} - } // namespace Dhcp6 } // namespace ot diff --git a/src/core/net/dhcp6_server.hpp b/src/core/net/dhcp6_server.hpp index d38c40edc..eba2d6c96 100644 --- a/src/core/net/dhcp6_server.hpp +++ b/src/core/net/dhcp6_server.hpp @@ -80,12 +80,6 @@ public: */ Error UpdateService(void); - /** - * Applies the Mesh Local Prefix. - * - */ - void ApplyMeshLocalPrefix(void); - private: class PrefixAgent { @@ -173,6 +167,7 @@ private: mAloc.InitAsThreadOrigin(); mAloc.GetAddress().SetToAnycastLocator(aMeshLocalPrefix, (Ip6::Address::kAloc16Mask << 8) + aContextId); + mAloc.mMeshLocal = true; } private: diff --git a/src/core/net/nd_agent.cpp b/src/core/net/nd_agent.cpp index 6f1760ab3..e05dd283f 100644 --- a/src/core/net/nd_agent.cpp +++ b/src/core/net/nd_agent.cpp @@ -105,6 +105,7 @@ void Agent::UpdateService(void) mAloc.InitAsThreadOrigin(); mAloc.GetAddress().SetToAnycastLocator(Get().GetMeshLocalPrefix(), rloc); + mAloc.mMeshLocal = true; Get().AddUnicastAddress(mAloc); ExitNow(); } @@ -114,18 +115,6 @@ exit: return; } -void Agent::ApplyMeshLocalPrefix(void) -{ - VerifyOrExit(IsAlocInUse()); - - Get().RemoveUnicastAddress(mAloc); - mAloc.GetAddress().SetPrefix(Get().GetMeshLocalPrefix()); - Get().AddUnicastAddress(mAloc); - -exit: - return; -} - } // namespace NeighborDiscovery } // namespace ot diff --git a/src/core/net/nd_agent.hpp b/src/core/net/nd_agent.hpp index 62125b678..01303a320 100644 --- a/src/core/net/nd_agent.hpp +++ b/src/core/net/nd_agent.hpp @@ -66,12 +66,6 @@ public: */ void UpdateService(void); - /** - * Updates the prefix of the Neighbor Discovery Agent Anycast Locator. - * - */ - void ApplyMeshLocalPrefix(void); - private: void FreeAloc(void) { mAloc.mNext = &mAloc; } bool IsAlocInUse(void) const { return mAloc.mNext != &mAloc; } diff --git a/src/core/net/netif.cpp b/src/core/net/netif.cpp index effc36ed5..e6c3c2e3c 100644 --- a/src/core/net/netif.cpp +++ b/src/core/net/netif.cpp @@ -365,6 +365,11 @@ void Netif::UnsubscribeAllExternalMulticastAddresses(void) void Netif::AddUnicastAddress(UnicastAddress &aAddress) { + if (aAddress.mMeshLocal) + { + aAddress.GetAddress().SetPrefix(Get().GetMeshLocalPrefix()); + } + SuccessOrExit(mUnicastAddresses.Add(aAddress)); SignalUnicastAddressChange(kAddressAdded, aAddress); @@ -438,8 +443,10 @@ Error Netif::AddExternalUnicastAddress(const UnicastAddress &aAddress) entry = mExtUnicastAddressPool.Allocate(); VerifyOrExit(entry != nullptr, error = kErrorNoBufs); - *entry = aAddress; - entry->mRloc = false; + *entry = aAddress; + entry->mRloc = false; + entry->mMeshLocal = false; + mUnicastAddresses.Push(*entry); SignalUnicastAddressChange(kAddressAdded, *entry); @@ -490,6 +497,29 @@ bool Netif::IsUnicastAddressExternal(const UnicastAddress &aAddress) const return mExtUnicastAddressPool.IsPoolEntry(aAddress); } +void Netif::ApplyNewMeshLocalPrefix(void) +{ + for (UnicastAddress &address : mUnicastAddresses) + { + if (address.mMeshLocal) + { + SignalUnicastAddressChange(kAddressRemoved, address); + address.GetAddress().SetPrefix(Get().GetMeshLocalPrefix()); + SignalUnicastAddressChange(kAddressAdded, address); + } + } + + for (MulticastAddress &address : mMulticastAddresses) + { + if (Get().IsMulticastAddressMeshLocalPrefixBased(address)) + { + SignalMulticastAddressChange(kAddressRemoved, address, kOriginThread); + address.GetAddress().SetMulticastNetworkPrefix(Get().GetMeshLocalPrefix()); + SignalMulticastAddressChange(kAddressAdded, address, kOriginThread); + } + } +} + //--------------------------------------------------------------------------------------------------------------------- // Netif::UnicastAddress @@ -502,10 +532,11 @@ void Netif::UnicastAddress::InitAsThreadOrigin(bool aPreferred) mValid = true; } -void Netif::UnicastAddress::InitAsThreadOriginRealmLocalScope(void) +void Netif::UnicastAddress::InitAsThreadOriginMeshLocal(void) { InitAsThreadOrigin(); SetScopeOverride(Address::kRealmLocalScope); + mMeshLocal = true; } void Netif::UnicastAddress::InitAsThreadOriginGlobalScope(void) diff --git a/src/core/net/netif.hpp b/src/core/net/netif.hpp index e2b777c09..0e5057134 100644 --- a/src/core/net/netif.hpp +++ b/src/core/net/netif.hpp @@ -123,10 +123,10 @@ public: /** * Clears and initializes the unicast address as a valid (but not preferred), thread-origin, - * realm-local scope (overridden) address with 64-bit prefix length. + * mesh-local address using the realm-local scope (overridden) address with 64-bit prefix length. * */ - void InitAsThreadOriginRealmLocalScope(void); + void InitAsThreadOriginMeshLocal(void); /** * Clears and initializes the unicast address as a valid (but not preferred), thread-origin, global @@ -646,6 +646,14 @@ public: */ bool HasAnyExternalMulticastAddress(void) const { return !ExternalMulticastAddress::Iterator(*this).IsDone(); } + /** + * Applies the new mesh local prefix. + * + * Updates all mesh-local unicast addresses and prefix-based multicast addresses of the network interface. + * + */ + void ApplyNewMeshLocalPrefix(void); + protected: /** * Subscribes the network interface to the realm-local all MPL forwarders, link-local, and realm-local diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index fa67446df..9591e4593 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -124,12 +124,10 @@ Mle::Mle(Instance &aInstance) mLinkLocal64.InitAsThreadOrigin(/* aPreferred */ true); mLinkLocal64.GetAddress().SetToLinkLocalAddress(Get().GetExtAddress()); - mLeaderAloc.InitAsThreadOriginRealmLocalScope(); - - mMeshLocal64.InitAsThreadOriginRealmLocalScope(); + mMeshLocal64.InitAsThreadOriginMeshLocal(); mMeshLocal64.GetAddress().GetIid().GenerateRandom(); - mMeshLocal16.InitAsThreadOriginRealmLocalScope(); + mMeshLocal16.InitAsThreadOriginMeshLocal(); mMeshLocal16.GetAddress().GetIid().SetToLocator(0); mMeshLocal16.mRloc = true; @@ -141,10 +139,8 @@ Mle::Mle(Instance &aInstance) mRealmLocalAllThreadNodes.GetAddress().mFields.m16[0] = HostSwap16(0xff33); mRealmLocalAllThreadNodes.GetAddress().mFields.m16[7] = HostSwap16(0x0001); + mMeshLocalPrefix.Clear(); SetMeshLocalPrefix(AsCoreType(&kMeshLocalPrefixInit)); - - // `SetMeshLocalPrefix()` also adds the Mesh-Local EID and subscribes - // to the Link- and Realm-Local All Thread Nodes multicast addresses. } Error Mle::Enable(void) @@ -195,7 +191,11 @@ Error Mle::Start(StartMode aMode) SetStateDetached(); - ApplyMeshLocalPrefix(); + Get().AddUnicastAddress(mMeshLocal64); + + Get().SubscribeMulticast(mLinkLocalAllThreadNodes); + Get().SubscribeMulticast(mRealmLocalAllThreadNodes); + SetRloc16(GetRloc16()); mAttachCounter = 0; @@ -693,10 +693,12 @@ void Mle::SetStateDetached(void) Get().Reset(); #endif +#if OPENTHREAD_FTD if (IsLeader()) { - Get().RemoveUnicastAddress(mLeaderAloc); + Get().RemoveUnicastAddress(Get().mLeaderAloc); } +#endif SetRole(kRoleDetached); SetAttachState(kAttachStateIdle); @@ -719,10 +721,12 @@ void Mle::SetStateDetached(void) void Mle::SetStateChild(uint16_t aRloc16) { +#if OPENTHREAD_FTD if (IsLeader()) { - Get().RemoveUnicastAddress(mLeaderAloc); + Get().RemoveUnicastAddress(Get().mLeaderAloc); } +#endif SetRloc16(aRloc16); SetRole(kRoleChild); @@ -888,28 +892,40 @@ void Mle::UpdateLinkLocalAddress(void) void Mle::SetMeshLocalPrefix(const Ip6::NetworkPrefix &aMeshLocalPrefix) { - VerifyOrExit(GetMeshLocalPrefix() != aMeshLocalPrefix, - Get().SignalIfFirst(kEventThreadMeshLocalAddrChanged)); + VerifyOrExit(mMeshLocalPrefix != aMeshLocalPrefix); - if (Get().IsUp()) - { - Get().RemoveUnicastAddress(mLeaderAloc); + mMeshLocalPrefix = aMeshLocalPrefix; - // We must remove the old addresses before adding the new ones. - Get().RemoveUnicastAddress(mMeshLocal64); - Get().RemoveUnicastAddress(mMeshLocal16); - Get().UnsubscribeMulticast(mLinkLocalAllThreadNodes); - Get().UnsubscribeMulticast(mRealmLocalAllThreadNodes); - } + // We ask `ThreadNetif` to apply the new mesh-local prefix which + // will then update all of its assigned unicast addresses that are + // marked as mesh-local, as well as all of the subscribed mesh-local + // prefix-based multicast addresses (such as link-local or + // realm-local All Thread Nodes addresses). It is important to call + // `ApplyNewMeshLocalPrefix()` first so that `ThreadNetif` can + // correctly signal the updates. It will first signal the removal + // of the previous address based on the old prefix, and then the + // addition of the new address with the new mesh-local prefix. - mMeshLocal64.GetAddress().SetPrefix(aMeshLocalPrefix); - mMeshLocal16.GetAddress().SetPrefix(aMeshLocalPrefix); - mLeaderAloc.GetAddress().SetPrefix(aMeshLocalPrefix); + Get().ApplyNewMeshLocalPrefix(); - // Just keep mesh local prefix if network interface is down - VerifyOrExit(Get().IsUp()); + // Some of the addresses may already be updated from the + // `ApplyNewMeshLocalPrefix()` call, but we apply the new prefix to + // them in case they are not yet added to the `Netif`. This ensures + // that addresses are always updated and other modules can retrieve + // them using methods such as `GetMeshLocal16()`, `GetMeshLocal64()` + // or `GetLinkLocalAllThreadNodesAddress()`, even if they have not + // yet been added to the `Netif`. - ApplyMeshLocalPrefix(); + mMeshLocal64.GetAddress().SetPrefix(mMeshLocalPrefix); + mMeshLocal16.GetAddress().SetPrefix(mMeshLocalPrefix); + mLinkLocalAllThreadNodes.GetAddress().SetMulticastNetworkPrefix(mMeshLocalPrefix); + mRealmLocalAllThreadNodes.GetAddress().SetMulticastNetworkPrefix(mMeshLocalPrefix); + +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + Get().ApplyNewMeshLocalPrefix(); +#endif + + Get().Signal(kEventThreadMeshLocalAddrChanged); exit: return; @@ -928,71 +944,6 @@ exit: } #endif -void Mle::ApplyMeshLocalPrefix(void) -{ - mLinkLocalAllThreadNodes.GetAddress().SetMulticastNetworkPrefix(GetMeshLocalPrefix()); - mRealmLocalAllThreadNodes.GetAddress().SetMulticastNetworkPrefix(GetMeshLocalPrefix()); - - VerifyOrExit(!IsDisabled()); - - // Add the addresses back into the table. - Get().AddUnicastAddress(mMeshLocal64); - Get().SubscribeMulticast(mLinkLocalAllThreadNodes); - Get().SubscribeMulticast(mRealmLocalAllThreadNodes); - - if (IsAttached()) - { - Get().AddUnicastAddress(mMeshLocal16); - } - - // update Leader ALOC - if (IsLeader()) - { - Get().AddUnicastAddress(mLeaderAloc); - } - -#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE - Get().ApplyMeshLocalPrefix(); -#endif - -#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE - Get().ApplyMeshLocalPrefix(); -#endif - -#if OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE - Get().ApplyMeshLocalPrefix(); -#endif - -#if OPENTHREAD_CONFIG_NEIGHBOR_DISCOVERY_AGENT_ENABLE - Get().ApplyMeshLocalPrefix(); -#endif - -#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE - for (ServiceAloc &serviceAloc : mServiceAlocs) - { - if (serviceAloc.IsInUse()) - { - Get().RemoveUnicastAddress(serviceAloc); - } - - serviceAloc.ApplyMeshLocalPrefix(GetMeshLocalPrefix()); - - if (serviceAloc.IsInUse()) - { - Get().AddUnicastAddress(serviceAloc); - } - } -#endif - -#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE - Get().ApplyMeshLocalPrefix(); -#endif - -exit: - // Changing the prefix also causes the mesh local address to be different. - Get().Signal(kEventThreadMeshLocalAddrChanged); -} - void Mle::SetRloc16(uint16_t aRloc16) { uint16_t oldRloc16 = GetRloc16(); @@ -1051,7 +1002,7 @@ Error Mle::GetLeaderAddress(Ip6::Address &aAddress) const VerifyOrExit(GetRloc16() != Mac::kShortAddrInvalid, error = kErrorDetached); - aAddress.SetToRoutingLocator(GetMeshLocalPrefix(), Rloc16FromRouterId(mLeaderData.GetLeaderRouterId())); + aAddress.SetToRoutingLocator(mMeshLocalPrefix, Rloc16FromRouterId(mLeaderData.GetLeaderRouterId())); exit: return error; @@ -1075,7 +1026,7 @@ Error Mle::GetServiceAloc(uint8_t aServiceId, Ip6::Address &aAddress) const Error error = kErrorNone; VerifyOrExit(GetRloc16() != Mac::kShortAddrInvalid, error = kErrorDetached); - aAddress.SetToAnycastLocator(GetMeshLocalPrefix(), ServiceAlocFromId(aServiceId)); + aAddress.SetToAnycastLocator(mMeshLocalPrefix, ServiceAlocFromId(aServiceId)); exit: return error; @@ -1259,7 +1210,7 @@ exit: Mle::ServiceAloc::ServiceAloc(void) { - InitAsThreadOriginRealmLocalScope(); + InitAsThreadOriginMeshLocal(); GetAddress().GetIid().SetToLocator(kNotInUse); } @@ -3954,10 +3905,7 @@ bool Mle::IsAnycastLocator(const Ip6::Address &aAddress) const return IsMeshLocalAddress(aAddress) && aAddress.GetIid().IsAnycastLocator(); } -bool Mle::IsMeshLocalAddress(const Ip6::Address &aAddress) const -{ - return (aAddress.GetPrefix() == GetMeshLocalPrefix()); -} +bool Mle::IsMeshLocalAddress(const Ip6::Address &aAddress) const { return (aAddress.GetPrefix() == mMeshLocalPrefix); } Error Mle::CheckReachability(uint16_t aMeshDest, const Ip6::Header &aIp6Header) { diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 1ca1645ec..6b2b6338d 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -352,7 +352,7 @@ public: * @returns A reference to the Mesh Local Prefix. * */ - const Ip6::NetworkPrefix &GetMeshLocalPrefix(void) const { return mMeshLocal16.GetAddress().GetPrefix(); } + const Ip6::NetworkPrefix &GetMeshLocalPrefix(void) const { return mMeshLocalPrefix; } /** * Sets the Mesh Local Prefix. @@ -377,12 +377,6 @@ public: Error SetMeshLocalIid(const Ip6::InterfaceIdentifier &aMlIid); #endif - /** - * Applies the Mesh Local Prefix. - * - */ - void ApplyMeshLocalPrefix(void); - /** * Returns a reference to the Thread link-local address. * @@ -690,6 +684,21 @@ public: */ bool HasRestored(void) const { return mHasRestored; } + /** + * Indicates whether or not a given netif multicast address instance is a prefix-based address added by MLE and + * uses the mesh local prefix. + * + * @param[in] aAddress A `Netif::MulticastAddress` address instance. + * + * @retval TRUE If @p aAddress is a prefix-based address which uses the mesh local prefix. + * @retval FALSE If @p aAddress is not a prefix-based address which uses the mesh local prefix. + * + */ + bool IsMulticastAddressMeshLocalPrefixBased(const Ip6::Netif::MulticastAddress &aAddress) const + { + return (&aAddress == &mLinkLocalAllThreadNodes) || (&aAddress == &mRealmLocalAllThreadNodes); + } + #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE /** * Gets the CSL timeout. @@ -1151,7 +1160,6 @@ private: 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 @@ -1401,12 +1409,12 @@ private: DelayTimer mDelayedResponseTimer; MsgTxTimer mMessageTransmissionTimer; DetachGracefullyTimer mDetachGracefullyTimer; + Ip6::NetworkPrefix mMeshLocalPrefix; 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 diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 414bb7556..97d05581b 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -96,6 +96,8 @@ MleRouter::MleRouter(Instance &aInstance) mLeaderWeight = kDefaultLeaderWeight; #endif + mLeaderAloc.InitAsThreadOriginMeshLocal(); + SetRouterId(kInvalidRouterId); #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index 1a1025c33..fd876044a 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -769,6 +769,8 @@ private: MeshCoP::SteeringData mSteeringData; #endif + Ip6::Netif::UnicastAddress mLeaderAloc; + Callback mDiscoveryRequestCallback; }; diff --git a/tests/toranj/cli/test-025-mesh-local-prefix-change.py b/tests/toranj/cli/test-025-mesh-local-prefix-change.py new file mode 100755 index 000000000..a3f75b96a --- /dev/null +++ b/tests/toranj/cli/test-025-mesh-local-prefix-change.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2023, 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 cli import verify +from cli import verify_within +import cli +import time + +# ----------------------------------------------------------------------------------------------------------------------- +# Test description: Validate update of unicast/multicast mesh-local addresses on prefix change +# +# Network topology +# +# r1 ---- r2 +# + +test_name = __file__[:-3] if __file__.endswith('.py') else __file__ +print('-' * 120) +print('Starting \'{}\''.format(test_name)) + +# ----------------------------------------------------------------------------------------------------------------------- +# Creating `cli.Node` instances + +speedup = 40 +cli.Node.set_time_speedup_factor(speedup) + +r1 = cli.Node() +r2 = cli.Node() + +# ----------------------------------------------------------------------------------------------------------------------- +# Form topology + +r1.form('ml-change') +r2.join(r1) + +verify(r1.get_state() == 'leader') +verify(r2.get_state() == 'router') + +# ----------------------------------------------------------------------------------------------------------------------- +# Test Implementation + +r1.srp_server_enable() +r1.srp_client_enable_auto_start_mode() +r2.srp_client_enable_auto_start_mode() + +time.sleep(0.5) + +ml_prefix = r1.get_mesh_local_prefix() +ml_prefix = ml_prefix[:ml_prefix.index("/64") - 1] + +# Validate that r1 has 4 mesh-local address: ML-EID, RLOC, leader ALOC +# and since it is acting as SRP server the service ALOC. + +r1_addrs = r1.get_ip_addrs() +verify(sum([addr.startswith(ml_prefix) for addr in r1_addrs]) == 4) + +# Validate that r1 has link-local and realm-local All Thread Nodes +# multicast addresses which are prefix-based and use mesh-local +# prefix. + +r1_maddrs = r1.get_ip_maddrs() +verify(sum([ml_prefix in maddr for maddr in r1_maddrs]) == 2) + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Change the mesh-local prefix on all devices. + +r2.cli('dataset clear') +r2.cli('dataset meshlocalprefix fd00:1122:3344:5566::') +r2.cli('dataset delaytimer 1100') # `toranj` allows 1000 msec as minimum in its config +r2.cli('dataset updater start') + +time.sleep(0.5) + +ml_prefix = r1.get_mesh_local_prefix() +ml_prefix = ml_prefix[:ml_prefix.index("/64") - 1] + +verify(ml_prefix == 'fd00:1122:3344:5566:') + +# Validate that all 4 mesh-local address on r1 are updated to use the +# new mesh-local prefix. + +r1_addrs = r1.get_ip_addrs() +verify(sum([addr.startswith(ml_prefix) for addr in r1_addrs]) == 4) + +# Validate the network data entry for SRP server is also updated to +# used the new address. + +verify(r1.srp_client_get_server_address().startswith(ml_prefix)) + +# Validate the r1 multicast addresses are also updated + +r1_maddrs = r1.get_ip_maddrs() +verify(sum([ml_prefix in maddr for maddr in r1_maddrs]) == 2) + +# ----------------------------------------------------------------------------------------------------------------------- +# Test finished + +cli.Node.finalize_all_nodes() + +print('\'{}\' passed.'.format(test_name)) diff --git a/tests/toranj/openthread-core-toranj-config.h b/tests/toranj/openthread-core-toranj-config.h index 52e766be5..7e2d4c7d4 100644 --- a/tests/toranj/openthread-core-toranj-config.h +++ b/tests/toranj/openthread-core-toranj-config.h @@ -131,6 +131,8 @@ #define OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH 1 +#define OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE 1 + #define OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE 1 #define OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE 1 diff --git a/tests/toranj/start.sh b/tests/toranj/start.sh index 609faf7f8..3e07304e6 100755 --- a/tests/toranj/start.sh +++ b/tests/toranj/start.sh @@ -189,6 +189,7 @@ if [ "$TORANJ_CLI" = 1 ]; then run cli/test-022-netdata-full.py run cli/test-023-mesh-diag.py run cli/test-024-mle-adv-imax-change.py + run cli/test-025-mesh-local-prefix-change.py run cli/test-400-srp-client-server.py run cli/test-601-channel-manager-channel-change.py # Skip the "channel-select" test on a TREL only radio link, since it