mirror of
https://github.com/espressif/openthread.git
synced 2026-06-06 05:24:51 +00:00
[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:
@@ -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);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
@@ -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
@@ -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")
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
/**
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
+379
@@ -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()
|
||||
Reference in New Issue
Block a user