[dua] dua registration and re-registration (#5276)

- registration workflow framework
- registration and reregistration
- registration and reregistration on behalf of children
- add pseudo response status for test/certification purpose
- add unit test
This commit is contained in:
Rongli Sun
2020-07-31 05:10:22 +08:00
committed by GitHub
parent 8c094c6ac2
commit 82e7e32bb5
27 changed files with 1481 additions and 55 deletions
+19
View File
@@ -174,6 +174,25 @@ void otBackboneRouterSetRegistrationJitter(otInstance *aInstance, uint8_t aJitte
*/
otError otBackboneRouterGetDomainPrefix(otInstance *aInstance, otBorderRouterConfig *aConfig);
/**
* This method configures response status for next DUA registration.
*
* Note: available only when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled.
* Only used for test and certification.
*
* TODO: (DUA) support coap error code and corresponding process for certification purpose.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aMlIid A pointer to the Mesh Local IID. If NULL, respond with @p aStatus for any
* coming DUA.req, otherwise only respond the one with matching @p aMlIid.
* @param[in] aStatus The status to respond.
*
*
*/
void otBackboneRouterConfigNextDuaRegistrationResponse(otInstance * aInstance,
const otIp6InterfaceIdentifier *aMlIid,
uint8_t aStatus);
/**
* @}
*
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (18)
#define OPENTHREAD_API_VERSION (19)
/**
* @addtogroup api-instance
+1 -1
View File
@@ -48,7 +48,7 @@ readonly VERBOSE="${VERBOSE:-0}"
build_simulation()
{
local version="$1"
local options=("-DOT_THREAD_VERSION=${version}" "-DBUILD_TESTING=ON")
local options=("-DOT_THREAD_VERSION=${version}" "-DBUILD_TESTING=ON" "-DOT_REFERENCE_DEVICE=ON")
if [[ ${version} == "1.2" ]]; then
options+=("-DOT_DUA=ON")
+21
View File
@@ -118,6 +118,27 @@ BBR Primary: None
Done
```
### bbr mgmt dua \<status\> [meshLocalIid]
Configure the response status for DUA.req with meshLocalIid in payload. Without meshLocalIid, simply respond any coming DUA.req next with the specified status.
Only for testing/reference device.
known status value:
- 0: ST_DUA_SUCCESS
- 1: ST_DUA_REREGISTER
- 2: ST_DUA_INVALID
- 3: ST_DUA_DUPLICATE
- 4: ST_DUA_NO_RESOURCES
- 5: ST_DUA_BBR_NOT_PRIMARY
- 6: ST_DUA_GENERAL_FAILURE
```bash
> bbr mgmt dua 1 2f7c235e5025a2fd
Done
```
### bbr state
Show local Backbone state ([`Disabled`,`Primary`, `Secondary`]) for Thread 1.2 FTD.
+30 -2
View File
@@ -514,9 +514,37 @@ void Interpreter::ProcessBackboneRouter(uint8_t aArgsLength, char *aArgs[])
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
else
{
error = ProcessBackboneRouterLocal(aArgsLength, aArgs);
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
if (strcmp(aArgs[0], "mgmt") == 0)
{
unsigned long value;
VerifyOrExit((aArgsLength == 3 || aArgsLength == 4), error = OT_ERROR_INVALID_ARGS);
if (strcmp(aArgs[1], "dua") == 0)
{
otIp6InterfaceIdentifier *mlIid = nullptr;
otIp6InterfaceIdentifier iid;
SuccessOrExit(error = ParseUnsignedLong(aArgs[2], value));
if (aArgsLength == 4)
{
VerifyOrExit(Hex2Bin(aArgs[3], iid.mFields.m8, sizeof(iid)) == sizeof(iid),
error = OT_ERROR_INVALID_ARGS);
mlIid = &iid;
}
otBackboneRouterConfigNextDuaRegistrationResponse(mInstance, mlIid, static_cast<uint8_t>(value));
ExitNow();
}
}
#endif // OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
SuccessOrExit(error = ProcessBackboneRouterLocal(aArgsLength, aArgs));
}
#endif
exit:
#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
AppendResult(error);
}
+12
View File
@@ -111,4 +111,16 @@ otError otBackboneRouterGetDomainPrefix(otInstance *aInstance, otBorderRouterCon
*static_cast<NetworkData::OnMeshPrefixConfig *>(aConfig));
}
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
void otBackboneRouterConfigNextDuaRegistrationResponse(otInstance * aInstance,
const otIp6InterfaceIdentifier *aMlIid,
uint8_t aStatus)
{
Instance &instance = *static_cast<Instance *>(aInstance);
instance.Get<BackboneRouter::Manager>().ConfigNextDuaRegistrationResponse(
static_cast<const Ip6::InterfaceIdentifier *>(aMlIid), aStatus);
}
#endif
#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
+6 -2
View File
@@ -227,6 +227,10 @@ void Leader::UpdateBackboneRouterPrimary(void)
#if OPENTHREAD_CONFIG_MLR_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
Get<MlrManager>().HandleBackboneRouterPrimaryUpdate(state, mConfig);
#endif
#if OPENTHREAD_CONFIG_DUA_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
Get<DuaManager>().HandleBackboneRouterPrimaryUpdate(state, mConfig);
#endif
}
void Leader::UpdateDomainPrefixConfig(void)
@@ -282,8 +286,8 @@ void Leader::UpdateDomainPrefixConfig(void)
Get<Local>().UpdateAllDomainBackboneRouters(state);
#endif
#if OPENTHREAD_CONFIG_DUA_ENABLE
Get<DuaManager>().UpdateDomainUnicastAddress(state);
#if OPENTHREAD_CONFIG_DUA_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
Get<DuaManager>().HandleDomainPrefixUpdate(state);
#endif
}
+4 -2
View File
@@ -40,6 +40,8 @@
#include <openthread/backbone_router.h>
#include <openthread/ip6.h>
#include "coap/coap.hpp"
#include "coap/coap_message.hpp"
#include "common/locator.hpp"
#include "net/ip6_address.hpp"
@@ -160,8 +162,8 @@ public:
*
* @param[in] aAddress A reference to the address.
*
* @retval true @p aAddress is a domain unicast address.
* @retval false @p aAddress is not a domain unicast address.
* @retval true @p aAddress is a Domain Unicast Address.
* @retval false @p aAddress is not a Domain Unicast Address.
*
*/
bool IsDomainUnicast(const Ip6::Address &aAddress) const;
+98
View File
@@ -42,6 +42,7 @@
#include "common/random.hpp"
#include "thread/mle_types.hpp"
#include "thread/thread_netif.hpp"
#include "thread/thread_tlvs.hpp"
#include "thread/thread_uri_paths.hpp"
namespace ot {
@@ -52,6 +53,11 @@ Manager::Manager(Instance &aInstance)
: InstanceLocator(aInstance)
, Notifier::Receiver(aInstance, Manager::HandleNotifierEvents)
, mMulticastListenerRegistration(OT_URI_PATH_MLR, Manager::HandleMulticastListenerRegistration, this)
, mDuaRegistration(OT_URI_PATH_DUA_REGISTRATION_REQUEST, Manager::HandleDuaRegistration, this)
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
, mDuaResponseStatus(ThreadStatusTlv::kDuaSuccess)
, mDuaResponseIsSpecified(false)
#endif
{
}
@@ -62,10 +68,12 @@ void Manager::HandleNotifierEvents(Events aEvents)
if (Get<BackboneRouter::Local>().GetState() == OT_BACKBONE_ROUTER_STATE_DISABLED)
{
Get<Coap::Coap>().RemoveResource(mMulticastListenerRegistration);
Get<Coap::Coap>().RemoveResource(mDuaRegistration);
}
else
{
Get<Coap::Coap>().AddResource(mMulticastListenerRegistration);
Get<Coap::Coap>().AddResource(mDuaRegistration);
}
}
}
@@ -118,6 +126,96 @@ exit:
otLogInfoBbr("Sent MLR.rsp (status=%d): %s", aStatus, otThreadErrorToString(error));
}
void Manager::HandleDuaRegistration(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
otError error = OT_ERROR_NONE;
ThreadStatusTlv::DuaStatus status = ThreadStatusTlv::kDuaSuccess;
bool isPrimary = Get<BackboneRouter::Local>().IsPrimary();
uint32_t lastTransactionTime = 0;
Ip6::Address target;
Ip6::InterfaceIdentifier meshLocalIid;
VerifyOrExit(aMessage.IsConfirmable() && aMessage.GetCode() == OT_COAP_CODE_POST, error = OT_ERROR_PARSE);
SuccessOrExit(error = Tlv::FindTlv(aMessage, ThreadTlv::kTarget, &target, sizeof(target)));
SuccessOrExit(error = Tlv::FindTlv(aMessage, ThreadTlv::kMeshLocalEid, &meshLocalIid, sizeof(meshLocalIid)));
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
if (mDuaResponseIsSpecified && (mDuaResponseTargetMlIid.IsUnspecified() || mDuaResponseTargetMlIid == meshLocalIid))
{
mDuaResponseIsSpecified = false;
ExitNow(status = mDuaResponseStatus);
}
#endif
VerifyOrExit(isPrimary, status = ThreadStatusTlv::kDuaNotPrimary);
VerifyOrExit(Get<BackboneRouter::Leader>().IsDomainUnicast(target), status = ThreadStatusTlv::kDuaInvalid);
if (Tlv::FindUint32Tlv(aMessage, ThreadTlv::kLastTransactionTime, lastTransactionTime) == OT_ERROR_NONE)
{
// TODO: (DUA) hasLastTransactionTime = true;
}
// TODO: (DUA) Add ND-PROXY table management
// TODO: (DUA) Add DAD process
// TODO: (DUA) Extended Address Query
exit:
otLogInfoBbr("Received DUA.req on %s: %s", (isPrimary ? "PBBR" : "SBBR"), otThreadErrorToString(error));
if (error == OT_ERROR_NONE)
{
SendDuaRegistrationResponse(aMessage, aMessageInfo, target, status);
}
}
void Manager::SendDuaRegistrationResponse(const Coap::Message & aMessage,
const Ip6::MessageInfo & aMessageInfo,
const Ip6::Address & aTarget,
ThreadStatusTlv::DuaStatus aStatus)
{
otError error = OT_ERROR_NONE;
Coap::Message *message = nullptr;
VerifyOrExit((message = Get<Coap::Coap>().NewMessage()) != nullptr, error = OT_ERROR_NO_BUFS);
SuccessOrExit(message->SetDefaultResponseHeader(aMessage));
SuccessOrExit(message->SetPayloadMarker());
SuccessOrExit(Tlv::AppendUint8Tlv(*message, ThreadTlv::kStatus, aStatus));
SuccessOrExit(Tlv::AppendTlv(*message, ThreadTlv::kTarget, &aTarget, sizeof(aTarget)));
SuccessOrExit(error = Get<Coap::Coap>().SendMessage(*message, aMessageInfo));
exit:
if (error != OT_ERROR_NONE && message != nullptr)
{
message->Free();
}
otLogInfoBbr("Sent DUA.rsp for DUA %s, status %d %s", aTarget.ToString().AsCString(), aStatus,
otThreadErrorToString(error));
}
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
void Manager::ConfigNextDuaRegistrationResponse(const Ip6::InterfaceIdentifier *aMlIid, uint8_t aStatus)
{
mDuaResponseIsSpecified = true;
if (aMlIid)
{
mDuaResponseTargetMlIid = *aMlIid;
}
else
{
mDuaResponseTargetMlIid.Clear();
}
mDuaResponseStatus = static_cast<ThreadStatusTlv::DuaStatus>(aStatus);
}
#endif
} // namespace BackboneRouter
} // namespace ot
+33
View File
@@ -64,6 +64,21 @@ public:
*/
explicit Manager(Instance &aInstance);
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
/**
* This method configures response status for next DUA registration.
*
* Note: available only when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled.
* Only used for test and certification.
*
* @param[in] aMlIid A pointer to the Mesh Local IID. If NULL, respond with @p aStatus for any
* coming DUA.req, otherwise only respond the one with matching @p aMlIid.
* @param[in] aStatus The status to respond.
*
*/
void ConfigNextDuaRegistrationResponse(const Ip6::InterfaceIdentifier *aMlIid, uint8_t aStatus);
#endif
private:
static void HandleMulticastListenerRegistration(void * aContext,
otMessage * aMessage,
@@ -77,6 +92,17 @@ private:
const Ip6::MessageInfo & aMessageInfo,
ThreadStatusTlv::MlrStatus aStatus);
static void HandleDuaRegistration(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
{
static_cast<Manager *>(aContext)->HandleDuaRegistration(*static_cast<const Coap::Message *>(aMessage),
*static_cast<const Ip6::MessageInfo *>(aMessageInfo));
}
void HandleDuaRegistration(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void SendDuaRegistrationResponse(const Coap::Message & aMessage,
const Ip6::MessageInfo & aMessageInfo,
const Ip6::Address & aTarget,
ThreadStatusTlv::DuaStatus aStatus);
static void HandleNotifierEvents(Notifier::Receiver &aReceiver, Events aEvents)
{
static_cast<Manager &>(aReceiver).HandleNotifierEvents(aEvents);
@@ -84,6 +110,13 @@ private:
void HandleNotifierEvents(Events aEvents);
Coap::Resource mMulticastListenerRegistration;
Coap::Resource mDuaRegistration;
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
Ip6::InterfaceIdentifier mDuaResponseTargetMlIid;
ThreadStatusTlv::DuaStatus mDuaResponseStatus;
bool mDuaResponseIsSpecified : 1;
#endif
};
} // namespace BackboneRouter
+7 -7
View File
@@ -743,13 +743,6 @@ template <> inline BackboneRouter::Manager &Instance::Get(void)
#endif
#if OPENTHREAD_CONFIG_DUA_ENABLE
template <> inline DuaManager &Instance::Get(void)
{
return mThreadNetif.mDuaManager;
}
#endif
#if OPENTHREAD_CONFIG_MLR_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
template <> inline MlrManager &Instance::Get(void)
{
@@ -757,6 +750,13 @@ template <> inline MlrManager &Instance::Get(void)
}
#endif
#if OPENTHREAD_CONFIG_DUA_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
template <> inline DuaManager &Instance::Get(void)
{
return mThreadNetif.mDuaManager;
}
#endif
#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
#if OPENTHREAD_CONFIG_OTNS_ENABLE
+10
View File
@@ -172,6 +172,16 @@
#define OPENTHREAD_CONFIG_TMF_NETWORK_DIAG_MTD_ENABLE 0
#endif
/**
* @def OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
*
* Define to 1 for Thread 1.2 FTD device to register DUA of its MTD children registered
* even if it doesn't enable DUA feature itself.
*
*/
#define OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE \
((OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) && OPENTHREAD_FTD)
/**
*
* This setting configures the Multicast Listener Registration parent proxing in Thread 1.2.
+1 -1
View File
@@ -210,7 +210,7 @@ public:
* @param[in] aNumFastPolls If non-zero, number of fast polls to send, if zero, default value is used instead.
*
*/
void SendFastPolls(uint8_t aNumFastPolls);
void SendFastPolls(uint8_t aNumFastPolls = 0);
/**
* This method asks data poll sender to stop fast polls when the expecting response is received.
+565 -17
View File
@@ -33,7 +33,7 @@
#include "dua_manager.hpp"
#if (OPENTHREAD_FTD || OPENTHREAD_MTD) && OPENTHREAD_CONFIG_DUA_ENABLE
#if OPENTHREAD_CONFIG_DUA_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
#include "common/code_utils.hpp"
#include "common/instance.hpp"
@@ -41,42 +41,94 @@
#include "common/logging.hpp"
#include "common/settings.hpp"
#include "net/ip6_address.hpp"
#include "thread/mle_types.hpp"
#include "thread/thread_netif.hpp"
#include "thread/thread_tlvs.hpp"
#include "thread/thread_uri_paths.hpp"
#include "utils/slaac_address.hpp"
namespace ot {
DuaManager::DuaManager(Instance &aInstance)
: InstanceLocator(aInstance)
, Notifier::Receiver(aInstance, DuaManager::HandleNotifierEvents)
, mTimer(aInstance, DuaManager::HandleTimer, this)
, mRegistrationTask(aInstance, DuaManager::HandleRegistrationTask, this)
, mDuaNotification(OT_URI_PATH_DUA_REGISTRATION_NOTIFY, &DuaManager::HandleDuaNotification, this)
, mIsDuaPending(false)
#if OPENTHREAD_CONFIG_DUA_ENABLE
, mDuaState(kNotExist)
, mDadCounter(0)
, mLastRegistrationTime(0)
#endif
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
, mChildIndexDuaRegistering(0)
, mRegisterCurrentChildIndex(false)
#endif
{
mDelay.mValue = 0;
#if OPENTHREAD_CONFIG_DUA_ENABLE
mDomainUnicastAddress.Clear();
mDomainUnicastAddress.mAddressOrigin = OT_ADDRESS_ORIGIN_THREAD;
mDomainUnicastAddress.mPreferred = true;
mDomainUnicastAddress.mPreferred = false;
mDomainUnicastAddress.mValid = true;
mDomainUnicastAddress.mScopeOverride = Ip6::Address::kGlobalScope;
mDomainUnicastAddress.mScopeOverrideValid = true;
mFixedDuaInterfaceIdentifier.Clear();
#endif
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
mChildDuaMask.Clear();
mChildDuaRegisteredMask.Clear();
#endif
Get<Coap::Coap>().AddResource(mDuaNotification);
}
void DuaManager::UpdateDomainUnicastAddress(BackboneRouter::Leader::DomainPrefixState aState)
void DuaManager::HandleDomainPrefixUpdate(BackboneRouter::Leader::DomainPrefixState aState)
{
const Ip6::Prefix *prefix;
const Ip6::Prefix *prefix = nullptr;
if ((aState == BackboneRouter::Leader::kDomainPrefixRemoved) ||
(aState == BackboneRouter::Leader::kDomainPrefixRefreshed))
{
Get<ThreadNetif>().RemoveUnicastAddress(mDomainUnicastAddress);
if (mIsDuaPending)
{
IgnoreError(Get<Coap::Coap>().AbortTransaction(&DuaManager::HandleDuaResponse, this));
}
#if OPENTHREAD_CONFIG_DUA_ENABLE
RemoveDomainUnicastAddress();
#endif
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
if (mChildDuaMask.HasAny())
{
mChildDuaMask.Clear();
mChildDuaRegisteredMask.Clear();
mRegisterCurrentChildIndex = false;
}
#endif
}
VerifyOrExit((aState == BackboneRouter::Leader::kDomainPrefixAdded) ||
(aState == BackboneRouter::Leader::kDomainPrefixRefreshed),
OT_NOOP);
#if OPENTHREAD_CONFIG_DUA_ENABLE
switch (aState)
{
case BackboneRouter::Leader::kDomainPrefixUnchanged:
// In case removed for some reason e.g. the kDuaInvalid response from PBBR forcely
VerifyOrExit(!Get<ThreadNetif>().HasUnicastAddress(GetDomainUnicastAddress()), OT_NOOP);
prefix = Get<BackboneRouter::Leader>().GetDomainPrefix();
OT_ASSERT(prefix != nullptr);
// fall through
case BackboneRouter::Leader::kDomainPrefixRefreshed:
case BackboneRouter::Leader::kDomainPrefixAdded:
prefix = Get<BackboneRouter::Leader>().GetDomainPrefix();
OT_ASSERT(prefix != nullptr);
break;
default:
ExitNow();
}
mDomainUnicastAddress.mPrefixLength = prefix->GetLength();
mDomainUnicastAddress.GetAddress().Clear();
@@ -92,12 +144,14 @@ void DuaManager::UpdateDomainUnicastAddress(BackboneRouter::Leader::DomainPrefix
SuccessOrExit(GenerateDomainUnicastAddressIid());
}
Get<ThreadNetif>().AddUnicastAddress(mDomainUnicastAddress);
AddDomainUnicastAddress();
#endif
exit:
return;
}
#if OPENTHREAD_CONFIG_DUA_ENABLE
otError DuaManager::GenerateDomainUnicastAddressIid(void)
{
otError error;
@@ -133,9 +187,9 @@ otError DuaManager::SetFixedDuaInterfaceIdentifier(const Ip6::InterfaceIdentifie
if (Get<ThreadNetif>().HasUnicastAddress(GetDomainUnicastAddress()))
{
Get<ThreadNetif>().RemoveUnicastAddress(mDomainUnicastAddress);
RemoveDomainUnicastAddress();
mDomainUnicastAddress.GetAddress().SetIid(mFixedDuaInterfaceIdentifier);
Get<ThreadNetif>().AddUnicastAddress(mDomainUnicastAddress);
AddDomainUnicastAddress();
}
exit:
@@ -150,11 +204,11 @@ void DuaManager::ClearFixedDuaInterfaceIdentifier(void)
if (GetDomainUnicastAddress().GetIid() == mFixedDuaInterfaceIdentifier &&
Get<ThreadNetif>().HasUnicastAddress(GetDomainUnicastAddress()))
{
Get<ThreadNetif>().RemoveUnicastAddress(mDomainUnicastAddress);
RemoveDomainUnicastAddress();
if (GenerateDomainUnicastAddressIid() == OT_ERROR_NONE)
{
Get<ThreadNetif>().AddUnicastAddress(mDomainUnicastAddress);
AddDomainUnicastAddress();
}
}
@@ -184,6 +238,500 @@ otError DuaManager::Store(void)
return Get<Settings>().SaveDadInfo(dadInfo);
}
void DuaManager::AddDomainUnicastAddress(void)
{
mDuaState = kToRegister;
mLastRegistrationTime = TimerMilli::GetNow();
Get<ThreadNetif>().AddUnicastAddress(mDomainUnicastAddress);
}
void DuaManager::RemoveDomainUnicastAddress(void)
{
if (mDuaState == kRegistering && mIsDuaPending)
{
IgnoreError(Get<Coap::Coap>().AbortTransaction(&DuaManager::HandleDuaResponse, this));
}
mDuaState = kNotExist;
mDomainUnicastAddress.mPreferred = false;
Get<ThreadNetif>().RemoveUnicastAddress(mDomainUnicastAddress);
}
void DuaManager::UpdateRegistrationDelay(uint8_t aDelay)
{
if (mDelay.mFields.mRegistrationDelay == 0 || mDelay.mFields.mRegistrationDelay > aDelay)
{
mDelay.mFields.mRegistrationDelay = aDelay;
otLogDebgDua("update regdelay %d", mDelay.mFields.mRegistrationDelay);
ScheduleTimer();
}
}
#endif
void DuaManager::UpdateReregistrationDelay(void)
{
uint16_t delay = 0;
otBackboneRouterConfig config;
VerifyOrExit(Get<BackboneRouter::Leader>().GetConfig(config) == OT_ERROR_NONE, OT_NOOP);
delay = config.mReregistrationDelay > 1 ? Random::NonCrypto::GetUint16InRange(1, config.mReregistrationDelay) : 1;
if (mDelay.mFields.mReregistrationDelay == 0 || mDelay.mFields.mReregistrationDelay > delay)
{
mDelay.mFields.mReregistrationDelay = delay;
ScheduleTimer();
otLogDebgDua("update reregdelay %d", mDelay.mFields.mReregistrationDelay);
}
exit:
return;
}
void DuaManager::UpdateCheckDelay(uint8_t aDelay)
{
if (mDelay.mFields.mCheckDelay == 0 || mDelay.mFields.mCheckDelay > aDelay)
{
mDelay.mFields.mCheckDelay = aDelay;
otLogDebgDua("update checkdelay %d", mDelay.mFields.mCheckDelay);
ScheduleTimer();
}
}
void DuaManager::HandleNotifierEvents(Events aEvents)
{
Mle::MleRouter &mle = Get<Mle::MleRouter>();
if (aEvents.Contains(kEventThreadRoleChanged))
{
if (mle.HasRestored())
{
UpdateReregistrationDelay();
}
#if OPENTHREAD_CONFIG_DUA_ENABLE && OPENTHREAD_FTD
else if (mle.IsRouter())
{
// Wait for link establishment with neighboring routers.
UpdateRegistrationDelay(kNewRouterRegistrationDelay);
}
else if (mle.IsExpectedToBecomeRouter())
{
// Will check again in case the device decides to stay REED when jitter timeout expires.
UpdateRegistrationDelay(mle.GetRouterSelectionJitterTimeout() + 1);
}
#endif
}
if (aEvents.ContainsAny(kEventIp6AddressAdded))
{
mRegistrationTask.Post();
}
}
void DuaManager::HandleBackboneRouterPrimaryUpdate(BackboneRouter::Leader::State aState,
const BackboneRouter::BackboneRouterConfig &aConfig)
{
OT_UNUSED_VARIABLE(aConfig);
if (aState == BackboneRouter::Leader::kStateAdded || aState == BackboneRouter::Leader::kStateToTriggerRereg)
{
UpdateReregistrationDelay();
}
}
void DuaManager::HandleTimer(void)
{
bool attempt = false;
otLogDebgDua("regdelay %d, reregdelay %d, checkdelay %d", mDelay.mFields.mRegistrationDelay,
mDelay.mFields.mReregistrationDelay, mDelay.mFields.mCheckDelay);
#if OPENTHREAD_CONFIG_DUA_ENABLE
if (mDuaState != kNotExist && TimerMilli::GetNow() > mLastRegistrationTime + Mle::kDuaDadPeriod)
{
mDomainUnicastAddress.mPreferred = true;
}
if ((mDelay.mFields.mRegistrationDelay > 0) && (--mDelay.mFields.mRegistrationDelay == 0))
{
attempt = true;
}
#endif
if ((mDelay.mFields.mCheckDelay > 0) && (--mDelay.mFields.mCheckDelay == 0))
{
attempt = true;
}
if ((mDelay.mFields.mReregistrationDelay > 0) && (--mDelay.mFields.mReregistrationDelay == 0))
{
#if OPENTHREAD_CONFIG_DUA_ENABLE
if (mDuaState != kNotExist)
{
mDuaState = kToRegister;
}
#endif
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
mChildDuaRegisteredMask.Clear();
#endif
attempt = true;
}
if (attempt)
{
mRegistrationTask.Post();
}
ScheduleTimer();
}
void DuaManager::ScheduleTimer(void)
{
if (mDelay.mValue == 0)
{
mTimer.Stop();
}
else if (!mTimer.IsRunning())
{
mTimer.Start(kStateUpdatePeriod);
}
}
void DuaManager::PerformNextRegistration(void)
{
otError error = OT_ERROR_NONE;
Mle::MleRouter & mle = Get<Mle::MleRouter>();
Coap::Message * message = nullptr;
Ip6::MessageInfo messageInfo;
Ip6::Address dua;
VerifyOrExit(mle.IsAttached(), error = OT_ERROR_INVALID_STATE);
VerifyOrExit(Get<BackboneRouter::Leader>().HasPrimary(), error = OT_ERROR_INVALID_STATE);
// Only allow one outgoing DUA.req
VerifyOrExit(!mIsDuaPending, error = OT_ERROR_BUSY);
// Only send DUA.req when necessary
#if OPENTHREAD_CONFIG_DUA_ENABLE
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
VerifyOrExit(mle.IsRouterOrLeader() || !mle.IsExpectedToBecomeRouter(), error = OT_ERROR_INVALID_STATE);
VerifyOrExit((mDuaState == kToRegister && mDelay.mFields.mRegistrationDelay == 0) ||
(mChildDuaMask.HasAny() && mChildDuaMask != mChildDuaRegisteredMask),
error = OT_ERROR_NOT_FOUND);
#else
VerifyOrExit(mDuaState == kToRegister && mDelay.mFields.mRegistrationDelay == 0, error = OT_ERROR_NOT_FOUND);
#endif // OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
VerifyOrExit(mle.IsFullThreadDevice() || mle.GetParent().IsThreadVersion1p1(), error = OT_ERROR_INVALID_STATE);
#endif // OPENTHREAD_CONFIG_DUA_ENABLE
// Prepare DUA.req
VerifyOrExit((message = Get<Coap::Coap>().NewPriorityMessage()) != nullptr, error = OT_ERROR_NO_BUFS);
SuccessOrExit(error =
message->Init(OT_COAP_TYPE_CONFIRMABLE, OT_COAP_CODE_POST, OT_URI_PATH_DUA_REGISTRATION_REQUEST));
SuccessOrExit(error = message->SetPayloadMarker());
#if OPENTHREAD_CONFIG_DUA_ENABLE
if (mDuaState == kToRegister && mDelay.mFields.mRegistrationDelay == 0)
{
dua = GetDomainUnicastAddress();
SuccessOrExit(error = Tlv::AppendTlv(*message, ThreadTlv::kTarget, &dua, sizeof(dua)));
SuccessOrExit(error = Tlv::AppendTlv(*message, ThreadTlv::kMeshLocalEid, &mle.GetMeshLocal64().GetIid(),
sizeof(Ip6::InterfaceIdentifier)));
mDuaState = kRegistering;
mLastRegistrationTime = TimerMilli::GetNow();
}
else
#endif // OPENTHREAD_CONFIG_DUA_ENABLE
{
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
uint32_t lastTransactionTime;
const Ip6::Address *duaPtr = nullptr;
Child * child = nullptr;
if (!mRegisterCurrentChildIndex)
{
for (Child &iter : Get<ChildTable>().Iterate(Child::kInStateValid))
{
uint16_t childIndex = Get<ChildTable>().GetChildIndex(iter);
if (mChildDuaMask.Get(childIndex) && !mChildDuaRegisteredMask.Get(childIndex))
{
mChildIndexDuaRegistering = childIndex;
break;
}
}
}
child = Get<ChildTable>().GetChildAtIndex(mChildIndexDuaRegistering);
duaPtr = child->GetDomainUnicastAddress();
OT_ASSERT(duaPtr != nullptr);
dua = *duaPtr;
SuccessOrExit(error = Tlv::AppendTlv(*message, ThreadTlv::kTarget, &dua, sizeof(dua)));
SuccessOrExit(error = Tlv::AppendTlv(*message, ThreadTlv::kMeshLocalEid, &child->GetMeshLocalIid(),
sizeof(Ip6::InterfaceIdentifier)));
lastTransactionTime = Time::MsecToSec(TimerMilli::GetNow() - child->GetLastHeard());
SuccessOrExit(error = Tlv::AppendUint32Tlv(*message, ThreadTlv::kLastTransactionTime, lastTransactionTime));
#endif // OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
}
if (!mle.IsFullThreadDevice() && mle.GetParent().IsThreadVersion1p1())
{
uint8_t pbbrServiceId;
SuccessOrExit(error = Get<BackboneRouter::Leader>().GetServiceId(pbbrServiceId));
SuccessOrExit(error = mle.GetServiceAloc(pbbrServiceId, messageInfo.GetPeerAddr()));
}
else
{
messageInfo.GetPeerAddr().SetToRoutingLocator(mle.GetMeshLocalPrefix(),
Get<BackboneRouter::Leader>().GetServer16());
}
messageInfo.SetPeerPort(kCoapUdpPort);
messageInfo.SetSockAddr(Get<Mle::MleRouter>().GetMeshLocal16());
SuccessOrExit(error = Get<Coap::Coap>().SendMessage(*message, messageInfo, &DuaManager::HandleDuaResponse, this));
mIsDuaPending = true;
// TODO: (DUA) need update when CSL is enabled.
if (!Get<Mle::Mle>().IsRxOnWhenIdle())
{
Get<DataPollSender>().SendFastPolls();
}
exit:
if (error == OT_ERROR_NO_BUFS)
{
UpdateCheckDelay(Mle::kNoBufDelay);
}
if (error != OT_ERROR_NONE && message != nullptr)
{
message->Free();
}
otLogInfoDua("Sent DUA.req for DUA %s: %s", dua.ToString().AsCString(), otThreadErrorToString(error));
}
void DuaManager::HandleDuaResponse(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, otError aResult)
{
OT_UNUSED_VARIABLE(aMessageInfo);
otError error;
mIsDuaPending = false;
if (aResult == OT_ERROR_RESPONSE_TIMEOUT)
{
UpdateCheckDelay(Mle::KResponseTimeoutDelay);
ExitNow(error = aResult);
}
VerifyOrExit(aResult == OT_ERROR_NONE && aMessage.GetCode() == OT_COAP_CODE_CHANGED, error = OT_ERROR_PARSE);
error = ProcessDuaResponse(aMessage);
exit:
if (error != OT_ERROR_RESPONSE_TIMEOUT)
{
mRegistrationTask.Post();
}
otLogInfoDua("Received DUA.req: %s", otThreadErrorToString(error));
}
void DuaManager::HandleDuaNotification(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
OT_UNUSED_VARIABLE(aMessageInfo);
otError error;
OT_UNUSED_VARIABLE(error);
VerifyOrExit(aMessage.GetCode() == OT_COAP_CODE_POST, error = OT_ERROR_PARSE);
if (aMessage.IsConfirmable() && Get<Coap::Coap>().SendEmptyAck(aMessage, aMessageInfo) == OT_ERROR_NONE)
{
otLogInfoDua("Sent DUA.ntf acknowledgment");
}
error = ProcessDuaResponse(aMessage);
exit:
otLogInfoDua("Received DUA.ntf: %d", otThreadErrorToString(error));
}
otError DuaManager::ProcessDuaResponse(Coap::Message &aMessage)
{
otError error = OT_ERROR_NONE;
Ip6::Address target;
uint8_t status;
SuccessOrExit(error = Tlv::FindUint8Tlv(aMessage, ThreadTlv::kStatus, status));
SuccessOrExit(error = Tlv::FindTlv(aMessage, ThreadTlv::kTarget, &target, sizeof(target)));
#if OPENTHREAD_CONFIG_DUA_ENABLE
if (Get<ThreadNetif>().HasUnicastAddress(target))
{
switch (static_cast<ThreadStatusTlv::DuaStatus>(status))
{
case ThreadStatusTlv::kDuaSuccess:
mLastRegistrationTime = TimerMilli::GetNow();
mDuaState = kRegistered;
break;
case ThreadStatusTlv::kDuaReRegister:
mDuaState = kToRegister;
mDelay.mFields.mCheckDelay = Mle::kImmediateReRegisterDelay;
break;
case ThreadStatusTlv::kDuaInvalid:
// Domain Prefix might be invalid.
RemoveDomainUnicastAddress();
break;
case ThreadStatusTlv::kDuaDuplicate:
RemoveDomainUnicastAddress();
mDadCounter++;
if (GenerateDomainUnicastAddressIid() == OT_ERROR_NONE)
{
AddDomainUnicastAddress();
}
break;
case ThreadStatusTlv::kDuaNoResources:
case ThreadStatusTlv::kDuaNotPrimary:
case ThreadStatusTlv::kDuaGeneralFailure:
UpdateReregistrationDelay();
break;
}
}
else
#endif
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
{
Child *child = Get<ChildTable>().GetChildAtIndex(mChildIndexDuaRegistering);
VerifyOrExit(child != NULL, error = OT_ERROR_NOT_FOUND);
VerifyOrExit(child->HasIp6Address(target), error = OT_ERROR_NOT_FOUND);
mRegisterCurrentChildIndex = false;
switch (status)
{
case ThreadStatusTlv::kDuaSuccess:
// Mark as Registered
mChildDuaRegisteredMask.Set(mChildIndexDuaRegistering, true);
break;
case ThreadStatusTlv::kDuaReRegister:
mRegisterCurrentChildIndex = true;
mDelay.mFields.mCheckDelay = Mle::kImmediateReRegisterDelay;
break;
case ThreadStatusTlv::kDuaInvalid:
case ThreadStatusTlv::kDuaDuplicate:
SendAddressNotification(target, static_cast<ThreadStatusTlv::DuaStatus>(status), *child);
IgnoreError(child->RemoveIp6Address(target));
mChildDuaMask.Set(mChildIndexDuaRegistering, false);
mChildDuaRegisteredMask.Set(mChildIndexDuaRegistering, false);
break;
case ThreadStatusTlv::kDuaNoResources:
case ThreadStatusTlv::kDuaNotPrimary:
case ThreadStatusTlv::kDuaGeneralFailure:
UpdateReregistrationDelay();
break;
}
}
#endif // OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
exit:
ScheduleTimer();
return error;
}
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
void DuaManager::SendAddressNotification(Ip6::Address & aAddress,
ThreadStatusTlv::DuaStatus aStatus,
const Child & aChild)
{
Coap::Message * message = nullptr;
Ip6::MessageInfo messageInfo;
otError error;
VerifyOrExit((message = Get<Coap::Coap>().NewPriorityMessage()) != nullptr, error = OT_ERROR_NO_BUFS);
SuccessOrExit(error =
message->Init(OT_COAP_TYPE_CONFIRMABLE, OT_COAP_CODE_POST, OT_URI_PATH_DUA_REGISTRATION_NOTIFY));
SuccessOrExit(error = message->SetPayloadMarker());
SuccessOrExit(error = Tlv::AppendUint8Tlv(*message, ThreadTlv::kStatus, static_cast<uint8_t>(aStatus)));
SuccessOrExit(error = Tlv::AppendTlv(*message, ThreadTlv::kTarget, &aAddress, sizeof(aAddress)));
messageInfo.GetPeerAddr().SetToRoutingLocator(Get<Mle::MleRouter>().GetMeshLocalPrefix(), aChild.GetRloc16());
messageInfo.SetPeerPort(kCoapUdpPort);
messageInfo.SetSockAddr(Get<Mle::MleRouter>().GetMeshLocal16());
SuccessOrExit(error = Get<Coap::Coap>().SendMessage(*message, messageInfo));
otLogInfoDua("Sent ADDR_NTF for child %04x DUA %s", aChild.GetRloc16(), aAddress.ToString().AsCString());
exit:
if (error != OT_ERROR_NONE)
{
// TODO: (DUA) (P4) may enhance to guarantee the delivery of DUA.ntf
otLogWarnDua("Sent ADDR_NTF for child %04x DUA %s Error %s", aChild.GetRloc16(),
aAddress.ToString().AsCString(), otThreadErrorToString(error));
if (message != NULL)
{
message->Free();
}
}
}
void DuaManager::UpdateChildDomainUnicastAddress(const Child &aChild, Mle::ChildDuaState aState)
{
uint16_t childIndex = Get<ChildTable>().GetChildIndex(aChild);
if ((aState == Mle::ChildDuaState::kRemoved || aState == Mle::ChildDuaState::kChanged) &&
mChildDuaMask.Get(childIndex))
{
// Abort on going proxy DUA.req for this child
#if OPENTHREAD_CONFIG_DUA_ENABLE
if (mIsDuaPending && mDuaState != DuaState::kRegistering && mChildIndexDuaRegistering == childIndex)
#else
if (mIsDuaPending && mChildIndexDuaRegistering == childIndex)
#endif
{
IgnoreError(Get<Coap::Coap>().AbortTransaction(&DuaManager::HandleDuaResponse, this));
// Reset mRegisterCurrentChildIndex properly
mRegisterCurrentChildIndex = mRegisterCurrentChildIndex && (aState == Mle::ChildDuaState::kRemoved);
}
mChildDuaMask.Set(childIndex, false);
mChildDuaRegisteredMask.Set(childIndex, false);
}
if (aState == Mle::ChildDuaState::kAdded || aState == Mle::ChildDuaState::kChanged)
{
if (mChildDuaMask == mChildDuaRegisteredMask)
{
UpdateCheckDelay(Random::NonCrypto::GetUint8InRange(1, Mle::kParentAggregateDelay));
}
mChildDuaMask.Set(childIndex, true);
mChildDuaRegisteredMask.Set(childIndex, false);
}
return;
}
#endif // OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
} // namespace ot
#endif // (OPENTHREAD_FTD || OPENTHREAD_MTD) && OPENTHREAD_CONFIG_DUA_ENABLE
#endif // OPENTHREAD_CONFIG_DUA_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
+127 -6
View File
@@ -36,11 +36,19 @@
#include "openthread-core-config.h"
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
#if OPENTHREAD_CONFIG_DUA_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
#include "backbone_router/bbr_leader.hpp"
#include "coap/coap.hpp"
#include "coap/coap_message.hpp"
#include "common/locator.hpp"
#include "common/notifier.hpp"
#include "common/tasklet.hpp"
#include "common/time.hpp"
#include "common/timer.hpp"
#include "net/netif.hpp"
#include "thread/thread_tlvs.hpp"
#include "thread/topology.hpp"
namespace ot {
@@ -62,7 +70,7 @@ namespace ot {
* This class implements managing DUA.
*
*/
class DuaManager : public InstanceLocator
class DuaManager : public InstanceLocator, public Notifier::Receiver
{
public:
/**
@@ -74,12 +82,24 @@ public:
explicit DuaManager(Instance &aInstance);
/**
* This method updates Domain Unicast Address.
* This method notifies Domain Prefix status.
*
* @param[in] aState The Domain Prefix state or state change.
*
*/
void UpdateDomainUnicastAddress(BackboneRouter::Leader::DomainPrefixState aState);
void HandleDomainPrefixUpdate(BackboneRouter::Leader::DomainPrefixState aState);
/**
* This method notifies Primary Backbone Router status.
*
* @param[in] aState The state or state change of Primary Backbone Router.
* @param[in] aConfig The Primary Backbone Router service.
*
*/
void HandleBackboneRouterPrimaryUpdate(BackboneRouter::Leader::State aState,
const BackboneRouter::BackboneRouterConfig &aConfig);
#if OPENTHREAD_CONFIG_DUA_ENABLE
/**
* This method returns a reference to the Domain Unicast Address.
@@ -129,17 +149,118 @@ public:
*
*/
void Restore(void);
#endif
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
void UpdateChildDomainUnicastAddress(const Child &aChild, Mle::ChildDuaState aState);
#endif
private:
enum
{
kNewRouterRegistrationDelay = 5, ///< Delay (in seconds) for waiting link establishment for a new Router.
kStateUpdatePeriod = 1000, ///< 1000ms period (i.e. 1s)
};
#if OPENTHREAD_CONFIG_DUA_ENABLE
otError GenerateDomainUnicastAddressIid(void);
otError Store(void);
void AddDomainUnicastAddress(void);
void RemoveDomainUnicastAddress(void);
void UpdateRegistrationDelay(uint8_t aDelay);
#endif
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
void SendAddressNotification(Ip6::Address &aAddress, ThreadStatusTlv::DuaStatus aStatus, const Child &aChild);
#endif
static void HandleNotifierEvents(Notifier::Receiver &aReceiver, Events aEvents)
{
static_cast<DuaManager &>(aReceiver).HandleNotifierEvents(aEvents);
}
void HandleNotifierEvents(Events aEvents);
static void HandleTimer(Timer &aTimer) { aTimer.GetOwner<DuaManager>().HandleTimer(); }
void HandleTimer(void);
static void HandleRegistrationTask(Tasklet &aTasklet) { aTasklet.GetOwner<DuaManager>().PerformNextRegistration(); }
void ScheduleTimer(void);
static void HandleDuaResponse(void * aContext,
otMessage * aMessage,
const otMessageInfo *aMessageInfo,
otError aResult)
{
static_cast<DuaManager *>(aContext)->HandleDuaResponse(
*static_cast<Coap::Message *>(aMessage), *static_cast<const Ip6::MessageInfo *>(aMessageInfo), aResult);
}
void HandleDuaResponse(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, otError aResult);
static void HandleDuaNotification(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
{
static_cast<DuaManager *>(aContext)->HandleDuaNotification(
*static_cast<Coap::Message *>(aMessage), *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
}
void HandleDuaNotification(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
otError ProcessDuaResponse(Coap::Message &aMessage);
void PerformNextRegistration(void);
void UpdateReregistrationDelay(void);
void UpdateCheckDelay(uint8_t aDelay);
TimerMilli mTimer;
Tasklet mRegistrationTask;
Coap::Resource mDuaNotification;
bool mIsDuaPending : 1;
#if OPENTHREAD_CONFIG_DUA_ENABLE
enum DuaState
{
kNotExist, ///< DUA is not avaiable.
kToRegister, ///< DUA is to be registered.
kRegistering, ///< DUA is being registered.
kRegistered, ///< DUA is registered.
};
DuaState mDuaState : 2;
uint8_t mDadCounter;
TimeMilli mLastRegistrationTime; ///< The time (in milliseconds) when sent last DUA.req or received DUA.rsp.
Ip6::InterfaceIdentifier mFixedDuaInterfaceIdentifier;
Ip6::NetifUnicastAddress mDomainUnicastAddress;
uint8_t mDadCounter;
#endif
union
{
struct
{
uint16_t mReregistrationDelay; ///< Delay (in seconds) for DUA re-registration.
uint8_t mCheckDelay; ///< Delay (in seconds) for checking whether or not registration is required.
#if OPENTHREAD_CONFIG_DUA_ENABLE
uint8_t mRegistrationDelay; ///< Delay (in seconds) for DUA registration.
#endif
} mFields;
uint32_t mValue; ///< Non-zero indicates timer should start.
} mDelay;
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
// TODO: (DUA) may re-evaluate the alternative option of distributing the flags into the child table:
// - Child class itself have some padding - may save some RAM
// - Avoid cross reference between a bit-vector and the child entry
ChildMask mChildDuaMask; ///< Child Mask for child who registers DUA via Child Update Request.
ChildMask mChildDuaRegisteredMask; ///< Child Mask for child's DUA that was registered by the parent on behalf.
uint16_t mChildIndexDuaRegistering : 15; ///< Child Index of the DUA being registered.
bool mRegisterCurrentChildIndex : 1; ///< Re-register the child just registered.
#endif
};
} // namespace ot
#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
#endif // OPENTHREAD_CONFIG_DUA_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
#endif // DUA_MANAGER_HPP_
+41
View File
@@ -2039,6 +2039,11 @@ otError MleRouter::UpdateChildAddresses(const Message &aMessage, uint16_t aOffse
uint8_t storedCount = 0;
uint16_t offset = 0;
uint16_t end = 0;
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
Ip6::Address oldDua;
const Ip6::Address *oldDuaPtr = nullptr;
bool hasDua = false;
#endif
#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
Ip6::Address oldMlrRegisteredAddresses[OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD - 1];
@@ -2051,6 +2056,13 @@ otError MleRouter::UpdateChildAddresses(const Message &aMessage, uint16_t aOffse
offset = aOffset + sizeof(tlv);
end = offset + tlv.GetLength();
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
if ((oldDuaPtr = aChild.GetDomainUnicastAddress()) != nullptr)
{
oldDua = *oldDuaPtr;
}
#endif
#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
// Retrieve registered multicast addresses of the Child
if (aChild.HasAnyMlrRegisteredAddress())
@@ -2096,6 +2108,25 @@ otError MleRouter::UpdateChildAddresses(const Message &aMessage, uint16_t aOffse
address.Clear();
address.SetPrefix(context.mPrefix);
address.SetIid(entry.GetIid());
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
if (Get<BackboneRouter::Leader>().IsDomainUnicast(address))
{
hasDua = true;
if (oldDuaPtr != nullptr)
{
if (oldDua != address)
{
Get<DuaManager>().UpdateChildDomainUnicastAddress(aChild, ChildDuaState::kChanged);
}
}
else
{
Get<DuaManager>().UpdateChildDomainUnicastAddress(aChild, ChildDuaState::kAdded);
}
}
#endif
}
else
{
@@ -2157,6 +2188,13 @@ otError MleRouter::UpdateChildAddresses(const Message &aMessage, uint16_t aOffse
// Clear EID-to-RLOC cache for the unicast address registered by the child.
Get<AddressResolver>().Remove(address);
}
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
// Dua is removed
if (oldDuaPtr != nullptr && !hasDua)
{
Get<DuaManager>().UpdateChildDomainUnicastAddress(aChild, ChildDuaState::kRemoved);
}
#endif
#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
Get<MlrManager>().UpdateProxiedSubscriptions(aChild, oldMlrRegisteredAddresses, oldMlrRegisteredAddressNum);
@@ -4771,6 +4809,9 @@ void MleRouter::Signal(otNeighborTableEvent aEvent, Neighbor &aNeighbor)
case OT_NEIGHBOR_TABLE_EVENT_CHILD_REMOVED:
Get<Notifier>().Signal(kEventThreadChildRemoved);
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
Get<DuaManager>().UpdateChildDomainUnicastAddress(static_cast<Child &>(aNeighbor), ChildDuaState::kRemoved);
#endif
break;
default:
+21 -5
View File
@@ -257,11 +257,16 @@ enum
*/
enum
{
kRegistrationDelayDefault = 1200, //< In seconds.
kMlrTimeoutDefault = 3600, //< In seconds.
kMlrTimeoutMin = 300, //< In seconds.
kBackboneRouterRegistrationJitter = 5, //< In seconds.
kParentAggregateDelay = 5, //< In seconds.
kRegistrationDelayDefault = 1200, ///< In seconds.
kMlrTimeoutDefault = 3600, ///< In seconds.
kMlrTimeoutMin = 300, ///< In seconds.
kBackboneRouterRegistrationJitter = 5, ///< In seconds.
kParentAggregateDelay = 5, ///< In seconds.
kNoBufDelay = 5, ///< In seconds.
kImmediateReRegisterDelay = 1, ///< In seconds.
KResponseTimeoutDelay = 30, ///< In seconds.
kDuaDadPeriod = 100, ///< In seconds. Time period after which the address
///< becomes "Preferred" if no duplicate address error.
};
static_assert(kMlrTimeoutDefault >= kMlrTimeoutMin,
@@ -269,6 +274,17 @@ static_assert(kMlrTimeoutDefault >= kMlrTimeoutMin,
static_assert(Mle::kParentAggregateDelay > 1, "kParentAggregateDelay should be larger than 1 second");
/**
* State change of Child's DUA
*
*/
enum class ChildDuaState : uint8_t
{
kAdded, ///< A new DUA registered by the Child via Address Registration.
kChanged, ///< A different DUA registered by the Child via Address Registration.
kRemoved, ///< DUA registered by the Child is removed and not in Address Registration.
};
#endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
/**
+4 -3
View File
@@ -111,12 +111,13 @@ ThreadNetif::ThreadNetif(Instance &aInstance)
, mBackboneRouterLocal(aInstance)
, mBackboneRouterManager(aInstance)
#endif
#if OPENTHREAD_CONFIG_DUA_ENABLE
, mDuaManager(aInstance)
#endif
#if OPENTHREAD_CONFIG_MLR_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
, mMlrManager(aInstance)
#endif
#if OPENTHREAD_CONFIG_DUA_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
, mDuaManager(aInstance)
#endif
, mChildSupervisor(aInstance)
, mSupervisionListener(aInstance)
, mAnnounceBegin(aInstance)
+7 -7
View File
@@ -55,14 +55,14 @@
#include "backbone_router/bbr_manager.hpp"
#endif
#if OPENTHREAD_CONFIG_DUA_ENABLE
#include "thread/dua_manager.hpp"
#endif
#if OPENTHREAD_CONFIG_MLR_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
#include "thread/mlr_manager.hpp"
#endif
#if OPENTHREAD_CONFIG_DUA_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
#include "thread/dua_manager.hpp"
#endif
#include "meshcop/dataset_manager.hpp"
#if OPENTHREAD_CONFIG_JOINER_ENABLE
@@ -261,11 +261,11 @@ private:
BackboneRouter::Local mBackboneRouterLocal;
BackboneRouter::Manager mBackboneRouterManager;
#endif
#if OPENTHREAD_CONFIG_DUA_ENABLE
DuaManager mDuaManager;
#endif
#if OPENTHREAD_CONFIG_MLR_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
MlrManager mMlrManager;
#endif
#if OPENTHREAD_CONFIG_DUA_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
DuaManager mDuaManager;
#endif
Utils::ChildSupervisor mChildSupervisor;
Utils::SupervisionListener mSupervisionListener;
+15
View File
@@ -135,6 +135,21 @@ public:
kMlrBbrNotPrimary = 5, ///< BBR is not Primary at this moment.
kMlrGeneralFailure = 6, ///< Reason(s) for failure are not further specified.
};
/**
* Domain Unicast Address (DUA) Registration Status values
*
*/
enum DuaStatus : uint8_t
{
kDuaSuccess = 0, ///< Successful registration.
kDuaReRegister = 1, ///< Registration was accepted but immediate reregistration is required to solve.
kDuaInvalid = 2, ///< Registration rejected (Fatal): Target EID is not a valid DUA.
kDuaDuplicate = 3, ///< Registration rejected (Fatal): DUA is already in use by another device.
kDuaNoResources = 4, ///< Registration rejected (Non-fatal): Backbone Router Resource shortage.
kDuaNotPrimary = 5, ///< Registration rejected (Non-fatal): Backbone Router is not primary at this moment.
kDuaGeneralFailure = 6, ///< Registration failure (Non-fatal): Reason(s) not futher specified.
};
};
/**
+33
View File
@@ -300,6 +300,39 @@ namespace ot {
*/
#define OT_URI_PATH_MLR "n/mr"
/**
* @def OT_URI_PATH_DUA_REGISTRATION_REQUEST
*
* The URI Path for Domain Unicast Address Registration Request (DUA.req).
*
*/
#define OT_URI_PATH_DUA_REGISTRATION_REQUEST "n/dr"
/**
* @def OT_URI_PATH_DUA_REGISTRATION_NOTIFY
*
* The URI Path for Domain Unicast Address Registration Notification (DUA.ntf).
*
*/
#define OT_URI_PATH_DUA_REGISTRATION_NOTIFY "n/dn"
/**
* @def OT_URI_PATH_BACKBONE_QUERY
*
* The URI Path for Backbone Query (BB.qry).
*
*/
#define OT_URI_PATH_BACKBONE_QUERY "b/bq"
/**
* @def OT_URI_PATH_BACKBONE_ANSWER
*
* The URI Path for Backbone Answer with destination to a link-local unicast address (BB.ans),
* or Proactive Backbone Notification with destination to a link-local multicast address (PRO_BB.ntf).
*
*/
#define OT_URI_PATH_BACKBONE_ANSWER "b/ba"
} // namespace ot
#endif // THREAD_URIS_HPP_
+20
View File
@@ -273,6 +273,26 @@ exit:
return retval;
}
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
const Ip6::Address *Child::GetDomainUnicastAddress(void) const
{
const Ip6::Address *addr = nullptr;
for (const Ip6::Address &ip6Address : mIp6Address)
{
VerifyOrExit(!ip6Address.IsUnspecified(), OT_NOOP);
if (Get<BackboneRouter::Leader>().IsDomainUnicast(ip6Address))
{
ExitNow(addr = &ip6Address);
}
}
exit:
return addr;
}
#endif
void Child::GenerateChallenge(void)
{
IgnoreError(Random::Crypto::FillBuffer(mAttachChallenge, sizeof(mAttachChallenge)));
+10
View File
@@ -759,6 +759,16 @@ public:
*/
bool HasIp6Address(const Ip6::Address &aAddress) const;
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
/**
* This method retrieves the Domain Unicast Address registered by the child.
*
* @returns A pointer to Domain Unicast Address registered by the child if there is.
*
*/
const Ip6::Address *GetDomainUnicastAddress(void) const;
#endif
/**
* This method gets the child timeout.
*
+2
View File
@@ -491,6 +491,8 @@ def create_default_uri_path_based_payload_factories():
'/d/dq': network_diag_tlvs_factory,
'/d/dr': network_diag_tlvs_factory,
'/n/mr': network_layer_tlvs_factory,
'/n/dr': network_layer_tlvs_factory,
'/n/dn': network_layer_tlvs_factory,
}
+12
View File
@@ -522,6 +522,13 @@ class Node:
self.remove_prefix(prefix)
self.register_netdata()
def set_next_dua_response(self, status, iid=None):
cmd = 'bbr mgmt dua {}'.format(status)
if iid is not None:
cmd += ' ' + str(iid)
self.send_command(cmd)
self._expect('Done')
def set_dua_iid(self, iid):
cmd = 'dua iid {}'.format(iid)
self.send_command(cmd)
@@ -1481,6 +1488,11 @@ class Node:
def udp_check_rx(self, bytes_should_rx):
self._expect('%d bytes' % bytes_should_rx)
def set_routereligible(self, enable: bool):
cmd = f'routereligible {"enable" if enable else "disable"}'
self.send_command(cmd)
self._expect('Done')
def router_list(self):
cmd = 'router list'
self.send_command(cmd)
@@ -136,7 +136,7 @@ class TestDomainUnicastAddress(thread_cert.TestCase):
return ''.join(ipaddress.ip_address(address).exploded.split(':')[4:])
def __check_dua_registration(self, node, iid, dp_cid):
''' Check whether or not the specified domain unicast address is registered in Address
''' Check whether or not the specified Domain Unicast Address is registered in Address
Registraion TLV.
Args:
@@ -311,6 +311,7 @@ class TestDomainUnicastAddress(thread_cert.TestCase):
self.simulator.go(WAIT_TIME)
WAIT_TIME = MED_TIMEOUT
self.simulator.go(WAIT_TIME)
dua = self.nodes[MED_1_2].get_addr(config.DOMAIN_PREFIX)
assert dua, 'Error: Expected DUA not found'
assert ipaddress.ip_address(med_1_2_dua) == ipaddress.ip_address(
@@ -0,0 +1,379 @@
#!/usr/bin/env python3
#
# Copyright (c) 2020, 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.
#
import unittest
import command
import config
import ipaddress
import mle
import thread_cert
BBR_1 = 1 # Collapsed with Leader Role
ROUTER_1_1 = 2
ROUTER_1_2 = 3
FED_1_2_1 = 4
MED_1_2_1 = 5
SED_1_2_1 = 6
FED_1_2_2 = 7
MED_1_2_2 = 8
SED_1_2_2 = 9
WAIT_ATTACH = 5
WAIT_REDUNDANCE = 3
ROUTER_SELECTION_JITTER = 1
BBR_REGISTRATION_JITTER = 5
SED_POLL_PERIOD = 2000 # 2s
MED_TIMEOUT = 20 # 20s
PARENT_AGGREGATE_DELAY = 5 # 5s
DUA_IID_MANUAL1 = '4444333322221111'
ST_DUA_SUCCESS = 0
ST_DUA_REREGISTER = 1
ST_DUA_INVALID = 2
ST_DUA_DUPLICATE = 3
ST_DUA_NO_RESOURCES = 4
ST_DUA_BBR_NOT_PRIMARY = 5
ST_DUA_GENERAL_FAILURE = 6
BBR_REREGISTRATION_DELAY = 10
"""
Topology
MED_1_2_1 SED_1_2_1
\ |
\ |
FED_1_2_1 --- ROUTER_1_1 FED_1_2_2 MED_1_2_2
| | /
| | /
BBR_1 (LEADER) --- ROUTER_1_2 --- SED_1_2_2
1) Bring up BBR_1, BBR_1 becomes Leader and Primary Backbone Router, with Domain
Prefix without `P_slaac`.
2) Test behaviors of ROUTER_1_2 under various response status:
a) Bring up ROUTER_1_2 with DUA_IID_MANUAL1, one DUA.req should happen to register DUA.
b) Remove DUA_IID_MANUAL1, one DUA.req should happen for the new generated DUA via SLAAC.
c) Configure BBR_1 to respond with the fatal error ST_DUA_INVALID, update BBR_1 with
BBR_REREGISTRATION_DELAY, ROUTER_1_2 should re-register its DUA within BBR_REREGISTRATION_DELAY.
- ROUTER_1_2 should remove its dua
- update network data, ROUTER_1_2 would regenerate and register the same dua
d) Configure BBR_1 to respond with the fatal error ST_DUA_DUPLICATE, update seqno to trigger reregistration.
After received DUA.rsp with ST_DUA_DUPLICATE, ROUTER_1_2 should
- increase dad counter
- regenerate a new DUA
- send DUA.req
e) (repeated) Configure BBR_1 to respond with per remaining error status:
- increase BBR seqno to trigger reregistration
- ROUTER_1_2 should re-register within BBR_REREGISTRATION_DELAY. For the not fatal errors, ROUTER_1_2
should re-register within another BBR_REREGISTRATION_DELAY (with least delay if ST_DUA_REREGISTER)
3) Bring up FED_1_2_1, MED_1_2_1, SED_1_2_1, they should send DUA.req by themselves as the parent
is of Thread 1.1 version.
4) Bring up FED_1_2_2, it sends DUA.req itself as it it FTD.
5) MED_1_2_2, SED_1_2_2, MTDs should should register their DUA to their parent
by Child Update Request, and the parent would send DUA.req for them on behalf.
6) Increase seqno on BBR_1, within BBR_REREGISTRATION_DELAY, there should be one DUA.req from
per [FED_1_2_1, MED_1_2_1, SED_1_2_1, FED_1_2_2], and 3 DUA.req from ROUTER_1_2 among which
2 DUA.req are for its MTD children.
"""
class TestDomainUnicastAddressRegistration(thread_cert.TestCase):
TOPOLOGY = {
BBR_1: {
'version': '1.2',
'whitelist': [ROUTER_1_1, ROUTER_1_2],
'is_bbr': True
},
ROUTER_1_1: {
'version': '1.1',
'whitelist': [BBR_1, FED_1_2_1, MED_1_2_1, SED_1_2_1]
},
ROUTER_1_2: {
'version': '1.2',
'whitelist': [BBR_1, FED_1_2_2, MED_1_2_2, SED_1_2_2]
},
FED_1_2_1: {
'version': '1.2',
'whitelist': [ROUTER_1_1],
},
MED_1_2_1: {
'mode': 'rsn',
'version': '1.2',
'whitelist': [ROUTER_1_1],
},
SED_1_2_1: {
'mode': 'sn',
'version': '1.2',
'whitelist': [ROUTER_1_1],
},
FED_1_2_2: {
'version': '1.2',
'whitelist': [ROUTER_1_2],
},
MED_1_2_2: {
'mode': 'rsn',
'version': '1.2',
'whitelist': [ROUTER_1_2],
},
SED_1_2_2: {
'mode': 'sn',
'version': '1.2',
'whitelist': [ROUTER_1_2],
},
}
"""All nodes are created with default configurations"""
def __get_iid(self, address):
''' Get the interface identifier of an IPv6 address.
Args:
address (string): An IPv6 address;
'''
return ''.join(ipaddress.ip_address(address).exploded.split(':')[4:])
def __check_dua_registration_tmf(self, node, occurences=1):
messages = self.simulator.get_messages_sent_by(node)
for i in range(occurences):
msg = messages.next_coap_message('0.02', '/n/dr', False)
assert msg, 'Expected {}, but {}th not found\n node: {}(extaddr: {})'.format(
occurences, i + 1, node, self.nodes[node].get_addr64())
def test(self):
# starting context id
context_id = 1
seq_num = 1
# 1) Bring up BBR_1, BBR_1 becomes Leader and Primary Backbone Router, with Domain
# Prefix without `P_slaac`.
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_backbone_router(
seqno=seq_num, reg_delay=BBR_REREGISTRATION_DELAY)
self.nodes[BBR_1].start()
WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER
self.simulator.go(WAIT_TIME)
self.assertEqual(self.nodes[BBR_1].get_state(), 'leader')
self.nodes[BBR_1].enable_backbone_router()
WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE
self.simulator.go(WAIT_TIME)
self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(),
'Primary')
assert self.nodes[BBR_1].has_ipmaddr(config.ALL_NETWORK_BBRS_ADDRESS)
assert not self.nodes[BBR_1].has_ipmaddr(config.ALL_DOMAIN_BBRS_ADDRESS)
self.nodes[BBR_1].set_domain_prefix(config.DOMAIN_PREFIX, 'prosD')
WAIT_TIME = WAIT_REDUNDANCE
self.simulator.go(WAIT_TIME)
assert self.nodes[BBR_1].has_ipmaddr(config.ALL_DOMAIN_BBRS_ADDRESS)
self.simulator.set_lowpan_context(context_id, config.DOMAIN_PREFIX)
domain_prefix_cid = context_id
# 2) Test behaviors of ROUTER_1_2 under various response status:
# a) Bring up ROUTER_1_2 with DUA_IID_MANUAL1, one DUA.req should happen to register DUA.
# Flush relative message queues.
self.flush_nodes([ROUTER_1_2])
self.nodes[ROUTER_1_2].set_dua_iid(DUA_IID_MANUAL1)
self.nodes[ROUTER_1_2].set_router_selection_jitter(
ROUTER_SELECTION_JITTER)
self.nodes[ROUTER_1_2].start()
WAIT_TIME = WAIT_ATTACH
self.simulator.go(WAIT_TIME)
self.assertEqual(self.nodes[ROUTER_1_2].get_state(), 'router')
mliid = self.__get_iid(self.nodes[ROUTER_1_2].get_mleid())
WAIT_TIME = WAIT_ATTACH + WAIT_REDUNDANCE
self.simulator.go(WAIT_TIME)
self.__check_dua_registration_tmf(ROUTER_1_2)
# b) Remove DUA_IID_MANUAL1, one DUA.req should happen for the new generated DUA via SLAAC.
# Flush relative message queues.
self.flush_nodes([ROUTER_1_2])
self.nodes[ROUTER_1_2].clear_dua_iid()
WAIT_TIME = WAIT_ATTACH + WAIT_REDUNDANCE
self.simulator.go(WAIT_TIME)
self.__check_dua_registration_tmf(ROUTER_1_2)
#c) Configure BBR_1 to respond with the fatal error ST_DUA_INVALID, update BBR_1 with
# BBR_REREGISTRATION_DELAY, ROUTER_1_2 should re-register its DUA within BBR_REREGISTRATION_DELAY.
# - ROUTER_1_2 should remove its dua
# - update network data, ROUTER_1_2 would regenerate and register the same dua
# Flush relative message queues.
self.flush_nodes([ROUTER_1_2])
seq_num = seq_num + 1
self.nodes[BBR_1].set_next_dua_response(ST_DUA_INVALID, mliid)
self.nodes[BBR_1].set_backbone_router(seqno=seq_num)
WAIT_TIME = BBR_REREGISTRATION_DELAY + WAIT_REDUNDANCE
self.simulator.go(WAIT_TIME)
self.__check_dua_registration_tmf(ROUTER_1_2, 1)
dua = self.nodes[ROUTER_1_2].get_addr(config.DOMAIN_PREFIX)
assert not dua, 'Error: Unexpected DUA ({}) found'.format(dua)
# Retry after new network data is available
seq_num = seq_num + 1
dua = self.nodes[ROUTER_1_2].get_addr(config.DOMAIN_PREFIX)
self.nodes[BBR_1].set_backbone_router(seqno=seq_num)
WAIT_TIME = BBR_REREGISTRATION_DELAY + WAIT_REDUNDANCE
self.simulator.go(WAIT_TIME)
self.__check_dua_registration_tmf(ROUTER_1_2, 1)
dua = self.nodes[ROUTER_1_2].get_addr(config.DOMAIN_PREFIX)
assert dua, 'Error: Expected DUA ({}) not found'.format(dua)
#d) Configure BBR_1 to respond with the fatal error ST_DUA_DUPLICATE, update seqno to trigger reregistration.
# After received DUA.rsp with ST_DUA_DUPLICATE, ROUTER_1_2 should
# - increase dad counter
# - regenerate a new DUA
# - send DUA.req
# Flush relative message queues.
self.flush_nodes([ROUTER_1_2])
seq_num = seq_num + 1
self.nodes[BBR_1].set_next_dua_response(ST_DUA_DUPLICATE, mliid)
self.nodes[BBR_1].set_backbone_router(seqno=seq_num)
WAIT_TIME = BBR_REREGISTRATION_DELAY * 2 + WAIT_REDUNDANCE
self.simulator.go(WAIT_TIME)
self.__check_dua_registration_tmf(ROUTER_1_2, 2)
dua2 = self.nodes[ROUTER_1_2].get_addr(config.DOMAIN_PREFIX)
assert dua2, 'Error: Expected DUA ({}) not found'.format(dua2)
assert dua2 != dua, 'Error: Expected Different DUA not found, same DUA {}'.format(
dua2)
# e) (repeated) Configure BBR_1 to respond with per remaining error status:
# - increase BBR seqno to trigger reregistration
# - ROUTER_1_2 should re-register within BBR_REREGISTRATION_DELAY. For the not fatal errors, ROUTER_1_2
# should re-register within another BBR_REREGISTRATION_DELAY (with least delay if ST_DUA_REREGISTER)
for status in [
ST_DUA_REREGISTER, ST_DUA_NO_RESOURCES, ST_DUA_BBR_NOT_PRIMARY,
ST_DUA_GENERAL_FAILURE
]:
print('Testing Status %d...'.format(status))
# Flush relative message queues.
self.flush_nodes([ROUTER_1_2])
seq_num = seq_num + 1
self.nodes[BBR_1].set_next_dua_response(status, mliid)
self.nodes[BBR_1].set_backbone_router(seqno=seq_num)
WAIT_TIME = BBR_REREGISTRATION_DELAY + WAIT_REDUNDANCE
if status != ST_DUA_REREGISTER:
WAIT_TIME += BBR_REREGISTRATION_DELAY
self.simulator.go(WAIT_TIME)
self.__check_dua_registration_tmf(ROUTER_1_2, 2)
# Bring up Router_1_1
self.nodes[ROUTER_1_1].set_router_selection_jitter(
ROUTER_SELECTION_JITTER)
self.nodes[ROUTER_1_1].start()
WAIT_TIME = WAIT_ATTACH
self.simulator.go(WAIT_TIME)
self.assertEqual(self.nodes[ROUTER_1_1].get_state(), 'router')
dua = self.nodes[ROUTER_1_1].get_addr(config.DOMAIN_PREFIX)
assert not dua, 'Error: Unexpected DUA ({}) found'.format(dua)
# Configure children
for node in [FED_1_2_1, FED_1_2_2]:
self.nodes[node].set_routereligible(False)
for node in [SED_1_2_1, SED_1_2_2]:
self.nodes[node].set_pollperiod(SED_POLL_PERIOD)
for node in [MED_1_2_1, MED_1_2_2]:
self.nodes[node].set_timeout(MED_TIMEOUT)
# 3) Bring up FED_1_2_1, MED_1_2_1, SED_1_2_1, they should send DUA.req by themselves as the parent
# is of Thread 1.1 version.
# 4) Bring up FED_1_2_2, it sends DUA.req itself as it it FTD.
for node in [FED_1_2_1, MED_1_2_1, SED_1_2_1, FED_1_2_2]:
print("Starting child {} (extaddr: {})...".format(
node, self.nodes[node].get_addr64()))
# Flush all message queues.
self.flush_all()
self.nodes[node].start()
WAIT_TIME = WAIT_ATTACH
self.simulator.go(WAIT_TIME)
self.assertEqual(self.nodes[node].get_state(), 'child')
WAIT_TIME = PARENT_AGGREGATE_DELAY + WAIT_REDUNDANCE
self.simulator.go(WAIT_TIME)
self.__check_dua_registration_tmf(node)
# 5) MED_1_2_2, SED_1_2_2, MTDs should should register their DUA to their parent
# by Child Update Request, and the parent would send DUA.req for them on behalf.
for node in [MED_1_2_2, SED_1_2_2]:
print("Starting child {} (extaddr: {})...".format(
node, self.nodes[node].get_addr64()))
# Flush all message queues.
self.flush_all()
self.nodes[node].start()
WAIT_TIME = WAIT_ATTACH
self.simulator.go(WAIT_TIME)
self.assertEqual(self.nodes[node].get_state(), 'child')
WAIT_TIME = PARENT_AGGREGATE_DELAY + WAIT_REDUNDANCE
print("waiting {}".format(WAIT_TIME))
self.simulator.go(WAIT_TIME)
self.__check_dua_registration_tmf(ROUTER_1_2, 1)
# 6) Increase seqno on BBR_1, within BBR_REREGISTRATION_DELAY, there should be one DUA.req from
# per [FED_1_2_1, MED_1_2_1, SED_1_2_1, FED_1_2_2], and 3 DUA.req from ROUTER_1_2 among which
# 2 DUA.req are for its MTD children.
# Flush all message queues.
self.flush_all()
seq_num = seq_num + 1
self.nodes[BBR_1].set_backbone_router(seqno=seq_num)
WAIT_TIME = BBR_REREGISTRATION_DELAY + WAIT_REDUNDANCE
self.simulator.go(WAIT_TIME)
WAIT_TIME = BBR_REREGISTRATION_DELAY + WAIT_REDUNDANCE
self.simulator.go(WAIT_TIME)
for node in [FED_1_2_1, MED_1_2_1, SED_1_2_1, FED_1_2_2]:
self.__check_dua_registration_tmf(node)
self.__check_dua_registration_tmf(ROUTER_1_2, 3)
if __name__ == '__main__':
unittest.main()