diff --git a/include/openthread/backbone_router_ftd.h b/include/openthread/backbone_router_ftd.h index e5cafbd29..535b06b0d 100644 --- a/include/openthread/backbone_router_ftd.h +++ b/include/openthread/backbone_router_ftd.h @@ -39,6 +39,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -158,6 +159,18 @@ uint8_t otBackboneRouterGetRegistrationJitter(otInstance *aInstance); */ void otBackboneRouterSetRegistrationJitter(otInstance *aInstance, uint8_t aJitter); +/** + * This method gets the local Domain Prefix configuration. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[out] aConfig A pointer to the Domain Prefix configuration. + * + * @retval OT_ERROR_NONE Successfully got the Domain Prefix configuration. + * @retval OT_ERROR_NOT_FOUND No Domain Prefix was configured. + * + */ +otError otBackboneRouterGetDomainPrefix(otInstance *aInstance, otBorderRouterConfig *aConfig); + /** * @} * diff --git a/include/openthread/netdata.h b/include/openthread/netdata.h index c87fcbaba..6e29bd554 100644 --- a/include/openthread/netdata.h +++ b/include/openthread/netdata.h @@ -102,6 +102,18 @@ typedef struct otBorderRouterConfig */ bool mStable : 1; + /** + * TRUE, if this border router is able to supply DNS infomration obtained via ND. FALSE, otherwise. + */ + bool mNdDns : 1; + + /** + * TRUE, if this prefix is a Thread Domain Prefix. FALSE, otherwise. + * + * Note: Domain Prefix is introduced since Thread 1.2. + */ + bool mDp : 1; + /** * The Border Agent Rloc. */ diff --git a/src/cli/README.md b/src/cli/README.md index 82ad5d3ee..6683d56a4 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -78,7 +78,7 @@ Done * [ping](#ping-ipaddr-size-count-interval-hoplimit) * [pollperiod](#pollperiod-pollperiod) * [preferrouterid](#preferrouterid-routerid) -* [prefix](#prefix-add-prefix-pvdcsr-prf) +* [prefix](#prefix-add-prefix-padcrosnD-prf) * [promiscuous](#promiscuous) * [pskc](#pskc--p-keypassphrase) * [releaserouterid](#releaserouterid-routerid) @@ -1193,17 +1193,23 @@ Done ### prefix Get the prefix list in the local Network Data. +Note: For the Thread 1.2 border router with backbone capability, the local Domain + Prefix would be listed as well (with flag `D`), with preceeding `- ` if backbone + functionality is disabled. ```bash > prefix 2001:dead:beef:cafe::/64 paros med +- fd00:7d03:7d03:7d03::/64 prosD med Done ``` -### prefix add \ [pvdcsr] [prf] +### prefix add \ [padcrosnD] [prf] Add a valid prefix to the Network Data. +Note: The Domain Prefix flag (`D`) is only available for Thread 1.2. + * p: Preferred flag * a: Stateless IPv6 Address Autoconfiguration flag * d: DHCPv6 IPv6 Address Configuration flag @@ -1211,11 +1217,16 @@ Add a valid prefix to the Network Data. * r: Default Route flag * o: On Mesh flag * s: Stable flag +* n: Nd Dns flag +* D: Domain Prefix flag * prf: Default router preference, which may be 'high', 'med', or 'low'. ```bash > prefix add 2001:dead:beef:cafe::/64 paros med Done + +> prefix add fd00:7d03:7d03:7d03::/64 prosD med +Done ``` ### prefix remove \ diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index e2e1bfdb6..7ede5f185 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -2527,6 +2527,15 @@ otError Interpreter::ProcessPrefixAdd(uint8_t aArgsLength, char *aArgs[]) config.mStable = true; break; + case 'n': + config.mNdDns = true; + break; + +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + case 'D': + config.mDp = true; + break; +#endif default: ExitNow(error = OT_ERROR_INVALID_ARGS); } @@ -2575,6 +2584,76 @@ exit: return error; } +void Interpreter::OutputPrefix(otBorderRouterConfig &aConfig) +{ + mServer->OutputFormat("%x:%x:%x:%x::/%d ", HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[0]), + HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[1]), + HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[2]), + HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[3]), aConfig.mPrefix.mLength); + + if (aConfig.mPreferred) + { + mServer->OutputFormat("p"); + } + + if (aConfig.mSlaac) + { + mServer->OutputFormat("a"); + } + + if (aConfig.mDhcp) + { + mServer->OutputFormat("d"); + } + + if (aConfig.mConfigure) + { + mServer->OutputFormat("c"); + } + + if (aConfig.mDefaultRoute) + { + mServer->OutputFormat("r"); + } + + if (aConfig.mOnMesh) + { + mServer->OutputFormat("o"); + } + + if (aConfig.mStable) + { + mServer->OutputFormat("s"); + } + + if (aConfig.mNdDns) + { + mServer->OutputFormat("n"); + } + + if (aConfig.mDp) + { + mServer->OutputFormat("D"); + } + + switch (aConfig.mPreference) + { + case OT_ROUTE_PREFERENCE_LOW: + mServer->OutputFormat(" low"); + break; + + case OT_ROUTE_PREFERENCE_MED: + mServer->OutputFormat(" med"); + break; + + case OT_ROUTE_PREFERENCE_HIGH: + mServer->OutputFormat(" high"); + break; + } + + mServer->OutputFormat("\r\n"); +} + otError Interpreter::ProcessPrefixList(void) { otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; @@ -2582,62 +2661,20 @@ otError Interpreter::ProcessPrefixList(void) while (otBorderRouterGetNextOnMeshPrefix(mInstance, &iterator, &config) == OT_ERROR_NONE) { - mServer->OutputFormat("%x:%x:%x:%x::/%d ", HostSwap16(config.mPrefix.mPrefix.mFields.m16[0]), - HostSwap16(config.mPrefix.mPrefix.mFields.m16[1]), - HostSwap16(config.mPrefix.mPrefix.mFields.m16[2]), - HostSwap16(config.mPrefix.mPrefix.mFields.m16[3]), config.mPrefix.mLength); - - if (config.mPreferred) - { - mServer->OutputFormat("p"); - } - - if (config.mSlaac) - { - mServer->OutputFormat("a"); - } - - if (config.mDhcp) - { - mServer->OutputFormat("d"); - } - - if (config.mConfigure) - { - mServer->OutputFormat("c"); - } - - if (config.mDefaultRoute) - { - mServer->OutputFormat("r"); - } - - if (config.mOnMesh) - { - mServer->OutputFormat("o"); - } - - if (config.mStable) - { - mServer->OutputFormat("s"); - } - - switch (config.mPreference) - { - case OT_ROUTE_PREFERENCE_LOW: - mServer->OutputFormat(" low\r\n"); - break; - - case OT_ROUTE_PREFERENCE_MED: - mServer->OutputFormat(" med\r\n"); - break; - - case OT_ROUTE_PREFERENCE_HIGH: - mServer->OutputFormat(" high\r\n"); - break; - } + OutputPrefix(config); } +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + if (otBackboneRouterGetState(mInstance) == OT_BACKBONE_ROUTER_STATE_DISABLED) + { + SuccessOrExit(otBackboneRouterGetDomainPrefix(mInstance, &config)); + mServer->OutputFormat("- "); + OutputPrefix(config); + } + // Else already printed via above while loop. +exit: +#endif + return OT_ERROR_NONE; } diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index 7649c4c97..260581baa 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -318,6 +318,7 @@ private: otError ProcessPrefixAdd(uint8_t aArgsLength, char *aArgs[]); otError ProcessPrefixRemove(uint8_t aArgsLength, char *aArgs[]); otError ProcessPrefixList(void); + void OutputPrefix(otBorderRouterConfig &aConfig); #endif void ProcessPromiscuous(uint8_t aArgsLength, char *aArgs[]); #if OPENTHREAD_FTD diff --git a/src/core/api/backbone_router_ftd_api.cpp b/src/core/api/backbone_router_ftd_api.cpp index 57c6923f5..7477d8f58 100644 --- a/src/core/api/backbone_router_ftd_api.cpp +++ b/src/core/api/backbone_router_ftd_api.cpp @@ -75,9 +75,16 @@ void otBackboneRouterSetConfig(otInstance *aInstance, const otBackboneRouterConf otError otBackboneRouterRegister(otInstance *aInstance) { + otError error = OT_ERROR_NONE; + Instance &instance = *static_cast(aInstance); - return instance.Get().AddService(true /* Force registration */); + SuccessOrExit(error = instance.Get().AddService(true /* Force registration */)); + + instance.Get().HandleServerDataUpdated(); + +exit: + return error; } uint8_t otBackboneRouterGetRegistrationJitter(otInstance *aInstance) @@ -94,4 +101,13 @@ void otBackboneRouterSetRegistrationJitter(otInstance *aInstance, uint8_t aJitte return instance.Get().SetRegistrationJitter(aJitter); } +otError otBackboneRouterGetDomainPrefix(otInstance *aInstance, otBorderRouterConfig *aConfig) +{ + Instance &instance = *static_cast(aInstance); + + OT_ASSERT(aConfig != NULL); + + return instance.Get().GetDomainPrefix(*aConfig); +} + #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE diff --git a/src/core/api/border_router_api.cpp b/src/core/api/border_router_api.cpp index 79658a141..4138d5871 100644 --- a/src/core/api/border_router_api.cpp +++ b/src/core/api/border_router_api.cpp @@ -54,52 +54,49 @@ otError otBorderRouterGetNetData(otInstance *aInstance, bool aStable, uint8_t *a otError otBorderRouterAddOnMeshPrefix(otInstance *aInstance, const otBorderRouterConfig *aConfig) { - uint8_t flags = 0; + otError error = OT_ERROR_NONE; Instance &instance = *static_cast(aInstance); OT_ASSERT(aConfig != NULL); + // Add Prefix validation check: + // Thread 1.1 Specification 5.13.2 says + // "A valid prefix MUST NOT allow both DHCPv6 and SLAAC for address configuration" + VerifyOrExit(!aConfig->mDhcp || !aConfig->mSlaac, error = OT_ERROR_INVALID_ARGS); - if (aConfig->mPreferred) + error = instance.Get().AddOnMeshPrefix(*aConfig); +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + // Only try to configure Domain Prefix after the parameter is vaidated via above `AddOnMeshPrefix()`. + if (error == OT_ERROR_NONE && aConfig->mDp) { - flags |= NetworkData::BorderRouterEntry::kPreferredFlag; - } + // Restore local server data + instance.Get().RemoveOnMeshPrefix(aConfig->mPrefix.mPrefix.mFields.m8, + aConfig->mPrefix.mLength); - if (aConfig->mSlaac) - { - flags |= NetworkData::BorderRouterEntry::kSlaacFlag; + instance.Get().SetDomainPrefix(*aConfig); } +#endif - if (aConfig->mDhcp) - { - flags |= NetworkData::BorderRouterEntry::kDhcpFlag; - } - - if (aConfig->mConfigure) - { - flags |= NetworkData::BorderRouterEntry::kConfigureFlag; - } - - if (aConfig->mDefaultRoute) - { - flags |= NetworkData::BorderRouterEntry::kDefaultRouteFlag; - } - - if (aConfig->mOnMesh) - { - flags |= NetworkData::BorderRouterEntry::kOnMeshFlag; - } - - return instance.Get().AddOnMeshPrefix( - aConfig->mPrefix.mPrefix.mFields.m8, aConfig->mPrefix.mLength, aConfig->mPreference, flags, aConfig->mStable); +exit: + return error; } otError otBorderRouterRemoveOnMeshPrefix(otInstance *aInstance, const otIp6Prefix *aPrefix) { + otError error = OT_ERROR_NONE; Instance &instance = *static_cast(aInstance); OT_ASSERT(aPrefix != NULL); - return instance.Get().RemoveOnMeshPrefix(aPrefix->mPrefix.mFields.m8, aPrefix->mLength); +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + error = instance.Get().RemoveDomainPrefix(*aPrefix); + + if (error == OT_ERROR_NOT_FOUND) +#endif + { + error = instance.Get().RemoveOnMeshPrefix(aPrefix->mPrefix.mFields.m8, aPrefix->mLength); + } + + return error; } otError otBorderRouterGetNextOnMeshPrefix(otInstance * aInstance, diff --git a/src/core/backbone_router/local.cpp b/src/core/backbone_router/local.cpp index 66470a7c7..2897c3edb 100644 --- a/src/core/backbone_router/local.cpp +++ b/src/core/backbone_router/local.cpp @@ -57,6 +57,7 @@ Local::Local(Instance &aInstance) , mRegistrationJitter(Mle::kBackboneRouterRegistrationJitter) , mIsServiceAdded(false) { + mDomainPrefixConfig.mPrefix.mLength = 0; } void Local::SetEnabled(bool aEnable) @@ -66,14 +67,18 @@ void Local::SetEnabled(bool aEnable) if (aEnable) { SetState(OT_BACKBONE_ROUTER_STATE_SECONDARY); + AddDomainPrefixToNetworkData(); AddService(); } else { + RemoveDomainPrefixFromNetworkData(); RemoveService(); SetState(OT_BACKBONE_ROUTER_STATE_DISABLED); } + Get().HandleServerDataUpdated(); + exit: return; } @@ -82,7 +87,10 @@ void Local::Reset(void) { VerifyOrExit(mState != OT_BACKBONE_ROUTER_STATE_DISABLED); - RemoveService(); + if (RemoveService() == OT_ERROR_NONE) + { + Get().HandleServerDataUpdated(); + } if (mState == OT_BACKBONE_ROUTER_STATE_PRIMARY) { @@ -127,12 +135,15 @@ void Local::SetConfig(const BackboneRouterConfig &aConfig) if (update) { - IgnoreReturnValue(AddService()); Get().Signal(OT_CHANGED_THREAD_BACKBONE_ROUTER_LOCAL); + + if (AddService() == OT_ERROR_NONE) + { + Get().HandleServerDataUpdated(); + } } - otLogDebgNetData("BBR local: seqno (%d), delay (%ds), timeout (%ds)", mSequenceNumber, mReregistrationDelay, - mMlrTimeout); + LogBackboneRouterService("Set", OT_ERROR_NONE); } otError Local::AddService(bool aForce) @@ -158,29 +169,24 @@ otError Local::AddService(bool aForce) reinterpret_cast(&serverData), sizeof(serverData))); mIsServiceAdded = true; - Get().HandleServerDataUpdated(); - - otLogInfoNetData("BBR Service added: seqno (%d), delay (%ds), timeout (%ds)", mSequenceNumber, mReregistrationDelay, - mMlrTimeout); exit: - otLogInfoNetData("Add BBR Service: %s", otThreadErrorToString(error)); + LogBackboneRouterService("Add", error); return error; } otError Local::RemoveService(void) { - otError error = OT_ERROR_NONE; + otError error; uint8_t serviceData = NetworkData::ServiceTlv::kServiceDataBackboneRouter; SuccessOrExit(error = Get().RemoveService(NetworkData::ServiceTlv::kThreadEnterpriseNumber, &serviceData, sizeof(serviceData))); mIsServiceAdded = false; - Get().HandleServerDataUpdated(); exit: - otLogInfoNetData("Remove BBR Service %s", otThreadErrorToString(error)); + LogBackboneRouterService("Remove", error); return error; } @@ -227,7 +233,10 @@ void Local::UpdateBackboneRouterPrimary(Leader::State aState, const BackboneRout mReregistrationDelay = aConfig.mReregistrationDelay; mMlrTimeout = aConfig.mMlrTimeout; Get().Signal(OT_CHANGED_THREAD_BACKBONE_ROUTER_LOCAL); - AddService(true /* Force registration to refresh and restore Primary state */); + if (AddService(true /* Force registration to refresh and restore Primary state */) == OT_ERROR_NONE) + { + Get().HandleServerDataUpdated(); + } } else { @@ -238,6 +247,99 @@ exit: return; } +otError Local::GetDomainPrefix(NetworkData::OnMeshPrefixConfig &aConfig) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(mDomainPrefixConfig.mPrefix.mLength > 0, error = OT_ERROR_NOT_FOUND); + + aConfig = mDomainPrefixConfig; + +exit: + return error; +} + +otError Local::RemoveDomainPrefix(const otIp6Prefix &aPrefix) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(aPrefix.mLength > 0, error = OT_ERROR_INVALID_ARGS); + + VerifyOrExit(mDomainPrefixConfig.mPrefix.mLength == aPrefix.mLength, error = OT_ERROR_NOT_FOUND); + + VerifyOrExit(Ip6::Address::PrefixMatch(mDomainPrefixConfig.mPrefix.mPrefix.mFields.m8, aPrefix.mPrefix.mFields.m8, + BitVectorBytes(aPrefix.mLength)) >= aPrefix.mLength, + error = OT_ERROR_NOT_FOUND); + + if (IsEnabled()) + { + RemoveDomainPrefixFromNetworkData(); + } + + mDomainPrefixConfig.mPrefix.mLength = 0; + +exit: + return error; +} + +void Local::SetDomainPrefix(const NetworkData::OnMeshPrefixConfig &aConfig) +{ + if (IsEnabled()) + { + RemoveDomainPrefixFromNetworkData(); + } + + mDomainPrefixConfig = aConfig; + LogDomainPrefix("Set", OT_ERROR_NONE); + + if (IsEnabled()) + { + AddDomainPrefixToNetworkData(); + } +} + +void Local::RemoveDomainPrefixFromNetworkData(void) +{ + otError error = OT_ERROR_NOT_FOUND; // only used for logging. + + if (mDomainPrefixConfig.mPrefix.mLength > 0) + { + error = Get().RemoveOnMeshPrefix(mDomainPrefixConfig.mPrefix.mPrefix.mFields.m8, + mDomainPrefixConfig.mPrefix.mLength); + } + + LogDomainPrefix("Remove", error); +} + +void Local::AddDomainPrefixToNetworkData(void) +{ + otError error = OT_ERROR_NOT_FOUND; // only used for logging. + + if (mDomainPrefixConfig.mPrefix.mLength > 0) + { + error = Get().AddOnMeshPrefix(mDomainPrefixConfig); + } + + LogDomainPrefix("Add", error); +} + +#if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_NETDATA == 1) +void Local::LogDomainPrefix(const char *aAction, otError aError) +{ + otLogInfoNetData("%s Domain Prefix: %s/%d, %s", aAction, + mDomainPrefixConfig.mPrefix.mLength > 0 + ? (*static_cast(&mDomainPrefixConfig.mPrefix.mPrefix)).ToString().AsCString() + : "", + mDomainPrefixConfig.mPrefix.mLength, otThreadErrorToString(aError)); +} + +void Local::LogBackboneRouterService(const char *aAction, otError aError) +{ + otLogInfoNetData("%s BBR Service: seqno (%d), delay (%ds), timeout (%ds), %s", aAction, mSequenceNumber, + mReregistrationDelay, mMlrTimeout, otThreadErrorToString(aError)); +} +#endif + } // namespace BackboneRouter } // namespace ot diff --git a/src/core/backbone_router/local.hpp b/src/core/backbone_router/local.hpp index 3d56f7c9c..b8029582e 100644 --- a/src/core/backbone_router/local.hpp +++ b/src/core/backbone_router/local.hpp @@ -42,6 +42,7 @@ #include "backbone_router/leader.hpp" #include "net/netif.hpp" +#include "thread/network_data.hpp" namespace ot { @@ -162,9 +163,49 @@ public: */ void UpdateBackboneRouterPrimary(Leader::State aState, const BackboneRouterConfig &aConfig); + /** + * This method gets the Domain Prefix configuration. + * + * @param[out] aConfig A reference to the Domain Prefix configuration. + * + * @retval OT_ERROR_NONE Successfully got the Domain Prefix configuration. + * @retval OT_ERROR_NOT_FOUND No Domain Prefix was configured. + * + */ + otError GetDomainPrefix(NetworkData::OnMeshPrefixConfig &aConfig); + + /** + * This method removes the local Domain Prefix configuration. + * + * @param[in] aPrefix A reference to the IPv6 Domain Prefix. + * + * @retval OT_ERROR_NONE Successfully removed the Domain Prefix. + * @retval OT_ERROR_INVALID_ARGS @p aPrefix is invalid. + * @retval OT_ERROR_NOT_FOUND No Domain Prefix was configured or @p aPrefix doesn't match. + * + */ + otError RemoveDomainPrefix(const otIp6Prefix &aPrefix); + + /** + * This method sets the local Domain Prefix configuration. + * + * @param[in] aConfig A reference to the Domain Prefix configuration. + * + */ + void SetDomainPrefix(const NetworkData::OnMeshPrefixConfig &aConfig); + private: void SetState(BackboneRouterState aState); otError RemoveService(void); + void AddDomainPrefixToNetworkData(void); + void RemoveDomainPrefixFromNetworkData(void); +#if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_NETDATA == 1) + void LogBackboneRouterService(const char *aAction, otError aError); + void LogDomainPrefix(const char *aAction, otError aError); +#else + void LogBackboneRouterService(const char *, otError) {} + void LogDomainPrefix(const char *, otError) {} +#endif BackboneRouterState mState; uint32_t mMlrTimeout; @@ -176,6 +217,8 @@ private: // Used to check whether or not in restore stage after reset or whether to remove // Backbone Router service for Secondary Backbone Router if it was added by force. bool mIsServiceAdded; + + NetworkData::OnMeshPrefixConfig mDomainPrefixConfig; }; } // namespace BackboneRouter diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 5e10a707a..c3d492361 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -1744,7 +1744,10 @@ void MleRouter::HandleStateUpdateTimer(void) // If no Backbone Router service after jitter, try to register its own Backbone Router Service. if (!Get().HasPrimary()) { - Get().AddService(); + if (Get().AddService() == OT_ERROR_NONE) + { + Get().HandleServerDataUpdated(); + } } } } diff --git a/src/core/thread/network_data.cpp b/src/core/thread/network_data.cpp index 810cc487d..60b2b11f1 100644 --- a/src/core/thread/network_data.cpp +++ b/src/core/thread/network_data.cpp @@ -218,6 +218,8 @@ otError NetworkData::GetNextOnMeshPrefix(Iterator &aIterator, uint16_t aRloc16, aConfig.mOnMesh = borderRouterEntry->IsOnMesh(); aConfig.mStable = borderRouter->IsStable(); aConfig.mRloc16 = borderRouterEntry->GetRloc(); + aConfig.mNdDns = borderRouterEntry->IsNdDns(); + aConfig.mDp = borderRouterEntry->IsDp(); iterator.SetEntryIndex(index + 1); diff --git a/src/core/thread/network_data_local.cpp b/src/core/thread/network_data_local.cpp index 9f7ffba13..63a039751 100644 --- a/src/core/thread/network_data_local.cpp +++ b/src/core/thread/network_data_local.cpp @@ -54,9 +54,54 @@ Local::Local(Instance &aInstance) } #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE -otError Local::AddOnMeshPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength, int8_t aPrf, uint8_t aFlags, bool aStable) +otError Local::AddOnMeshPrefix(const OnMeshPrefixConfig &aConfig) { - return AddPrefix(aPrefix, aPrefixLength, NetworkDataTlv::kTypeBorderRouter, aPrf, aFlags, aStable); + uint16_t flags = 0; + + if (aConfig.mPreferred) + { + flags |= BorderRouterEntry::kPreferredFlag; + } + + if (aConfig.mSlaac) + { + flags |= BorderRouterEntry::kSlaacFlag; + } + + if (aConfig.mDhcp) + { + flags |= BorderRouterEntry::kDhcpFlag; + } + + if (aConfig.mConfigure) + { + flags |= BorderRouterEntry::kConfigureFlag; + } + + if (aConfig.mDefaultRoute) + { + flags |= BorderRouterEntry::kDefaultRouteFlag; + } + + if (aConfig.mOnMesh) + { + flags |= BorderRouterEntry::kOnMeshFlag; + } + + if (aConfig.mNdDns) + { + flags |= BorderRouterEntry::kNdDnsFlag; + } + +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + if (aConfig.mDp) + { + flags |= BorderRouterEntry::kDpFlag; + } +#endif + + return AddPrefix(aConfig.mPrefix.mPrefix.mFields.m8, aConfig.mPrefix.mLength, NetworkDataTlv::kTypeBorderRouter, + aConfig.mPreference, flags, aConfig.mStable); } otError Local::RemoveOnMeshPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength) @@ -78,7 +123,7 @@ otError Local::AddPrefix(const uint8_t * aPrefix, uint8_t aPrefixLength, NetworkDataTlv::Type aSubTlvType, int8_t aPrf, - uint8_t aFlags, + uint16_t aFlags, bool aStable) { otError error = OT_ERROR_NONE; @@ -86,7 +131,7 @@ otError Local::AddPrefix(const uint8_t * aPrefix, uint8_t subTlvLength; PrefixTlv *prefixTlv; - VerifyOrExit(prefixLengthBytes <= sizeof(Ip6::Address), error = OT_ERROR_INVALID_ARGS); + VerifyOrExit(aPrefixLength > 0 && prefixLengthBytes <= sizeof(Ip6::Address), error = OT_ERROR_INVALID_ARGS); switch (aPrf) { diff --git a/src/core/thread/network_data_local.hpp b/src/core/thread/network_data_local.hpp index ac49db664..025bee5f6 100644 --- a/src/core/thread/network_data_local.hpp +++ b/src/core/thread/network_data_local.hpp @@ -73,18 +73,14 @@ public: /** * This method adds a Border Router entry to the Thread Network Data. * - * @param[in] aPrefix A pointer to the prefix. - * @param[in] aPrefixLength The prefix length in bits. - * @param[in] aPrf The preference value. - * @param[in] aFlags The Border Router Flags value. - * @param[in] aStable The Stable value. + * @param[in] aConfig A reference to the on mesh perfix configuration. * * @retval OT_ERROR_NONE Successfully added the Border Router entry. * @retval OT_ERROR_NO_BUFS Insufficient space to add the Border Router entry. * @retval OT_ERROR_INVALID_ARGS The prefix is mesh local prefix. * */ - otError AddOnMeshPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength, int8_t aPrf, uint8_t aFlags, bool aStable); + otError AddOnMeshPrefix(const OnMeshPrefixConfig &aConfig); /** * This method removes a Border Router entry from the Thread Network Data. @@ -182,7 +178,7 @@ private: uint8_t aPrefixLength, NetworkDataTlv::Type aSubTlvType, int8_t aPrf, - uint8_t aFlags, + uint16_t aFlags, bool aStable); otError RemovePrefix(const uint8_t *aPrefix, uint8_t aPrefixLength, NetworkDataTlv::Type aSubTlvType); void UpdateRloc(PrefixTlv &aPrefix); diff --git a/src/core/thread/network_data_tlvs.hpp b/src/core/thread/network_data_tlvs.hpp index 305d08cc4..7c8e96001 100644 --- a/src/core/thread/network_data_tlvs.hpp +++ b/src/core/thread/network_data_tlvs.hpp @@ -521,14 +521,16 @@ class BorderRouterEntry public: enum { - kPreferenceOffset = 6, + kPreferenceOffset = 14, kPreferenceMask = 3 << kPreferenceOffset, - kPreferredFlag = 1 << 5, - kSlaacFlag = 1 << 4, - kDhcpFlag = 1 << 3, - kConfigureFlag = 1 << 2, - kDefaultRouteFlag = 1 << 1, - kOnMeshFlag = 1 << 0, + kPreferredFlag = 1 << 13, + kSlaacFlag = 1 << 12, + kDhcpFlag = 1 << 11, + kConfigureFlag = 1 << 10, + kDefaultRouteFlag = 1 << 9, + kOnMeshFlag = 1 << 8, + kNdDnsFlag = 1 << 7, + kDpFlag = 1 << 6, }; /** @@ -538,8 +540,7 @@ public: void Init(void) { SetRloc(Mac::kShortAddrInvalid); - mFlags = 0; - mReserved = 0; + mFlags = 0; } /** @@ -558,20 +559,23 @@ public: void SetRloc(uint16_t aRloc16) { mRloc = HostSwap16(aRloc16); } /** - * This method returns the Flags byte value. + * This method returns the Flags value. * - * @returns The Flags byte value. + * @returns The Flags value. * */ - uint8_t GetFlags(void) const { return mFlags & ~kPreferenceMask; } + uint16_t GetFlags(void) const { return HostSwap16(mFlags) & ~kPreferenceMask; } /** - * This method sets the Flags byte value. + * This method sets the Flags value. * - * @param[in] aFlags The Flags byte value. + * @param[in] aFlags The Flags value. * */ - void SetFlags(uint8_t aFlags) { mFlags = (mFlags & kPreferenceMask) | (aFlags & ~kPreferenceMask); } + void SetFlags(uint16_t aFlags) + { + mFlags = HostSwap16((HostSwap16(mFlags) & kPreferenceMask) | (aFlags & ~kPreferenceMask)); + } /** * This method returns the Preference value. @@ -579,7 +583,10 @@ public: * @returns the Preference value. * */ - int8_t GetPreference(void) const { return static_cast(mFlags) >> kPreferenceOffset; } + int8_t GetPreference(void) const + { + return static_cast(static_cast(HostSwap16(mFlags)) >> kPreferenceOffset); + } /** * This method sets the Preference value. @@ -589,7 +596,7 @@ public: */ void SetPreference(int8_t aPrf) { - mFlags = (mFlags & ~kPreferenceMask) | ((static_cast(aPrf) << kPreferenceOffset) & kPreferenceMask); + mFlags = HostSwap16(GetFlags() | ((static_cast(aPrf) << kPreferenceOffset) & kPreferenceMask)); } /** @@ -599,19 +606,7 @@ public: * @retval FALSE If the Preferred flag is not set. * */ - bool IsPreferred(void) const { return (mFlags & kPreferredFlag) != 0; } - - /** - * This method clears the Preferred flag. - * - */ - void ClearPreferred(void) { mFlags &= ~kPreferredFlag; } - - /** - * This method sets the Preferred flag. - * - */ - void SetPreferred(void) { mFlags |= kPreferredFlag; } + bool IsPreferred(void) const { return (HostSwap16(mFlags) & kPreferredFlag) != 0; } /** * This method indicates whether or not the SLAAC flag is set. @@ -620,19 +615,7 @@ public: * @retval FALSE If the SLAAC flag is not set. * */ - bool IsSlaac(void) const { return (mFlags & kSlaacFlag) != 0; } - - /** - * This method clears the SLAAC flag. - * - */ - void ClearSlaac(void) { mFlags &= ~kSlaacFlag; } - - /** - * This method sets the SLAAC flag. - * - */ - void SetSlaac(void) { mFlags |= kSlaacFlag; } + bool IsSlaac(void) const { return (HostSwap16(mFlags) & kSlaacFlag) != 0; } /** * This method indicates whether or not the DHCP flag is set. @@ -641,19 +624,7 @@ public: * @retval FALSE If the DHCP flag is not set. * */ - bool IsDhcp(void) const { return (mFlags & kDhcpFlag) != 0; } - - /** - * This method clears the DHCP flag. - * - */ - void ClearDhcp(void) { mFlags &= ~kDhcpFlag; } - - /** - * This method sets the DHCP flag. - * - */ - void SetDhcp(void) { mFlags |= kDhcpFlag; } + bool IsDhcp(void) const { return (HostSwap16(mFlags) & kDhcpFlag) != 0; } /** * This method indicates whether or not the Configure flag is set. @@ -662,19 +633,7 @@ public: * @retval FALSE If the Configure flag is not set. * */ - bool IsConfigure(void) const { return (mFlags & kConfigureFlag) != 0; } - - /** - * This method clears the Configure flag. - * - */ - void ClearConfigure(void) { mFlags &= ~kConfigureFlag; } - - /** - * This method sets the Configure flag. - * - */ - void SetConfigure(void) { mFlags |= kConfigureFlag; } + bool IsConfigure(void) const { return (HostSwap16(mFlags) & kConfigureFlag) != 0; } /** * This method indicates whether or not the Default Route flag is set. @@ -683,19 +642,7 @@ public: * @retval FALSE If the Default Route flag is not set. * */ - bool IsDefaultRoute(void) const { return (mFlags & kDefaultRouteFlag) != 0; } - - /** - * This method clears the Default Route flag. - * - */ - void ClearDefaultRoute(void) { mFlags &= ~kDefaultRouteFlag; } - - /** - * This method sets the Default Route flag. - * - */ - void SetDefaultRoute(void) { mFlags |= kDefaultRouteFlag; } + bool IsDefaultRoute(void) const { return (HostSwap16(mFlags) & kDefaultRouteFlag) != 0; } /** * This method indicates whether or not the On-Mesh flag is set. @@ -704,19 +651,25 @@ public: * @retval FALSE If the On-Mesh flag is not set. * */ - bool IsOnMesh(void) const { return (mFlags & kOnMeshFlag) != 0; } + bool IsOnMesh(void) const { return (HostSwap16(mFlags) & kOnMeshFlag) != 0; } /** - * This method clears the On-Mesh flag. + * This method indicates whether or not the Nd-Dns flag is set. + * + * @retval TRUE If the Nd-Dns flag is set. + * @retval FALSE If the Nd-Dns flag is not set. * */ - void ClearOnMesh(void) { mFlags &= ~kOnMeshFlag; } + bool IsNdDns(void) const { return (HostSwap16(mFlags) & kNdDnsFlag) != 0; } /** - * This method sets the On-Mesh flag. + * This method indicates whether or not the Domain Prefix flag is set. + * + * @retval TRUE If the Domain Prefix flag is set. + * @retval FALSE If the Domain Prefix flag is not set. * */ - void SetOnMesh(void) { mFlags |= kOnMeshFlag; } + bool IsDp(void) const { return (HostSwap16(mFlags) & kDpFlag) != 0; } /** * This method returns a pointer to the next BorderRouterEntry @@ -736,8 +689,7 @@ public: private: uint16_t mRloc; - uint8_t mFlags; - uint8_t mReserved; + uint16_t mFlags; } OT_TOOL_PACKED_END; /** diff --git a/tests/scripts/thread-cert/config.py b/tests/scripts/thread-cert/config.py index fb973aaa0..f491dc75c 100644 --- a/tests/scripts/thread-cert/config.py +++ b/tests/scripts/thread-cert/config.py @@ -56,6 +56,8 @@ REALM_LOCAL_ALL_ROUTERS_ADDRESS = 'ff03::2' LINK_LOCAL_ALL_NODES_ADDRESS = 'ff02::1' LINK_LOCAL_ALL_ROUTERS_ADDRESS = 'ff02::2' +DOMAIN_PREFIX = 'fd00:7d03:7d03:7d03::/64' + DEFAULT_MASTER_KEY = bytearray([ 0x00, 0x11, diff --git a/tests/scripts/thread-cert/node.py b/tests/scripts/thread-cert/node.py index ba52c9ce5..0f762d200 100755 --- a/tests/scripts/thread-cert/node.py +++ b/tests/scripts/thread-cert/node.py @@ -509,6 +509,15 @@ class Node: self.send_command(cmd) self._expect('Done') + def set_domain_prefix(self, prefix): + flags = 'prosD' + self.add_prefix(prefix, flags) + self.register_netdata() + + def remove_domain_prefix(self, prefix): + self.remove_prefix(prefix) + self.register_netdata() + def set_link_quality(self, addr, lqi): cmd = 'macfilter rss add-lqi %s %s' % (addr, lqi) self.send_command(cmd) diff --git a/tests/scripts/thread-cert/v1_2_test_backbone_router_service.py b/tests/scripts/thread-cert/v1_2_test_backbone_router_service.py index f17cecc6b..fbb5c97db 100755 --- a/tests/scripts/thread-cert/v1_2_test_backbone_router_service.py +++ b/tests/scripts/thread-cert/v1_2_test_backbone_router_service.py @@ -30,6 +30,7 @@ import unittest import thread_cert +import config LEADER_1_1 = 1 BBR_1 = 2 @@ -90,10 +91,12 @@ class TestBackboneRouterService(thread_cert.TestCase): WAIT_TIME = WAIT_ATTACH self.simulator.go(WAIT_TIME) self.assertEqual(self.nodes[LEADER_1_1].get_state(), 'leader') + self.simulator.set_lowpan_context(1, config.DOMAIN_PREFIX) # 1) First Backbone Router would become the Primary. self.nodes[BBR_1].set_router_selection_jitter(ROUTER_SELECTION_JITTER) self.nodes[BBR_1].set_bbr_registration_jitter(BBR_REGISTRATION_JITTER) + self.nodes[BBR_1].set_domain_prefix(config.DOMAIN_PREFIX) self.nodes[BBR_1].set_backbone_router(seqno=1) self.nodes[BBR_1].start() WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER @@ -111,6 +114,7 @@ class TestBackboneRouterService(thread_cert.TestCase): self.nodes[BBR_1].reset() self.nodes[BBR_1].set_bbr_registration_jitter(BBR_REGISTRATION_JITTER) self.nodes[BBR_1].set_router_selection_jitter(ROUTER_SELECTION_JITTER) + self.nodes[BBR_1].set_domain_prefix(config.DOMAIN_PREFIX) self.nodes[BBR_1].enable_backbone_router() self.nodes[BBR_1].start() WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER @@ -135,6 +139,7 @@ class TestBackboneRouterService(thread_cert.TestCase): ROUTER_SELECTION_JITTER) self.nodes[BBR_1].set_bbr_registration_jitter( BBR_REGISTRATION_JITTER) + self.nodes[BBR_1].set_domain_prefix(config.DOMAIN_PREFIX) self.nodes[BBR_1].enable_backbone_router() self.nodes[BBR_1].start() WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER @@ -157,6 +162,7 @@ class TestBackboneRouterService(thread_cert.TestCase): # by default. self.nodes[BBR_2].set_router_selection_jitter(ROUTER_SELECTION_JITTER) self.nodes[BBR_2].set_bbr_registration_jitter(BBR_REGISTRATION_JITTER) + self.nodes[BBR_2].set_domain_prefix(config.DOMAIN_PREFIX) self.nodes[BBR_2].start() WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER self.simulator.go(WAIT_TIME) @@ -168,12 +174,16 @@ class TestBackboneRouterService(thread_cert.TestCase): # Enable Backbone function, it will stay at Secondary state as # there is Primary Backbone Router already. + # Here removes the Domain Prefix before enabling backbone function + # intentionally to avoid SRV_DATA.ntf due to prefix inconsistency. + self.nodes[BBR_2].remove_domain_prefix(config.DOMAIN_PREFIX) self.nodes[BBR_2].enable_backbone_router() self.nodes[BBR_2].set_backbone_router(seqno=255) WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE self.simulator.go(WAIT_TIME) self.assertEqual(self.nodes[BBR_2].get_backbone_router_state(), 'Secondary') + # Check no SRV_DATA.ntf. messages = self.simulator.get_messages_sent_by(BBR_2) msg = messages.next_coap_message('0.02', '/a/sd', False) @@ -219,6 +229,7 @@ class TestBackboneRouterService(thread_cert.TestCase): # Verify that BBR_2 stays at Secondary. self.nodes[BBR_2].set_router_selection_jitter(ROUTER_SELECTION_JITTER) self.nodes[BBR_2].set_bbr_registration_jitter(BBR_REGISTRATION_JITTER) + self.nodes[BBR_1].set_domain_prefix(config.DOMAIN_PREFIX) self.nodes[BBR_2].enable_backbone_router() self.nodes[BBR_2].interface_up() self.nodes[BBR_2].thread_start()