mirror of
https://github.com/espressif/openthread.git
synced 2026-08-08 11:47:46 +00:00
[child-supervision] mechanism to inform interval from child to parent (#7993)
This commit contains changes to child supervision feature. It adds a new mechanism for a child to inform its desired supervision interval to its parent. A new optional MLE TLV is added with type 27 and value of `uint16_t` indicating the supervision interval in seconds. This TLV is included in MLE Child ID Request and MLE Child Update Request (sent from the child). The parent echoes back this TLV in the corresponding responses to indicate that it supports supervision. This commit changes the parent implementation to track the supervision interval per child. This commit also updates the OT public APIs along with the related CLI commands: - API now allows the supervision interval to be set on a child. - New field in `otChildInfo` to indicate the child's supervision interval. - New counter is added to track the number of supervision check timeouts failures on a child (intended for testing and debugging). This commit adds a test `test_child_supervision` to cover behavior of child supervision and its new behaviors. This change allows backward compatibility: If the parent does not support child supervision, it ignores the new TLV in the MLE messages and the child would fall back to periodically exchanging MLE Child Update Request with parent. If the child does not support supervision and/or does not indicate its desired child supervision interval, the parent will fall back to use the configured default interval.
This commit is contained in:
@@ -88,7 +88,6 @@ ot_option(OT_BORDER_ROUTING OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE "border rout
|
||||
ot_option(OT_BORDER_ROUTING_COUNTERS OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE "border routing counters")
|
||||
ot_option(OT_CHANNEL_MANAGER OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE "channel manager")
|
||||
ot_option(OT_CHANNEL_MONITOR OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE "channel monitor")
|
||||
ot_option(OT_CHILD_SUPERVISION OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE "child supervision")
|
||||
ot_option(OT_COAP OPENTHREAD_CONFIG_COAP_API_ENABLE "coap api")
|
||||
ot_option(OT_COAP_BLOCK OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE "coap block-wise transfer (RFC7959)")
|
||||
ot_option(OT_COAP_OBSERVE OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE "coap observe (RFC7641)")
|
||||
|
||||
@@ -45,7 +45,6 @@ COAPS ?= 1
|
||||
COMMISSIONER ?= 1
|
||||
CHANNEL_MANAGER ?= 1
|
||||
CHANNEL_MONITOR ?= 1
|
||||
CHILD_SUPERVISION ?= 1
|
||||
DATASET_UPDATER ?= 1
|
||||
DHCP6_CLIENT ?= 1
|
||||
DHCP6_SERVER ?= 1
|
||||
|
||||
@@ -16,7 +16,6 @@ This page lists the available common switches with description. Unless stated ot
|
||||
| BUILTIN_MBEDTLS_MANAGEMENT | OT_BUILTIN_MBEDTLS_MANAGEMENT | Enables the built-in mbedTLS management. Enable this switch if the external mbedTLS is used, but mbedTLS memory allocation and debug config should be managed internally by OpenThread. |
|
||||
| CHANNEL_MANAGER | OT_CHANNEL_MANAGER | Enables support for channel manager. Enable this switch on devices that are supposed to request a Thread network channel change. This switch should be used only with an FTD build. |
|
||||
| CHANNEL_MONITOR | OT_CHANNEL_MONITOR | Enables support for channel monitor. Enable this switch on devices that are supposed to determine the cleaner channels. |
|
||||
| CHILD_SUPERVISION | OT_CHILD_SUPERVISION | Enables support for [child supervision](https://openthread.io/guides/build/features/child-supervision). Enable this switch on a parent or child node with custom OpenThread application that manages the supervision, checks timeout intervals, and verifies connectivity between parent and child. |
|
||||
| COAP | OT_COAP | Enables support for the CoAP API. Enable this switch if you want to control Constrained Application Protocol communication. |
|
||||
| COAP_OBSERVE | OT_COAP_OBSERVE | Enables support for CoAP Observe (RFC7641) API. |
|
||||
| COAPS | OT_COAPS | Enables support for the secure CoAP API. Enable this switch if you want to control Constrained Application Protocol Secure (CoAP over DTLS) communication. |
|
||||
|
||||
@@ -42,7 +42,6 @@ COMMISSIONER ?= 0
|
||||
COVERAGE ?= 0
|
||||
CHANNEL_MANAGER ?= 0
|
||||
CHANNEL_MONITOR ?= 0
|
||||
CHILD_SUPERVISION ?= 0
|
||||
DATASET_UPDATER ?= 0
|
||||
DEBUG ?= 0
|
||||
DHCP6_CLIENT ?= 0
|
||||
@@ -159,10 +158,6 @@ ifeq ($(CHANNEL_MONITOR),1)
|
||||
COMMONCFLAGS += -DOPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE=1
|
||||
endif
|
||||
|
||||
ifeq ($(CHILD_SUPERVISION),1)
|
||||
COMMONCFLAGS += -DOPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE=1
|
||||
endif
|
||||
|
||||
ifeq ($(CSL_RECEIVER),1)
|
||||
COMMONCFLAGS += -DOPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE=1
|
||||
endif
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief
|
||||
* This file includes the OpenThread API for child supervision feature
|
||||
* This file includes the OpenThread API for child supervision feature.
|
||||
*/
|
||||
|
||||
#ifndef OPENTHREAD_CHILD_SUPERVISION_H_
|
||||
@@ -47,38 +47,35 @@ extern "C" {
|
||||
* @brief
|
||||
* This module includes functions for child supervision feature.
|
||||
*
|
||||
* The functions in this module are available when child supervision feature
|
||||
* (`OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE`) is enabled.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the child supervision interval (in seconds).
|
||||
* Gets the child supervision interval (in seconds) on a child.
|
||||
*
|
||||
* Child supervision feature provides a mechanism for parent to ensure that a message is sent to each sleepy child
|
||||
* within the supervision interval. If there is no transmission to the child within the supervision interval,
|
||||
* OpenThread enqueues and sends a supervision message (a data message with empty payload) to the child.
|
||||
* Child supervision feature provides a mechanism for a sleepy child to ask its parent to ensure to send a message to
|
||||
* it within the supervision interval. If there is no transmission to the child within the supervision interval,
|
||||
* parent sends a supervision message (a data message with empty payload) to the child.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
*
|
||||
* @returns The child supervision interval. Zero indicates that child supervision is disabled.
|
||||
* @returns The child supervision interval. Zero indicates that supervision is disabled.
|
||||
*
|
||||
*/
|
||||
uint16_t otChildSupervisionGetInterval(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Sets the child supervision interval (in seconds).
|
||||
* Sets the child supervision interval (in seconds) on the child.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aInterval The supervision interval (in seconds). Zero to disable supervision on parent.
|
||||
* @param[in] aInterval The supervision interval (in seconds). Zero to disable supervision.
|
||||
*
|
||||
*/
|
||||
void otChildSupervisionSetInterval(otInstance *aInstance, uint16_t aInterval);
|
||||
|
||||
/**
|
||||
* Gets the supervision check timeout interval (in seconds).
|
||||
* Gets the supervision check timeout interval (in seconds) on the child.
|
||||
*
|
||||
* If the device is a sleepy child and it does not hear from its parent within the specified check timeout, it initiates
|
||||
* the re-attach process (MLE Child Update Request/Response exchange with its parent).
|
||||
@@ -99,6 +96,21 @@ uint16_t otChildSupervisionGetCheckTimeout(otInstance *aInstance);
|
||||
*/
|
||||
void otChildSupervisionSetCheckTimeout(otInstance *aInstance, uint16_t aTimeout);
|
||||
|
||||
/**
|
||||
* Get the value of supervision check timeout failure counter.
|
||||
*
|
||||
* The counter tracks the number of supervision check failures on the child. It is incremented when the child does
|
||||
* not hear from its parent within the specified check timeout interval.
|
||||
*
|
||||
*/
|
||||
uint16_t otChildSupervisionGetCheckFailureCounter(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Reset the supervision check timeout failure counter to zero.
|
||||
*
|
||||
*/
|
||||
void otChildSupervisionResetCheckFailureCounter(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (291)
|
||||
#define OPENTHREAD_API_VERSION (292)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -68,6 +68,7 @@ typedef struct
|
||||
uint16_t mFrameErrorRate; ///< Frame error rate (0xffff->100%). Requires error tracking feature.
|
||||
uint16_t mMessageErrorRate; ///< (IPv6) msg error rate (0xffff->100%). Requires error tracking feature.
|
||||
uint16_t mQueuedMessageCnt; ///< Number of queued messages for the child.
|
||||
uint16_t mSupervisionInterval; ///< Supervision interval (in seconds).
|
||||
uint8_t mVersion; ///< MLE version
|
||||
bool mRxOnWhenIdle : 1; ///< rx-on-when-idle
|
||||
bool mFullThreadDevice : 1; ///< Full Thread Device
|
||||
|
||||
@@ -44,7 +44,6 @@ build_nrf52840()
|
||||
"-DOT_BORDER_ROUTER=ON"
|
||||
"-DOT_CHANNEL_MANAGER=ON"
|
||||
"-DOT_CHANNEL_MONITOR=ON"
|
||||
"-DOT_CHILD_SUPERVISION=ON"
|
||||
"-DOT_COAP=ON"
|
||||
"-DOT_COAPS=ON"
|
||||
"-DOT_COMMISSIONER=ON"
|
||||
|
||||
@@ -48,7 +48,6 @@ OT_BUILD_OPTIONS=(
|
||||
"-DOT_COVERAGE=ON"
|
||||
"-DOT_CHANNEL_MANAGER=ON"
|
||||
"-DOT_CHANNEL_MONITOR=ON"
|
||||
"-DOT_CHILD_SUPERVISION=ON"
|
||||
"-DOT_DATASET_UPDATER=ON"
|
||||
"-DOT_DHCP6_CLIENT=ON"
|
||||
"-DOT_DHCP6_SERVER=ON"
|
||||
|
||||
@@ -47,7 +47,6 @@ build_all_features()
|
||||
"-DOPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_COAP_API_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_COMMISSIONER_ENABLE=1"
|
||||
@@ -144,7 +143,6 @@ build_nest_common()
|
||||
"-DOPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_DIAG_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_JAM_DETECTION_ENABLE=1"
|
||||
|
||||
@@ -126,7 +126,6 @@ size_nrf52840_version()
|
||||
"-DOT_BORDER_ROUTER=ON"
|
||||
"-DOT_CHANNEL_MANAGER=ON"
|
||||
"-DOT_CHANNEL_MONITOR=ON"
|
||||
"-DOT_CHILD_SUPERVISION=ON"
|
||||
"-DOT_COAP=ON"
|
||||
"-DOT_COAPS=ON"
|
||||
"-DOT_COMMISSIONER=ON"
|
||||
|
||||
@@ -81,7 +81,6 @@ OT_POSIX_SIM_COMMON_OPTIONS=(
|
||||
"-DOT_COMMISSIONER=ON"
|
||||
"-DOT_CHANNEL_MANAGER=ON"
|
||||
"-DOT_CHANNEL_MONITOR=ON"
|
||||
"-DOT_CHILD_SUPERVISION=ON"
|
||||
"-DOT_DATASET_UPDATER=ON"
|
||||
"-DOT_DHCP6_CLIENT=ON"
|
||||
"-DOT_DHCP6_SERVER=ON"
|
||||
|
||||
@@ -95,7 +95,6 @@ OT_CLANG_TIDY_BUILD_OPTS=(
|
||||
'-DOT_BORDER_ROUTING=ON'
|
||||
'-DOT_CHANNEL_MANAGER=ON'
|
||||
'-DOT_CHANNEL_MONITOR=ON'
|
||||
'-DOT_CHILD_SUPERVISION=ON'
|
||||
'-DOT_COAP=ON'
|
||||
'-DOT_COAP_BLOCK=ON'
|
||||
'-DOT_COAP_OBSERVE=ON'
|
||||
|
||||
+26
-4
@@ -623,10 +623,10 @@ Print table of attached children.
|
||||
|
||||
```bash
|
||||
> child table
|
||||
| ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|D|N|Ver|CSL|QMsgCnt| Extended MAC |
|
||||
+-----+--------+------------+------------+-------+------+-+-+-+---+---+-------+------------------+
|
||||
| 1 | 0xc801 | 240 | 24 | 3 | 131 |1|0|0| 3| 0 | 0 | 4ecede68435358ac |
|
||||
| 2 | 0xc802 | 240 | 2 | 3 | 131 |0|0|0| 3| 1 | 0 | a672a601d2ce37d8 |
|
||||
| ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|D|N|Ver|CSL|QMsgCnt|Suprvsn| Extended MAC |
|
||||
+-----+--------+------------+------------+-------+------+-+-+-+---+---+-------+-------+------------------+
|
||||
| 1 | 0xc801 | 240 | 24 | 3 | 131 |1|0|0| 3| 0 | 0 | 129 | 4ecede68435358ac |
|
||||
| 2 | 0xc802 | 240 | 2 | 3 | 131 |0|0|0| 3| 1 | 0 | 0 | a672a601d2ce37d8 |
|
||||
Done
|
||||
```
|
||||
|
||||
@@ -646,6 +646,7 @@ Timeout: 100
|
||||
Age: 0
|
||||
Link Quality In: 3
|
||||
RSSI: -20
|
||||
Supervision Interval: 129
|
||||
Done
|
||||
```
|
||||
|
||||
@@ -741,6 +742,27 @@ Set the Child Supervision Check Timeout value.
|
||||
Done
|
||||
```
|
||||
|
||||
### childsupervision failcounter
|
||||
|
||||
Get the current value of supervision check timeout failure counter.
|
||||
|
||||
The counter tracks the number of supervision check failures on the child. It is incremented when the child does not hear from its parent within the specified check timeout interval.
|
||||
|
||||
```bash
|
||||
> childsupervision failcounter
|
||||
0
|
||||
Done
|
||||
```
|
||||
|
||||
### childsupervision failcounter reset
|
||||
|
||||
Reset the supervision check timeout failure counter to zero.
|
||||
|
||||
```bash
|
||||
> childsupervision failcounter reset
|
||||
Done
|
||||
```
|
||||
|
||||
### childtimeout
|
||||
|
||||
Get the Thread Child Timeout value.
|
||||
|
||||
+19
-16
@@ -37,6 +37,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openthread/child_supervision.h>
|
||||
#include <openthread/diag.h>
|
||||
#include <openthread/dns.h>
|
||||
#include <openthread/icmp6.h>
|
||||
@@ -58,9 +59,6 @@
|
||||
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
|
||||
#include <openthread/server.h>
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
#include <openthread/child_supervision.h>
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
|
||||
#include <openthread/platform/misc.h>
|
||||
#endif
|
||||
@@ -1894,12 +1892,12 @@ template <> otError Interpreter::Process<Cmd("child")>(Arg aArgs[])
|
||||
if (isTable)
|
||||
{
|
||||
static const char *const kChildTableTitles[] = {
|
||||
"ID", "RLOC16", "Timeout", "Age", "LQ In", "C_VN", "R",
|
||||
"D", "N", "Ver", "CSL", "QMsgCnt", "Extended MAC",
|
||||
"ID", "RLOC16", "Timeout", "Age", "LQ In", "C_VN", "R",
|
||||
"D", "N", "Ver", "CSL", "QMsgCnt", "Suprvsn", "Extended MAC",
|
||||
};
|
||||
|
||||
static const uint8_t kChildTableColumnWidths[] = {
|
||||
5, 8, 12, 12, 7, 6, 1, 1, 1, 3, 3, 7, 18,
|
||||
5, 8, 12, 12, 7, 6, 1, 1, 1, 3, 3, 7, 7, 18,
|
||||
};
|
||||
|
||||
OutputTableHeader(kChildTableTitles, kChildTableColumnWidths);
|
||||
@@ -1929,6 +1927,7 @@ template <> otError Interpreter::Process<Cmd("child")>(Arg aArgs[])
|
||||
OutputFormat("|%3u", childInfo.mVersion);
|
||||
OutputFormat("| %1d ", childInfo.mIsCslSynced);
|
||||
OutputFormat("| %5u ", childInfo.mQueuedMessageCnt);
|
||||
OutputFormat("| %5u ", childInfo.mSupervisionInterval);
|
||||
OutputFormat("| ");
|
||||
OutputExtAddress(childInfo.mExtAddress);
|
||||
OutputLine(" |");
|
||||
@@ -1991,6 +1990,7 @@ template <> otError Interpreter::Process<Cmd("child")>(Arg aArgs[])
|
||||
OutputLine("Age: %lu", ToUlong(childInfo.mAge));
|
||||
OutputLine("Link Quality In: %u", childInfo.mLinkQualityIn);
|
||||
OutputLine("RSSI: %d", childInfo.mAverageRssi);
|
||||
OutputLine("Supervision Interval: %d", childInfo.mSupervisionInterval);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
@@ -2099,7 +2099,6 @@ template <> otError Interpreter::Process<Cmd("childmax")>(Arg aArgs[])
|
||||
}
|
||||
#endif // OPENTHREAD_FTD
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
template <> otError Interpreter::Process<Cmd("childsupervision")>(Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_INVALID_ARGS;
|
||||
@@ -2127,7 +2126,6 @@ template <> otError Interpreter::Process<Cmd("childsupervision")>(Arg aArgs[])
|
||||
*/
|
||||
error = ProcessGetSet(aArgs + 1, otChildSupervisionGetCheckTimeout, otChildSupervisionSetCheckTimeout);
|
||||
}
|
||||
#if OPENTHREAD_FTD
|
||||
/**
|
||||
* @cli childsupervision interval
|
||||
* @code
|
||||
@@ -2135,8 +2133,6 @@ template <> otError Interpreter::Process<Cmd("childsupervision")>(Arg aArgs[])
|
||||
* 30
|
||||
* Done
|
||||
* @endcode
|
||||
* @par
|
||||
* This command can only be used with FTD devices.
|
||||
* @par api_copy
|
||||
* #otChildSupervisionGetInterval
|
||||
*/
|
||||
@@ -2149,18 +2145,27 @@ template <> otError Interpreter::Process<Cmd("childsupervision")>(Arg aArgs[])
|
||||
* Done
|
||||
* @endcode
|
||||
* @cparam childsupervision interval @ca{interval-seconds}
|
||||
* @par
|
||||
* This command can only be used with FTD devices.
|
||||
* @par api_copy
|
||||
* #otChildSupervisionSetInterval
|
||||
*/
|
||||
error = ProcessGetSet(aArgs + 1, otChildSupervisionGetInterval, otChildSupervisionSetInterval);
|
||||
}
|
||||
#endif
|
||||
else if (aArgs[0] == "failcounter")
|
||||
{
|
||||
if (aArgs[1].IsEmpty())
|
||||
{
|
||||
OutputLine("%u", otChildSupervisionGetCheckFailureCounter(GetInstancePtr()));
|
||||
error = OT_ERROR_NONE;
|
||||
}
|
||||
else if (aArgs[1] == "reset")
|
||||
{
|
||||
otChildSupervisionResetCheckFailureCounter(GetInstancePtr());
|
||||
error = OT_ERROR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
|
||||
/** @cli childtimeout
|
||||
* @code
|
||||
@@ -7637,9 +7642,7 @@ otError Interpreter::ProcessCommand(Arg aArgs[])
|
||||
CmdEntry("childmax"),
|
||||
CmdEntry("childrouterlinks"),
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
CmdEntry("childsupervision"),
|
||||
#endif
|
||||
CmdEntry("childtimeout"),
|
||||
#if OPENTHREAD_CONFIG_COAP_API_ENABLE
|
||||
CmdEntry("coap"),
|
||||
|
||||
+2
-6
@@ -98,10 +98,6 @@ if (openthread_enable_core_config_args) {
|
||||
defines += [ "OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE=1" ]
|
||||
}
|
||||
|
||||
if (openthread_config_child_supervision_enable) {
|
||||
defines += [ "OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE=1" ]
|
||||
}
|
||||
|
||||
if (openthread_config_coap_api_enable) {
|
||||
defines += [ "OPENTHREAD_CONFIG_COAP_API_ENABLE=1" ]
|
||||
}
|
||||
@@ -602,6 +598,8 @@ openthread_core_files = [
|
||||
"thread/anycast_locator.cpp",
|
||||
"thread/anycast_locator.hpp",
|
||||
"thread/child_mask.hpp",
|
||||
"thread/child_supervision.cpp",
|
||||
"thread/child_supervision.hpp",
|
||||
"thread/child_table.cpp",
|
||||
"thread/child_table.hpp",
|
||||
"thread/csl_tx_scheduler.cpp",
|
||||
@@ -688,8 +686,6 @@ openthread_core_files = [
|
||||
"utils/channel_manager.hpp",
|
||||
"utils/channel_monitor.cpp",
|
||||
"utils/channel_monitor.hpp",
|
||||
"utils/child_supervision.cpp",
|
||||
"utils/child_supervision.hpp",
|
||||
"utils/flash.cpp",
|
||||
"utils/flash.hpp",
|
||||
"utils/heap.cpp",
|
||||
|
||||
@@ -192,6 +192,7 @@ set(COMMON_SOURCES
|
||||
thread/announce_begin_server.cpp
|
||||
thread/announce_sender.cpp
|
||||
thread/anycast_locator.cpp
|
||||
thread/child_supervision.cpp
|
||||
thread/child_table.cpp
|
||||
thread/csl_tx_scheduler.cpp
|
||||
thread/discover_scanner.cpp
|
||||
@@ -233,7 +234,6 @@ set(COMMON_SOURCES
|
||||
thread/uri_paths.cpp
|
||||
utils/channel_manager.cpp
|
||||
utils/channel_monitor.cpp
|
||||
utils/child_supervision.cpp
|
||||
utils/flash.cpp
|
||||
utils/heap.cpp
|
||||
utils/history_tracker.cpp
|
||||
|
||||
@@ -282,6 +282,7 @@ SOURCES_COMMON = \
|
||||
thread/announce_begin_server.cpp \
|
||||
thread/announce_sender.cpp \
|
||||
thread/anycast_locator.cpp \
|
||||
thread/child_supervision.cpp \
|
||||
thread/child_table.cpp \
|
||||
thread/csl_tx_scheduler.cpp \
|
||||
thread/discover_scanner.cpp \
|
||||
@@ -323,7 +324,6 @@ SOURCES_COMMON = \
|
||||
thread/uri_paths.cpp \
|
||||
utils/channel_manager.cpp \
|
||||
utils/channel_monitor.cpp \
|
||||
utils/child_supervision.cpp \
|
||||
utils/flash.cpp \
|
||||
utils/heap.cpp \
|
||||
utils/history_tracker.cpp \
|
||||
@@ -602,6 +602,7 @@ HEADERS_COMMON = \
|
||||
thread/announce_sender.hpp \
|
||||
thread/anycast_locator.hpp \
|
||||
thread/child_mask.hpp \
|
||||
thread/child_supervision.hpp \
|
||||
thread/child_table.hpp \
|
||||
thread/csl_tx_scheduler.hpp \
|
||||
thread/discover_scanner.hpp \
|
||||
@@ -647,7 +648,6 @@ HEADERS_COMMON = \
|
||||
thread/version.hpp \
|
||||
utils/channel_manager.hpp \
|
||||
utils/channel_monitor.hpp \
|
||||
utils/child_supervision.hpp \
|
||||
utils/flash.hpp \
|
||||
utils/heap.hpp \
|
||||
utils/history_tracker.hpp \
|
||||
|
||||
@@ -33,8 +33,6 @@
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
|
||||
#include <openthread/child_supervision.h>
|
||||
|
||||
#include "common/as_core_type.hpp"
|
||||
@@ -42,28 +40,32 @@
|
||||
|
||||
using namespace ot;
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
uint16_t otChildSupervisionGetInterval(otInstance *aInstance)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<Utils::ChildSupervisor>().GetSupervisionInterval();
|
||||
return AsCoreType(aInstance).Get<SupervisionListener>().GetInterval();
|
||||
}
|
||||
|
||||
void otChildSupervisionSetInterval(otInstance *aInstance, uint16_t aInterval)
|
||||
{
|
||||
AsCoreType(aInstance).Get<Utils::ChildSupervisor>().SetSupervisionInterval(aInterval);
|
||||
AsCoreType(aInstance).Get<SupervisionListener>().SetInterval(aInterval);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
uint16_t otChildSupervisionGetCheckTimeout(otInstance *aInstance)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<Utils::SupervisionListener>().GetTimeout();
|
||||
return AsCoreType(aInstance).Get<SupervisionListener>().GetTimeout();
|
||||
}
|
||||
|
||||
void otChildSupervisionSetCheckTimeout(otInstance *aInstance, uint16_t aTimeout)
|
||||
{
|
||||
AsCoreType(aInstance).Get<Utils::SupervisionListener>().SetTimeout(aTimeout);
|
||||
AsCoreType(aInstance).Get<SupervisionListener>().SetTimeout(aTimeout);
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
uint16_t otChildSupervisionGetCheckFailureCounter(otInstance *aInstance)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<SupervisionListener>().GetCounter();
|
||||
}
|
||||
|
||||
void otChildSupervisionResetCheckFailureCounter(otInstance *aInstance)
|
||||
{
|
||||
AsCoreType(aInstance).Get<SupervisionListener>().ResetCounter();
|
||||
}
|
||||
|
||||
@@ -175,13 +175,10 @@ Instance::Instance(void)
|
||||
#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
|
||||
, mSrpServer(*this)
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
#if OPENTHREAD_FTD
|
||||
, mChildSupervisor(*this)
|
||||
#endif
|
||||
, mSupervisionListener(*this)
|
||||
#endif
|
||||
, mAnnounceBegin(*this)
|
||||
, mPanIdQuery(*this)
|
||||
, mEnergyScan(*this)
|
||||
|
||||
@@ -101,6 +101,7 @@
|
||||
#include "thread/announce_begin_server.hpp"
|
||||
#include "thread/announce_sender.hpp"
|
||||
#include "thread/anycast_locator.hpp"
|
||||
#include "thread/child_supervision.hpp"
|
||||
#include "thread/discover_scanner.hpp"
|
||||
#include "thread/dua_manager.hpp"
|
||||
#include "thread/energy_scan_server.hpp"
|
||||
@@ -123,7 +124,6 @@
|
||||
#include "thread/tmf.hpp"
|
||||
#include "utils/channel_manager.hpp"
|
||||
#include "utils/channel_monitor.hpp"
|
||||
#include "utils/child_supervision.hpp"
|
||||
#include "utils/heap.hpp"
|
||||
#include "utils/history_tracker.hpp"
|
||||
#include "utils/jam_detector.hpp"
|
||||
@@ -544,12 +544,10 @@ private:
|
||||
Srp::Server mSrpServer;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
#if OPENTHREAD_FTD
|
||||
Utils::ChildSupervisor mChildSupervisor;
|
||||
#endif
|
||||
Utils::SupervisionListener mSupervisionListener;
|
||||
ChildSupervisor mChildSupervisor;
|
||||
#endif
|
||||
SupervisionListener mSupervisionListener;
|
||||
|
||||
AnnounceBeginServer mAnnounceBegin;
|
||||
PanIdQueryServer mPanIdQuery;
|
||||
@@ -849,12 +847,10 @@ template <> inline Utils::JamDetector &Instance::Get(void) { return mJamDetector
|
||||
template <> inline Sntp::Client &Instance::Get(void) { return mSntpClient; }
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
#if OPENTHREAD_FTD
|
||||
template <> inline Utils::ChildSupervisor &Instance::Get(void) { return mChildSupervisor; }
|
||||
#endif
|
||||
template <> inline Utils::SupervisionListener &Instance::Get(void) { return mSupervisionListener; }
|
||||
template <> inline ChildSupervisor &Instance::Get(void) { return mChildSupervisor; }
|
||||
#endif
|
||||
template <> inline SupervisionListener &Instance::Get(void) { return mSupervisionListener; }
|
||||
|
||||
#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
|
||||
template <> inline Utils::PingSender &Instance::Get(void) { return mPingSender; }
|
||||
|
||||
@@ -133,9 +133,7 @@ void Notifier::EmitEvents(void)
|
||||
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
||||
Get<BackboneRouter::Manager>().HandleNotifierEvents(events);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
Get<Utils::ChildSupervisor>().HandleNotifierEvents(events);
|
||||
#endif
|
||||
Get<ChildSupervisor>().HandleNotifierEvents(events);
|
||||
#if OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE || OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE
|
||||
Get<MeshCoP::DatasetUpdater>().HandleNotifierEvents(events);
|
||||
#endif
|
||||
|
||||
@@ -96,12 +96,10 @@ void TimeTicker::HandleTimer(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
if (mReceivers & Mask(kChildSupervisor))
|
||||
{
|
||||
Get<Utils::ChildSupervisor>().HandleTimeTick();
|
||||
Get<ChildSupervisor>().HandleTimeTick();
|
||||
}
|
||||
#endif
|
||||
#endif // OPENTHREAD_FTD
|
||||
|
||||
#if OPENTHREAD_CONFIG_IP6_FRAGMENTATION_ENABLE
|
||||
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
kMeshForwarder, ///< `MeshForwarder`
|
||||
kMleRouter, ///< `Mle::MleRouter`
|
||||
kAddressResolver, ///< `AddressResolver`
|
||||
kChildSupervisor, ///< `Utils::ChildSupervisor`
|
||||
kChildSupervisor, ///< `ChildSupervisor`
|
||||
kIp6FragmentReassembler, ///< `Ip6::Ip6` (handling of fragmented messages)
|
||||
kDuaManager, ///< `DuaManager`
|
||||
kMlrManager, ///< `MlrManager`
|
||||
|
||||
@@ -35,24 +35,12 @@
|
||||
#ifndef CONFIG_CHILD_SUPERVISION_H_
|
||||
#define CONFIG_CHILD_SUPERVISION_H_
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
*
|
||||
* Define to 1 to enable Child Supervision support.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
#define OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_CHILD_SUPERVISION_INTERVAL
|
||||
*
|
||||
* The default supervision interval in seconds used by parent. Set to zero to disable the supervision process on the
|
||||
* parent.
|
||||
* The default supervision interval in seconds to use when in child state. Zero indicates no supervision needed.
|
||||
*
|
||||
* Applicable only if child supervision feature is enabled (i.e.,
|
||||
* `OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE ` is set).
|
||||
* The current supervision interval can be changed using `otChildSupervisionSetInterval()`.
|
||||
*
|
||||
* Child supervision feature provides a mechanism for parent to ensure that a message is sent to each sleepy child
|
||||
* within the supervision interval. If there is no transmission to the child within the supervision interval, child
|
||||
@@ -69,7 +57,7 @@
|
||||
* The default supervision check timeout interval (in seconds) used by a device in child state. Set to zero to disable
|
||||
* the supervision check process on the child.
|
||||
*
|
||||
* Applicable only if child supervision feature is enabled (i.e., `OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE` is set).
|
||||
* The check timeout interval can be changed using `otChildSupervisionSetCheckTimeout()`.
|
||||
*
|
||||
* If the sleepy child does not hear from its parent within the specified timeout interval, it initiates the re-attach
|
||||
* process (MLE Child Update Request/Response exchange with its parent).
|
||||
@@ -80,15 +68,22 @@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_CHILD_SUPERVISION_MSG_NO_ACK_REQUEST
|
||||
* @def OPENTHREAD_CONFIG_CHILD_SUPERVISION_OLDER_VERSION_CHILD_DEFAULT_INTERVAL
|
||||
*
|
||||
* Define as 1 to clear/disable 15.4 ack request in the MAC header of a supervision message.
|
||||
* Specifies the default supervision interval to use on parent for children that do not explicitly indicate their
|
||||
* desired supervision internal (do not include a "Supervision Interval TLV") and are running older Thread versions
|
||||
* (version <= 1.3.0).
|
||||
*
|
||||
* Applicable only if child supervision feature is enabled (i.e., `OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE` is set).
|
||||
* This config is added to allow backward compatibility on parent with SED children that used Child Supervision
|
||||
* feature in OT stack before adoption of it by Thread specification and addition of the "Supervision Interval TLV" as
|
||||
* the mechanism for child to inform the parent of its desired supervision interval.
|
||||
*
|
||||
* The config can be set to zero to effectively disable it, i.e., if a child does not provide "Supervision Interval TLV"
|
||||
* it indicates that it does not want to be supervised and then parent will use zero interval for the child.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_CHILD_SUPERVISION_MSG_NO_ACK_REQUEST
|
||||
#define OPENTHREAD_CONFIG_CHILD_SUPERVISION_MSG_NO_ACK_REQUEST 0
|
||||
#ifndef OPENTHREAD_CONFIG_CHILD_SUPERVISION_OLDER_VERSION_CHILD_DEFAULT_INTERVAL
|
||||
#define OPENTHREAD_CONFIG_CHILD_SUPERVISION_OLDER_VERSION_CHILD_DEFAULT_INTERVAL 129
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_CHILD_SUPERVISION_H_
|
||||
|
||||
@@ -640,4 +640,12 @@
|
||||
#error "OPENTHREAD_CONFIG_BORDER_ROUTING_NAT64_ENABLE was replaced by OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE"
|
||||
#endif
|
||||
|
||||
#ifdef OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
#error "OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE is removed. The feature is now supported by default (on 1.3.0)"
|
||||
#endif
|
||||
|
||||
#ifdef OPENTHREAD_CONFIG_CHILD_SUPERVISION_MSG_NO_ACK_REQUEST
|
||||
#error "OPENTHREAD_CONFIG_CHILD_SUPERVISION_MSG_NO_ACK_REQUEST is removed".
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_CORE_CONFIG_CHECK_H_
|
||||
|
||||
@@ -41,26 +41,16 @@
|
||||
#include "thread/thread_netif.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Utils {
|
||||
|
||||
RegisterLogModule("ChildSupervsn");
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
ChildSupervisor::ChildSupervisor(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mSupervisionInterval(kDefaultSupervisionInterval)
|
||||
{
|
||||
}
|
||||
|
||||
void ChildSupervisor::SetSupervisionInterval(uint16_t aInterval)
|
||||
{
|
||||
mSupervisionInterval = aInterval;
|
||||
CheckState();
|
||||
}
|
||||
|
||||
Child *ChildSupervisor::GetDestination(const Message &aMessage) const
|
||||
{
|
||||
Child *child = nullptr;
|
||||
@@ -108,9 +98,14 @@ void ChildSupervisor::HandleTimeTick(void)
|
||||
{
|
||||
for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
|
||||
{
|
||||
if (child.IsRxOnWhenIdle() || (child.GetSupervisionInterval() == 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
child.IncrementSecondsSinceLastSupervision();
|
||||
|
||||
if ((child.GetSecondsSinceLastSupervision() >= mSupervisionInterval) && !child.IsRxOnWhenIdle())
|
||||
if (child.GetSecondsSinceLastSupervision() >= child.GetSupervisionInterval())
|
||||
{
|
||||
SendMessage(child);
|
||||
}
|
||||
@@ -119,14 +114,11 @@ void ChildSupervisor::HandleTimeTick(void)
|
||||
|
||||
void ChildSupervisor::CheckState(void)
|
||||
{
|
||||
bool shouldRun = false;
|
||||
// Child Supervision should run if Thread MLE operation is
|
||||
// enabled, and there is at least one "valid" child in the
|
||||
// child table.
|
||||
|
||||
// Child Supervision should run if `mSupervisionInterval` is not
|
||||
// zero, Thread MLE operation is enabled, and there is at least one
|
||||
// "valid" child in the child table.
|
||||
|
||||
shouldRun = ((mSupervisionInterval != 0) && !Get<Mle::MleRouter>().IsDisabled() &&
|
||||
Get<ChildTable>().HasChildren(Child::kInStateValid));
|
||||
bool shouldRun = (!Get<Mle::Mle>().IsDisabled() && Get<ChildTable>().HasChildren(Child::kInStateValid));
|
||||
|
||||
if (shouldRun && !Get<TimeTicker>().IsReceiverRegistered(TimeTicker::kChildSupervisor))
|
||||
{
|
||||
@@ -154,6 +146,7 @@ void ChildSupervisor::HandleNotifierEvents(Events aEvents)
|
||||
SupervisionListener::SupervisionListener(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mTimeout(0)
|
||||
, mInterval(kDefaultInterval)
|
||||
, mTimer(aInstance)
|
||||
{
|
||||
SetTimeout(kDefaultTimeout);
|
||||
@@ -163,10 +156,29 @@ void SupervisionListener::Start(void) { RestartTimer(); }
|
||||
|
||||
void SupervisionListener::Stop(void) { mTimer.Stop(); }
|
||||
|
||||
void SupervisionListener::SetInterval(uint16_t aInterval)
|
||||
{
|
||||
VerifyOrExit(mInterval != aInterval);
|
||||
|
||||
LogInfo("Interval: %u -> %u", mInterval, aInterval);
|
||||
|
||||
mInterval = aInterval;
|
||||
|
||||
if (Get<Mle::Mle>().IsChild())
|
||||
{
|
||||
IgnoreError(Get<Mle::Mle>().SendChildUpdateRequest());
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void SupervisionListener::SetTimeout(uint16_t aTimeout)
|
||||
{
|
||||
if (mTimeout != aTimeout)
|
||||
{
|
||||
LogInfo("Timeout: %u -> %u", mTimeout, aTimeout);
|
||||
|
||||
mTimeout = aTimeout;
|
||||
RestartTimer();
|
||||
}
|
||||
@@ -201,7 +213,8 @@ void SupervisionListener::HandleTimer(void)
|
||||
{
|
||||
VerifyOrExit(Get<Mle::MleRouter>().IsChild() && !Get<MeshForwarder>().GetRxOnWhenIdle());
|
||||
|
||||
LogWarn("Supervision timeout. No frame from parent in %d sec", mTimeout);
|
||||
LogWarn("Supervision timeout. No frame from parent in %u sec", mTimeout);
|
||||
mCounter++;
|
||||
|
||||
IgnoreError(Get<Mle::MleRouter>().SendChildUpdateRequest());
|
||||
|
||||
@@ -209,7 +222,4 @@ exit:
|
||||
RestartTimer();
|
||||
}
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
|
||||
} // namespace Utils
|
||||
} // namespace ot
|
||||
@@ -53,8 +53,6 @@ namespace ot {
|
||||
class ThreadNetif;
|
||||
class Child;
|
||||
|
||||
namespace Utils {
|
||||
|
||||
/**
|
||||
*
|
||||
* Child supervision feature provides a mechanism for parent
|
||||
@@ -85,8 +83,6 @@ namespace Utils {
|
||||
*
|
||||
*/
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
/**
|
||||
@@ -119,25 +115,6 @@ public:
|
||||
*/
|
||||
void Stop(void);
|
||||
|
||||
/**
|
||||
* This method sets the supervision interval.
|
||||
*
|
||||
* Setting the supervision interval to a non-zero value will ensure to start the supervision process (if not
|
||||
* already started).
|
||||
*
|
||||
* @param[in] aInterval If non-zero, the desired supervision interval (in seconds), zero to disable supervision.
|
||||
*
|
||||
*/
|
||||
void SetSupervisionInterval(uint16_t aInterval);
|
||||
|
||||
/**
|
||||
* This method returns the supervision interval.
|
||||
*
|
||||
* @returns The current supervision interval (seconds), or zero if supervision is disabled.
|
||||
*
|
||||
*/
|
||||
uint16_t GetSupervisionInterval(void) const { return mSupervisionInterval; }
|
||||
|
||||
/**
|
||||
* This method returns the destination for a supervision message.
|
||||
*
|
||||
@@ -165,8 +142,6 @@ private:
|
||||
void CheckState(void);
|
||||
void HandleTimeTick(void);
|
||||
void HandleNotifierEvents(Events aEvents);
|
||||
|
||||
uint16_t mSupervisionInterval;
|
||||
};
|
||||
|
||||
#endif // #if OPENTHREAD_FTD
|
||||
@@ -198,6 +173,22 @@ public:
|
||||
*/
|
||||
void Stop(void);
|
||||
|
||||
/**
|
||||
* This method sets the supervision interval.
|
||||
*
|
||||
* @param[in] aInterval If non-zero, the desired supervision interval (in seconds), zero to disable supervision.
|
||||
*
|
||||
*/
|
||||
void SetInterval(uint16_t aInterval);
|
||||
|
||||
/**
|
||||
* This method returns the supervision interval.
|
||||
*
|
||||
* @returns The current supervision interval (seconds), or zero if supervision is disabled.
|
||||
*
|
||||
*/
|
||||
uint16_t GetInterval(void) const { return mInterval; }
|
||||
|
||||
/**
|
||||
* This method sets the supervision check timeout (in seconds).
|
||||
*
|
||||
@@ -221,6 +212,21 @@ public:
|
||||
*/
|
||||
uint16_t GetTimeout(void) const { return mTimeout; }
|
||||
|
||||
/**
|
||||
* This method returns the value of supervision check timeout failure counter.
|
||||
*
|
||||
* The counter tracks the number of supervision check failures on the child. It is incremented when the child does
|
||||
* not hear from its parent within the specified check timeout interval.
|
||||
*
|
||||
*/
|
||||
uint16_t GetCounter(void) const { return mCounter; }
|
||||
|
||||
/**
|
||||
* This method reset the supervision check timeout failure counter.
|
||||
*
|
||||
*/
|
||||
void ResetCounter(void) { mCounter = 0; }
|
||||
|
||||
/**
|
||||
* This method updates the supervision listener state. It informs the listener of a received frame.
|
||||
*
|
||||
@@ -231,7 +237,8 @@ public:
|
||||
void UpdateOnReceive(const Mac::Address &aSourceAddress, bool aIsSecure);
|
||||
|
||||
private:
|
||||
static constexpr uint16_t kDefaultTimeout = OPENTHREAD_CONFIG_CHILD_SUPERVISION_CHECK_TIMEOUT; // (seconds)
|
||||
static constexpr uint16_t kDefaultTimeout = OPENTHREAD_CONFIG_CHILD_SUPERVISION_CHECK_TIMEOUT; // (seconds)
|
||||
static constexpr uint16_t kDefaultInterval = OPENTHREAD_CONFIG_CHILD_SUPERVISION_INTERVAL; // (seconds)
|
||||
|
||||
void RestartTimer(void);
|
||||
void HandleTimer(void);
|
||||
@@ -239,17 +246,11 @@ private:
|
||||
using ListenerTimer = TimerMilliIn<SupervisionListener, &SupervisionListener::HandleTimer>;
|
||||
|
||||
uint16_t mTimeout;
|
||||
uint16_t mInterval;
|
||||
uint16_t mCounter;
|
||||
ListenerTimer mTimer;
|
||||
};
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
} // namespace Utils
|
||||
} // namespace ot
|
||||
|
||||
#endif // CHILD_SUPERVISION_HPP_
|
||||
@@ -345,7 +345,7 @@ Error IndirectSender::PrepareFrameForChild(Mac::TxFrame &aFrame, FrameContext &a
|
||||
break;
|
||||
|
||||
case Message::kTypeSupervision:
|
||||
PrepareEmptyFrame(aFrame, aChild, kSupervisionMsgAckRequest);
|
||||
PrepareEmptyFrame(aFrame, aChild, /* aAckRequest */ true);
|
||||
aContext.mMessageNextOffset = message->GetLength();
|
||||
break;
|
||||
|
||||
@@ -418,12 +418,10 @@ void IndirectSender::HandleSentFrameToChild(const Mac::TxFrame &aFrame,
|
||||
|
||||
VerifyOrExit(mEnabled);
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
if (aError == kErrorNone)
|
||||
{
|
||||
Get<Utils::ChildSupervisor>().UpdateOnSend(aChild);
|
||||
Get<ChildSupervisor>().UpdateOnSend(aChild);
|
||||
}
|
||||
#endif
|
||||
|
||||
// A zero `nextOffset` indicates that the sent frame is an empty
|
||||
// frame generated by `PrepareFrameForChild()` when there was no
|
||||
|
||||
@@ -203,12 +203,6 @@ public:
|
||||
void HandleChildModeChange(Child &aChild, Mle::DeviceMode aOldMode);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Indicates whether to set/enable 15.4 ack request in the MAC header of a supervision message.
|
||||
*
|
||||
*/
|
||||
static constexpr bool kSupervisionMsgAckRequest = (OPENTHREAD_CONFIG_CHILD_SUPERVISION_MSG_NO_ACK_REQUEST == 0);
|
||||
|
||||
// Callbacks from DataPollHandler
|
||||
Error PrepareFrameForChild(Mac::TxFrame &aFrame, FrameContext &aContext, Child &aChild);
|
||||
void HandleSentFrameToChild(const Mac::TxFrame &aFrame, const FrameContext &aContext, Error aError, Child &aChild);
|
||||
|
||||
@@ -663,16 +663,12 @@ void MeshForwarder::SetRxOnWhenIdle(bool aRxOnWhenIdle)
|
||||
if (aRxOnWhenIdle)
|
||||
{
|
||||
mDataPollSender.StopPolling();
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
Get<Utils::SupervisionListener>().Stop();
|
||||
#endif
|
||||
Get<SupervisionListener>().Stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
mDataPollSender.StartPolling();
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
Get<Utils::SupervisionListener>().Start();
|
||||
#endif
|
||||
Get<SupervisionListener>().Start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1301,9 +1297,7 @@ void MeshForwarder::HandleReceivedFrame(Mac::RxFrame &aFrame)
|
||||
|
||||
frameData.Init(aFrame.GetPayload(), aFrame.GetPayloadLength());
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
Get<Utils::SupervisionListener>().UpdateOnReceive(macAddrs.mSource, linkInfo.IsLinkSecurityEnabled());
|
||||
#endif
|
||||
Get<SupervisionListener>().UpdateOnReceive(macAddrs.mSource, linkInfo.IsLinkSecurityEnabled());
|
||||
|
||||
switch (aFrame.GetType())
|
||||
{
|
||||
|
||||
@@ -122,15 +122,13 @@ Error MeshForwarder::SendMessage(Message &aMessage)
|
||||
break;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
case Message::kTypeSupervision:
|
||||
{
|
||||
Child *child = Get<Utils::ChildSupervisor>().GetDestination(aMessage);
|
||||
Child *child = Get<ChildSupervisor>().GetDestination(aMessage);
|
||||
OT_ASSERT((child != nullptr) && !child->IsRxOnWhenIdle());
|
||||
mIndirectSender.AddMessageForSleepyChild(aMessage, *child);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
aMessage.SetDirectTransmission();
|
||||
|
||||
@@ -1790,6 +1790,7 @@ Error Mle::SendChildIdRequest(void)
|
||||
SuccessOrExit(error = message->AppendModeTlv(mDeviceMode));
|
||||
SuccessOrExit(error = message->AppendTimeoutTlv(mTimeout));
|
||||
SuccessOrExit(error = message->AppendVersionTlv());
|
||||
SuccessOrExit(error = message->AppendSupervisionIntervalTlv(Get<SupervisionListener>().GetInterval()));
|
||||
|
||||
if (!IsFullThreadDevice())
|
||||
{
|
||||
@@ -2055,6 +2056,7 @@ Error Mle::SendChildUpdateRequest(bool aAppendChallenge, uint32_t aTimeout)
|
||||
SuccessOrExit(error = message->AppendSourceAddressTlv());
|
||||
SuccessOrExit(error = message->AppendLeaderDataTlv());
|
||||
SuccessOrExit(error = message->AppendTimeoutTlv(aTimeout));
|
||||
SuccessOrExit(error = message->AppendSupervisionIntervalTlv(Get<SupervisionListener>().GetInterval()));
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
if (Get<Mac::Mac>().IsCslEnabled())
|
||||
{
|
||||
@@ -2148,6 +2150,10 @@ Error Mle::SendChildUpdateResponse(const TlvList &aTlvList, const Challenge &aCh
|
||||
SuccessOrExit(error = message->AppendMleFrameCounterTlv());
|
||||
break;
|
||||
|
||||
case Tlv::kSupervisionInterval:
|
||||
SuccessOrExit(error = message->AppendSupervisionIntervalTlv(Get<SupervisionListener>().GetInterval()));
|
||||
break;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
case Tlv::kCslTimeout:
|
||||
if (Get<Mac::Mac>().IsCslEnabled())
|
||||
@@ -4707,6 +4713,11 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Mle::TxMessage::AppendSupervisionIntervalTlv(uint16_t aInterval)
|
||||
{
|
||||
return Tlv::Append<SupervisionIntervalTlv>(*this, aInterval);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
|
||||
Error Mle::TxMessage::AppendTimeRequestTlv(void)
|
||||
{
|
||||
|
||||
+15
-1
@@ -73,6 +73,8 @@ namespace ot {
|
||||
* @}
|
||||
*/
|
||||
|
||||
class SupervisionListener;
|
||||
|
||||
/**
|
||||
* @namespace ot::Mle
|
||||
*
|
||||
@@ -100,6 +102,7 @@ class Mle : public InstanceLocator, private NonCopyable
|
||||
{
|
||||
friend class DiscoverScanner;
|
||||
friend class ot::Notifier;
|
||||
friend class ot::SupervisionListener;
|
||||
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
|
||||
friend class ot::LinkMetrics::LinkMetrics;
|
||||
#endif
|
||||
@@ -842,7 +845,7 @@ protected:
|
||||
#endif
|
||||
};
|
||||
|
||||
static constexpr uint8_t kMaxTlvListSize = 16; ///< Maximum number of TLVs in a `TlvList`.
|
||||
static constexpr uint8_t kMaxTlvListSize = 32; ///< Maximum number of TLVs in a `TlvList`.
|
||||
|
||||
/**
|
||||
* This type represents a list of TLVs (array of TLV types).
|
||||
@@ -1117,6 +1120,17 @@ protected:
|
||||
*/
|
||||
Error AppendAddressRegistrationTlv(AddressRegistrationMode aMode = kAppendAllAddresses);
|
||||
|
||||
/**
|
||||
* This method appends a Supervision Interval TLV to the message.
|
||||
*
|
||||
* @param[in] aInterval The interval value.
|
||||
*
|
||||
* @retval kErrorNone Successfully appended the Supervision Interval TLV.
|
||||
* @retval kErrorNoBufs Insufficient buffers available to append the Supervision Interval TLV.
|
||||
*
|
||||
*/
|
||||
Error AppendSupervisionIntervalTlv(uint16_t aInterval);
|
||||
|
||||
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
|
||||
/**
|
||||
* This method appends a Time Request TLV to the message.
|
||||
|
||||
@@ -1995,6 +1995,7 @@ void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo)
|
||||
Child *child;
|
||||
Router *router;
|
||||
uint8_t numTlvs;
|
||||
uint16_t supervisionInterval;
|
||||
|
||||
Log(kMessageReceive, kTypeChildIdRequest, aRxInfo.mMessageInfo.GetPeerAddr());
|
||||
|
||||
@@ -2033,6 +2034,18 @@ void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo)
|
||||
// Timeout
|
||||
SuccessOrExit(error = Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout));
|
||||
|
||||
// Supervision interval
|
||||
switch (Tlv::Find<SupervisionIntervalTlv>(aRxInfo.mMessage, supervisionInterval))
|
||||
{
|
||||
case kErrorNone:
|
||||
break;
|
||||
case kErrorNotFound:
|
||||
supervisionInterval = (version <= kThreadVersion1p3) ? kChildSupervisionDefaultIntervalForOlderVersion : 0;
|
||||
break;
|
||||
default:
|
||||
ExitNow(error = kErrorParse);
|
||||
}
|
||||
|
||||
// TLV Request
|
||||
SuccessOrExit(error = aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList));
|
||||
|
||||
@@ -2114,6 +2127,7 @@ void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo)
|
||||
child->SetVersion(version);
|
||||
child->GetLinkInfo().AddRss(aRxInfo.mMessageInfo.GetThreadLinkInfo()->GetRss());
|
||||
child->SetTimeout(timeout);
|
||||
child->SetSupervisionInterval(supervisionInterval);
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
child->ClearLastRxFragmentTag();
|
||||
#endif
|
||||
@@ -2168,6 +2182,7 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo)
|
||||
Challenge challenge;
|
||||
LeaderData leaderData;
|
||||
uint32_t timeout;
|
||||
uint16_t supervisionInterval;
|
||||
Child *child;
|
||||
DeviceMode oldMode;
|
||||
TlvList requestedTlvList;
|
||||
@@ -2274,6 +2289,24 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo)
|
||||
ExitNow(error = kErrorParse);
|
||||
}
|
||||
|
||||
// Supervision interval
|
||||
switch (Tlv::Find<SupervisionIntervalTlv>(aRxInfo.mMessage, supervisionInterval))
|
||||
{
|
||||
case kErrorNone:
|
||||
tlvList.Add(Tlv::kSupervisionInterval);
|
||||
break;
|
||||
|
||||
case kErrorNotFound:
|
||||
supervisionInterval =
|
||||
(child->GetVersion() <= kThreadVersion1p3) ? kChildSupervisionDefaultIntervalForOlderVersion : 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
ExitNow(error = kErrorParse);
|
||||
}
|
||||
|
||||
child->SetSupervisionInterval(supervisionInterval);
|
||||
|
||||
// TLV Request
|
||||
switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList))
|
||||
{
|
||||
@@ -2473,6 +2506,21 @@ void MleRouter::HandleChildUpdateResponse(RxInfo &aRxInfo)
|
||||
ExitNow(error = kErrorParse);
|
||||
}
|
||||
|
||||
{
|
||||
uint16_t supervisionInterval;
|
||||
|
||||
switch (Tlv::Find<SupervisionIntervalTlv>(aRxInfo.mMessage, supervisionInterval))
|
||||
{
|
||||
case kErrorNone:
|
||||
child->SetSupervisionInterval(supervisionInterval);
|
||||
break;
|
||||
case kErrorNotFound:
|
||||
break;
|
||||
default:
|
||||
ExitNow(error = kErrorParse);
|
||||
}
|
||||
}
|
||||
|
||||
// IPv6 Address
|
||||
if (Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kAddressRegistration, addrOffset, addrLength) == kErrorNone)
|
||||
{
|
||||
@@ -3025,6 +3073,11 @@ void MleRouter::SendChildUpdateResponse(Child *aChild,
|
||||
case Tlv::kTimeout:
|
||||
SuccessOrExit(error = message->AppendTimeoutTlv(aChild->GetTimeout()));
|
||||
break;
|
||||
|
||||
case Tlv::kSupervisionInterval:
|
||||
SuccessOrExit(error = message->AppendSupervisionIntervalTlv(aChild->GetSupervisionInterval()));
|
||||
break;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
case Tlv::kCslClockAccuracy:
|
||||
if (!aChild->IsRxOnWhenIdle())
|
||||
|
||||
@@ -558,6 +558,9 @@ private:
|
||||
|
||||
static constexpr uint8_t kMinCriticalChildrenCount = 6;
|
||||
|
||||
static constexpr uint16_t kChildSupervisionDefaultIntervalForOlderVersion =
|
||||
OPENTHREAD_CONFIG_CHILD_SUPERVISION_OLDER_VERSION_CHILD_DEFAULT_INTERVAL;
|
||||
|
||||
void HandleDetachStart(void);
|
||||
void HandleChildStart(AttachMode aMode);
|
||||
void HandleLinkRequest(RxInfo &aRxInfo);
|
||||
|
||||
@@ -102,6 +102,7 @@ public:
|
||||
kActiveDataset = 24, ///< Active Operational Dataset TLV
|
||||
kPendingDataset = 25, ///< Pending Operational Dataset TLV
|
||||
kDiscovery = 26, ///< Thread Discovery TLV
|
||||
kSupervisionInterval = 27, ///< Supervision Interval TLV
|
||||
kCslChannel = 80, ///< CSL Channel TLV
|
||||
kCslTimeout = 85, ///< CSL Timeout TLV
|
||||
kCslClockAccuracy = 86, ///< CSL Clock Accuracy TLV
|
||||
@@ -230,6 +231,12 @@ typedef SimpleTlvInfo<Tlv::kActiveTimestamp, MeshCoP::Timestamp> ActiveTimestamp
|
||||
*/
|
||||
typedef SimpleTlvInfo<Tlv::kPendingTimestamp, MeshCoP::Timestamp> PendingTimestampTlv;
|
||||
|
||||
/**
|
||||
* This class defines Timeout TLV constants and types.
|
||||
*
|
||||
*/
|
||||
typedef UintTlvInfo<Tlv::kSupervisionInterval, uint16_t> SupervisionIntervalTlv;
|
||||
|
||||
/**
|
||||
* This class defines CSL Timeout TLV constants and types.
|
||||
*
|
||||
|
||||
@@ -243,23 +243,24 @@ const char *Neighbor::StateToString(State aState)
|
||||
void Child::Info::SetFrom(const Child &aChild)
|
||||
{
|
||||
Clear();
|
||||
mExtAddress = aChild.GetExtAddress();
|
||||
mTimeout = aChild.GetTimeout();
|
||||
mRloc16 = aChild.GetRloc16();
|
||||
mChildId = Mle::ChildIdFromRloc16(aChild.GetRloc16());
|
||||
mNetworkDataVersion = aChild.GetNetworkDataVersion();
|
||||
mAge = Time::MsecToSec(TimerMilli::GetNow() - aChild.GetLastHeard());
|
||||
mLinkQualityIn = aChild.GetLinkQualityIn();
|
||||
mAverageRssi = aChild.GetLinkInfo().GetAverageRss();
|
||||
mLastRssi = aChild.GetLinkInfo().GetLastRss();
|
||||
mFrameErrorRate = aChild.GetLinkInfo().GetFrameErrorRate();
|
||||
mMessageErrorRate = aChild.GetLinkInfo().GetMessageErrorRate();
|
||||
mQueuedMessageCnt = aChild.GetIndirectMessageCount();
|
||||
mVersion = ClampToUint8(aChild.GetVersion());
|
||||
mRxOnWhenIdle = aChild.IsRxOnWhenIdle();
|
||||
mFullThreadDevice = aChild.IsFullThreadDevice();
|
||||
mFullNetworkData = (aChild.GetNetworkDataType() == NetworkData::kFullSet);
|
||||
mIsStateRestoring = aChild.IsStateRestoring();
|
||||
mExtAddress = aChild.GetExtAddress();
|
||||
mTimeout = aChild.GetTimeout();
|
||||
mRloc16 = aChild.GetRloc16();
|
||||
mChildId = Mle::ChildIdFromRloc16(aChild.GetRloc16());
|
||||
mNetworkDataVersion = aChild.GetNetworkDataVersion();
|
||||
mAge = Time::MsecToSec(TimerMilli::GetNow() - aChild.GetLastHeard());
|
||||
mLinkQualityIn = aChild.GetLinkQualityIn();
|
||||
mAverageRssi = aChild.GetLinkInfo().GetAverageRss();
|
||||
mLastRssi = aChild.GetLinkInfo().GetLastRss();
|
||||
mFrameErrorRate = aChild.GetLinkInfo().GetFrameErrorRate();
|
||||
mMessageErrorRate = aChild.GetLinkInfo().GetMessageErrorRate();
|
||||
mQueuedMessageCnt = aChild.GetIndirectMessageCount();
|
||||
mVersion = ClampToUint8(aChild.GetVersion());
|
||||
mRxOnWhenIdle = aChild.IsRxOnWhenIdle();
|
||||
mFullThreadDevice = aChild.IsFullThreadDevice();
|
||||
mFullNetworkData = (aChild.GetNetworkDataType() == NetworkData::kFullSet);
|
||||
mIsStateRestoring = aChild.IsStateRestoring();
|
||||
mSupervisionInterval = aChild.GetSupervisionInterval();
|
||||
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
mIsCslSynced = aChild.IsCslSynchronized();
|
||||
#else
|
||||
|
||||
@@ -1210,7 +1210,21 @@ public:
|
||||
*/
|
||||
void SetRequestTlv(uint8_t aIndex, uint8_t aType) { mRequestTlvs[aIndex] = aType; }
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
/**
|
||||
* This method returns the supervision interval (in seconds).
|
||||
*
|
||||
* @returns The supervision interval (in seconds).
|
||||
*
|
||||
*/
|
||||
uint16_t GetSupervisionInterval(void) const { return mSupervisionInterval; }
|
||||
|
||||
/**
|
||||
* This method sets the supervision interval.
|
||||
*
|
||||
* @param[in] aInterval The supervision interval (in seconds).
|
||||
*
|
||||
*/
|
||||
void SetSupervisionInterval(uint16_t aInterval) { mSupervisionInterval = aInterval; }
|
||||
|
||||
/**
|
||||
* This method increments the number of seconds since last supervision of the child.
|
||||
@@ -1232,8 +1246,6 @@ public:
|
||||
*/
|
||||
void ResetSecondsSinceLastSupervision(void) { mSecondsSinceSupervision = 0; }
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
|
||||
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
|
||||
/**
|
||||
* This method returns MLR state of an IPv6 multicast address.
|
||||
@@ -1331,9 +1343,8 @@ private:
|
||||
uint8_t mAttachChallenge[Mle::kMaxChallengeSize]; ///< The challenge value
|
||||
};
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
uint16_t mSecondsSinceSupervision; ///< Number of seconds since last supervision of the child.
|
||||
#endif
|
||||
uint16_t mSupervisionInterval; // Supervision interval for the child (in sec).
|
||||
uint16_t mSecondsSinceSupervision; // Number of seconds since last supervision of the child.
|
||||
|
||||
static_assert(OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS < 8192, "mQueuedMessageCount cannot fit max required!");
|
||||
};
|
||||
|
||||
@@ -1867,9 +1867,7 @@ template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CAPS>(void)
|
||||
SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_JAM_DETECT));
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_CHILD_SUPERVISION));
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE
|
||||
SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_CHANNEL_MONITOR));
|
||||
|
||||
@@ -344,10 +344,8 @@ NcpBase::PropertyHandler NcpBase::FindGetPropertyHandler(spinel_prop_key_t aKey)
|
||||
OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_TIME_SYNC_PERIOD),
|
||||
OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_TIME_SYNC_XTAL_THRESHOLD),
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_CHILD_SUPERVISION_INTERVAL),
|
||||
OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_CHILD_SUPERVISION_CHECK_TIMEOUT),
|
||||
#endif
|
||||
#endif // OPENTHREAD_FTD
|
||||
#if OPENTHREAD_PLATFORM_POSIX
|
||||
OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_RCP_VERSION),
|
||||
@@ -606,10 +604,8 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey)
|
||||
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_TIME_SYNC_PERIOD),
|
||||
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_TIME_SYNC_XTAL_THRESHOLD),
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_CHILD_SUPERVISION_INTERVAL),
|
||||
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_CHILD_SUPERVISION_CHECK_TIMEOUT),
|
||||
#endif
|
||||
#endif // OPENTHREAD_FTD
|
||||
#if OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE
|
||||
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_SLAAC_ENABLED),
|
||||
|
||||
@@ -39,9 +39,7 @@
|
||||
#if OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE
|
||||
#include <openthread/channel_manager.h>
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
#include <openthread/child_supervision.h>
|
||||
#endif
|
||||
#include <openthread/dataset.h>
|
||||
#include <openthread/dataset_ftd.h>
|
||||
#include <openthread/diag.h>
|
||||
@@ -1223,8 +1221,6 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
|
||||
template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHILD_SUPERVISION_INTERVAL>(void)
|
||||
{
|
||||
return mEncoder.WriteUint16(otChildSupervisionGetInterval(mInstance));
|
||||
@@ -1242,8 +1238,6 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE
|
||||
|
||||
template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL>(void)
|
||||
|
||||
@@ -40,9 +40,7 @@
|
||||
#if OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE
|
||||
#include <openthread/channel_monitor.h>
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
#include <openthread/child_supervision.h>
|
||||
#endif
|
||||
#include <openthread/diag.h>
|
||||
#include <openthread/icmp6.h>
|
||||
#if OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE
|
||||
@@ -2391,8 +2389,6 @@ void NcpBase::HandleJamStateChange(bool aJamState)
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
|
||||
template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHILD_SUPERVISION_CHECK_TIMEOUT>(void)
|
||||
{
|
||||
return mEncoder.WriteUint16(otChildSupervisionGetCheckTimeout(mInstance));
|
||||
@@ -2410,8 +2406,6 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE
|
||||
|
||||
template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MONITOR_SAMPLE_INTERVAL>(void)
|
||||
|
||||
@@ -44,7 +44,6 @@ COAPS ?= 1
|
||||
COMMISSIONER ?= 1
|
||||
CHANNEL_MANAGER ?= 1
|
||||
CHANNEL_MONITOR ?= 1
|
||||
CHILD_SUPERVISION ?= 1
|
||||
DAEMON ?= 0
|
||||
DATASET_UPDATER ?= 1
|
||||
DHCP6_CLIENT ?= 1
|
||||
|
||||
@@ -45,7 +45,6 @@ set -euxo pipefail
|
||||
-DOT_BORDER_ROUTER=ON \
|
||||
-DOT_CHANNEL_MANAGER=ON \
|
||||
-DOT_CHANNEL_MONITOR=ON \
|
||||
-DOT_CHILD_SUPERVISION=ON \
|
||||
-DOT_COAP=ON \
|
||||
-DOT_COAPS=ON \
|
||||
-DOT_COAP_BLOCK=ON \
|
||||
|
||||
@@ -38,9 +38,9 @@ set rloc [get_rloc16]
|
||||
|
||||
switch_node 1
|
||||
send "child table\n"
|
||||
expect "| ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|D|N|Ver|CSL|QMsgCnt| Extended MAC |"
|
||||
expect "+-----+--------+------------+------------+-------+------+-+-+-+---+---+-------+------------------+"
|
||||
expect -re "\\| +(\\d+) \\| 0x$rloc \\| +\\d+ \\| +\\d+ \\| +\\d+ \\| +\\d+ \\|\\d\\|\\d\\|\\d\\| *\\d+\\| \\d \\| +\\d+ \\| $extaddr \\|"
|
||||
expect "| ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|D|N|Ver|CSL|QMsgCnt|Suprvsn| Extended MAC |"
|
||||
expect "+-----+--------+------------+------------+-------+------+-+-+-+---+---+-------+-------+------------------+"
|
||||
expect -re "\\| +(\\d+) \\| 0x$rloc \\| +\\d+ \\| +\\d+ \\| +\\d+ \\| +\\d+ \\|\\d\\|\\d\\|\\d\\| *\\d+\\| \\d \\| +\\d+ \\| +\\d+ \\| $extaddr \\|"
|
||||
set child_id $expect_out(1,string)
|
||||
expect_line "Done"
|
||||
send "child list\n"
|
||||
|
||||
@@ -154,6 +154,7 @@ EXTRA_DIST = \
|
||||
test_anycast.py \
|
||||
test_anycast_locator.py \
|
||||
test_br_upgrade_router_role.py \
|
||||
test_child_supervision.py \
|
||||
test_coap.py \
|
||||
test_coap_block.py \
|
||||
test_coap_observe.py \
|
||||
@@ -236,6 +237,7 @@ check_SCRIPTS = \
|
||||
test_anycast.py \
|
||||
test_anycast_locator.py \
|
||||
test_br_upgrade_router_role.py \
|
||||
test_child_supervision.py \
|
||||
test_coap.py \
|
||||
test_coap_block.py \
|
||||
test_coap_observe.py \
|
||||
|
||||
@@ -90,6 +90,7 @@ class TlvType(IntEnum):
|
||||
ACTIVE_OPERATIONAL_DATASET = 24
|
||||
PENDING_OPERATIONAL_DATASET = 25
|
||||
THREAD_DISCOVERY = 26
|
||||
SUPERVISION_INTERVAL = 27
|
||||
CSL_CHANNEL = 80
|
||||
CSL_SYNCHRONIZED_TIMEOUT = 85
|
||||
CSL_CLOCK_ACCURACY = 86
|
||||
|
||||
@@ -1721,6 +1721,30 @@ class NodeImpl:
|
||||
self.send_command('pollperiod %d' % pollperiod)
|
||||
self._expect_done()
|
||||
|
||||
def get_child_supervision_interval(self):
|
||||
self.send_command('childsupervision interval')
|
||||
return self._expect_result(r'\d+')
|
||||
|
||||
def set_child_supervision_interval(self, interval):
|
||||
self.send_command('childsupervision interval %d' % interval)
|
||||
self._expect_done()
|
||||
|
||||
def get_child_supervision_check_timeout(self):
|
||||
self.send_command('childsupervision checktimeout')
|
||||
return self._expect_result(r'\d+')
|
||||
|
||||
def set_child_supervision_check_timeout(self, timeout):
|
||||
self.send_command('childsupervision checktimeout %d' % timeout)
|
||||
self._expect_done()
|
||||
|
||||
def get_child_supervision_check_failure_counter(self):
|
||||
self.send_command('childsupervision failcounter')
|
||||
return self._expect_result(r'\d+')
|
||||
|
||||
def reset_child_supervision_check_failure_counter(self):
|
||||
self.send_command('childsupervision failcounter reset')
|
||||
self._expect_done()
|
||||
|
||||
def get_csl_info(self):
|
||||
self.send_command('csl')
|
||||
self._expect_done()
|
||||
@@ -1928,10 +1952,10 @@ class NodeImpl:
|
||||
|
||||
#
|
||||
# Example output:
|
||||
# | ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|D|N|Ver|CSL|QMsgCnt| Extended MAC |
|
||||
# +-----+--------+------------+------------+-------+------+-+-+-+---+---+-------+------------------+
|
||||
# | 1 | 0xc801 | 240 | 24 | 3 | 131 |1|0|0| 3| 0 | 0 | 4ecede68435358ac |
|
||||
# | 2 | 0xc802 | 240 | 2 | 3 | 131 |0|0|0| 3| 1 | 0 | a672a601d2ce37d8 |
|
||||
# | ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|D|N|Ver|CSL|QMsgCnt|Suprvsn| Extended MAC |
|
||||
# +-----+--------+------------+------------+-------+------+-+-+-+---+---+-------+-------+------------------+
|
||||
# | 1 | 0xc801 | 240 | 24 | 3 | 131 |1|0|0| 3| 0 | 0 | 129 | 4ecede68435358ac |
|
||||
# | 2 | 0xc802 | 240 | 2 | 3 | 131 |0|0|0| 3| 1 | 0 | 0 | a672a601d2ce37d8 |
|
||||
# Done
|
||||
#
|
||||
|
||||
@@ -1962,6 +1986,7 @@ class NodeImpl:
|
||||
'ver': int(col('Ver')),
|
||||
'csl': bool(int(col('CSL'))),
|
||||
'qmsgcnt': int(col('QMsgCnt')),
|
||||
'suprvsn': int(col('Suprvsn'))
|
||||
}
|
||||
|
||||
return table
|
||||
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2022, 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 thread_cert
|
||||
|
||||
# Test description:
|
||||
#
|
||||
# This test verifies behavior child supervision.
|
||||
#
|
||||
#
|
||||
# Topology:
|
||||
#
|
||||
# Parent (leader)
|
||||
# |
|
||||
# |
|
||||
# Child (sleepy).
|
||||
|
||||
PARENT = 1
|
||||
CHILD = 2
|
||||
|
||||
|
||||
class ChildSupervision(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
SUPPORT_NCP = False
|
||||
|
||||
TOPOLOGY = {
|
||||
PARENT: {
|
||||
'name': 'PARENT',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
CHILD: {
|
||||
'name': 'CHILD',
|
||||
'is_mtd': True,
|
||||
'mode': 'n',
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
parent = self.nodes[PARENT]
|
||||
child = self.nodes[CHILD]
|
||||
|
||||
# Form the network.
|
||||
|
||||
parent.start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(parent.get_state(), 'leader')
|
||||
|
||||
child.start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(child.get_state(), 'child')
|
||||
child.set_pollperiod(500)
|
||||
|
||||
self.assertEqual(int(child.get_child_supervision_check_failure_counter()), 0)
|
||||
|
||||
# Check the parent's child table.
|
||||
|
||||
table = parent.get_child_table()
|
||||
self.assertEqual(len(table), 1)
|
||||
self.assertEqual(table[1]['suprvsn'], int(child.get_child_supervision_interval()))
|
||||
|
||||
# Change the supervision interval on child. This should trigger an
|
||||
# MLE Child Update exchange from child to parent so to inform parent
|
||||
# about the change. Verify that parent is notified by checking the
|
||||
# parent's child table.
|
||||
|
||||
child.set_child_supervision_interval(20)
|
||||
|
||||
self.simulator.go(2)
|
||||
|
||||
self.assertEqual(int(child.get_child_supervision_interval()), 20)
|
||||
table = parent.get_child_table()
|
||||
self.assertEqual(len(table), 1)
|
||||
self.assertEqual(table[1]['suprvsn'], int(child.get_child_supervision_interval()))
|
||||
|
||||
# Change supervision check timeout on the child.
|
||||
|
||||
child.set_child_supervision_check_timeout(25)
|
||||
self.assertEqual(int(child.get_child_supervision_check_timeout()), 25)
|
||||
|
||||
# Wait for multiple supervision intervals and ensure that child
|
||||
# stays attached (child supervision working as expected).
|
||||
|
||||
self.simulator.go(110)
|
||||
|
||||
self.assertEqual(child.get_state(), 'child')
|
||||
table = parent.get_child_table()
|
||||
self.assertEqual(len(table), 1)
|
||||
self.assertEqual(int(child.get_child_supervision_check_failure_counter()), 0)
|
||||
|
||||
# Disable supervision check on child.
|
||||
|
||||
child.set_child_supervision_check_timeout(0)
|
||||
|
||||
# Enable allowlist on parent without adding the child. After child
|
||||
# timeout expires, the parent should remove the child from its child
|
||||
# table.
|
||||
|
||||
parent.clear_allowlist()
|
||||
parent.enable_allowlist()
|
||||
|
||||
table = parent.get_child_table()
|
||||
child_timeout = table[1]['timeout']
|
||||
|
||||
self.simulator.go(child_timeout + 1)
|
||||
table = parent.get_child_table()
|
||||
self.assertEqual(len(table), 0)
|
||||
|
||||
# Since supervision check is disabled on the child, it should
|
||||
# continue to stay attached to parent (since data polls are acked by
|
||||
# radio driver).
|
||||
|
||||
self.assertEqual(child.get_state(), 'child')
|
||||
self.assertEqual(int(child.get_child_supervision_check_failure_counter()), 0)
|
||||
|
||||
# Re-enable supervision check on child. After the check timeout the
|
||||
# child must try to exchange "Child Update" messages with parent and
|
||||
# then detect that parent is not responding and detach.
|
||||
|
||||
child.set_child_supervision_check_timeout(25)
|
||||
|
||||
self.simulator.go(35)
|
||||
self.assertEqual(child.get_state(), 'detached')
|
||||
self.assertTrue(int(child.get_child_supervision_check_failure_counter()) > 0)
|
||||
|
||||
# Disable allowlist on parent. Child should be able to attach again.
|
||||
|
||||
parent.disable_allowlist()
|
||||
self.simulator.go(30)
|
||||
self.assertEqual(child.get_state(), 'child')
|
||||
child.reset_child_supervision_check_failure_counter()
|
||||
self.assertEqual(int(child.get_child_supervision_check_failure_counter()), 0)
|
||||
|
||||
# Set the supervision interval to zero on child (child is asking
|
||||
# parent not to supervise it anymore). This practically behaves
|
||||
# the same as if parent does not support child supervision
|
||||
# feature.
|
||||
|
||||
child.set_child_supervision_interval(0)
|
||||
child.set_child_supervision_check_timeout(25)
|
||||
self.simulator.go(2)
|
||||
|
||||
self.assertEqual(int(child.get_child_supervision_interval()), 0)
|
||||
self.assertEqual(int(child.get_child_supervision_check_timeout()), 25)
|
||||
|
||||
table = parent.get_child_table()
|
||||
self.assertEqual(len(table), 1)
|
||||
self.assertEqual(table[2]['suprvsn'], int(child.get_child_supervision_interval()))
|
||||
|
||||
# Wait for multiple check timeouts. The child should still stay
|
||||
# attached to parent.
|
||||
|
||||
self.simulator.go(100)
|
||||
self.assertEqual(child.get_state(), 'child')
|
||||
self.assertEqual(len(parent.get_child_table()), 1)
|
||||
self.assertTrue(int(child.get_child_supervision_check_failure_counter()) > 0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,180 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2018, 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 time
|
||||
import wpan
|
||||
from wpan import verify
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Test description: Child Supervision feature
|
||||
#
|
||||
# This test covers the behavior of Child Supervision feature.
|
||||
#
|
||||
# This test uses MAC allowlisting to emulate the situation where a child is
|
||||
# removed from parent's child table while the child continues to stay attached
|
||||
# to the parent (since data polls from child are acked at radio platform layer).
|
||||
# Specifically the test verifies that once supervision check is enabled on the
|
||||
# child, the child detects that it is no longer present in the parent's table
|
||||
# and tries to re-attach.
|
||||
|
||||
# The test verifies the behavior of both parent and child, when supervision is
|
||||
# enabled. It verifies that parent is periodically sending supervision messages
|
||||
# to the child and that the child is monitoring the messages.
|
||||
#
|
||||
# This test also indirectly verifies the child timeout on parent.
|
||||
#
|
||||
|
||||
test_name = __file__[:-3] if __file__.endswith('.py') else __file__
|
||||
print('-' * 120)
|
||||
print('Starting \'{}\''.format(test_name))
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Creating `wpan.Nodes` instances
|
||||
|
||||
speedup = 2
|
||||
wpan.Node.set_time_speedup_factor(speedup)
|
||||
|
||||
parent = wpan.Node()
|
||||
child = wpan.Node()
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Init all nodes
|
||||
|
||||
wpan.Node.init_all_nodes()
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Build network topology
|
||||
|
||||
CHILD_TIMEOUT = 6
|
||||
CHILD_SUPERVISION_CHECK_TIMEOUT = 2
|
||||
PARENT_SUPERVISION_INTERVAL = 1
|
||||
|
||||
child.set(wpan.WPAN_POLL_INTERVAL, '500')
|
||||
child.set(wpan.WPAN_THREAD_CHILD_TIMEOUT, str(CHILD_TIMEOUT))
|
||||
|
||||
parent.form("child-sup")
|
||||
child.join_node(parent, wpan.JOIN_TYPE_SLEEPY_END_DEVICE)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Test implementation
|
||||
|
||||
# Disable child supervision on child and parent
|
||||
parent.set(wpan.WPAN_CHILD_SUPERVISION_INTERVAL, '0')
|
||||
child.set(wpan.WPAN_CHILD_SUPERVISION_CHECK_TIMEOUT, '0')
|
||||
verify(int(parent.get(wpan.WPAN_CHILD_SUPERVISION_INTERVAL), 0) == 0)
|
||||
verify(int(child.get(wpan.WPAN_CHILD_SUPERVISION_CHECK_TIMEOUT), 0) == 0)
|
||||
|
||||
# Check that the child is associated and has correct timeout
|
||||
verify(child.is_associated())
|
||||
verify(int(child.get(wpan.WPAN_THREAD_CHILD_TIMEOUT), 0) == CHILD_TIMEOUT)
|
||||
|
||||
# Verify the child table on parent contains the child with correct timeout
|
||||
child_table = wpan.parse_child_table_result(parent.get(wpan.WPAN_THREAD_CHILD_TABLE))
|
||||
verify(len(child_table) == 1)
|
||||
verify(int(child_table[0].timeout, 0) == CHILD_TIMEOUT)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
# Enabling allowlisting on parent
|
||||
#
|
||||
# Since child is not in parent's allowlist, the data polls from child
|
||||
# should be rejected and the child should be removed from parent's
|
||||
# child table after timeout. The child however should continue to
|
||||
# stay attached (since data polls are acked by radio driver) and
|
||||
# supervision check is disabled on the child.
|
||||
|
||||
parent.set(wpan.WPAN_MAC_ALLOWLIST_ENABLED, '1')
|
||||
|
||||
|
||||
def check_child_is_removed_from_parent_child_table():
|
||||
child_table = wpan.parse_child_table_result(parent.get(wpan.WPAN_THREAD_CHILD_TABLE))
|
||||
verify(len(child_table) == 0)
|
||||
|
||||
|
||||
# wait till child is removed from parent's child table
|
||||
# after this child should still be associated
|
||||
wpan.verify_within(check_child_is_removed_from_parent_child_table, CHILD_TIMEOUT / speedup + 2)
|
||||
verify(child.is_associated())
|
||||
|
||||
# Enable supervision check on child and expect the child to
|
||||
# become detached after the check timeout
|
||||
|
||||
child.set(
|
||||
wpan.WPAN_CHILD_SUPERVISION_CHECK_TIMEOUT,
|
||||
str(CHILD_SUPERVISION_CHECK_TIMEOUT),
|
||||
)
|
||||
|
||||
|
||||
def check_child_is_detached():
|
||||
verify(not child.is_associated())
|
||||
|
||||
|
||||
wpan.verify_within(check_child_is_detached, CHILD_SUPERVISION_CHECK_TIMEOUT / speedup + 8)
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
# Enable child supervision on parent and disable allowlisting
|
||||
|
||||
parent.set(wpan.WPAN_CHILD_SUPERVISION_INTERVAL, str(PARENT_SUPERVISION_INTERVAL))
|
||||
parent.set(wpan.WPAN_MAC_ALLOWLIST_ENABLED, '0')
|
||||
|
||||
# Wait for the child to attach back
|
||||
|
||||
|
||||
def check_child_is_attached():
|
||||
verify(child.is_associated())
|
||||
|
||||
|
||||
wpan.verify_within(check_child_is_attached, 5)
|
||||
|
||||
# MAC counters are used to verify the child supervision behavior.
|
||||
|
||||
parent_unicast_tx_count = int(parent.get("NCP:Counter:TX_PKT_UNICAST"), 0)
|
||||
|
||||
time.sleep(PARENT_SUPERVISION_INTERVAL * 1.2 / speedup)
|
||||
|
||||
# To verify that the parent is indeed sending empty "supervision"
|
||||
# messages to its child, MAC counter for number of unicast tx is
|
||||
# used. Note that supervision interval on parent is set to 1 sec.
|
||||
|
||||
verify(int(parent.get("NCP:Counter:TX_PKT_UNICAST"), 0) >= parent_unicast_tx_count + 1)
|
||||
|
||||
verify(child.is_associated())
|
||||
|
||||
# Disable child supervision on parent
|
||||
parent.set(wpan.WPAN_CHILD_SUPERVISION_INTERVAL, '0')
|
||||
|
||||
time.sleep(CHILD_SUPERVISION_CHECK_TIMEOUT * 3 / speedup)
|
||||
verify(child.is_associated())
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Test finished
|
||||
|
||||
wpan.Node.finalize_all_nodes()
|
||||
|
||||
print('\'{}\' passed.'.format(test_name))
|
||||
@@ -435,14 +435,6 @@
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_CHANNEL_MANAGER_THRESHOLD_TO_CHANGE_CHANNEL (0xffff * 10 / 100)
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
|
||||
*
|
||||
* Define to 1 to enable Child Supervision support.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE 1
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_TMF_PENDING_DATASET_MINIMUM_DELAY
|
||||
*
|
||||
|
||||
@@ -222,7 +222,6 @@ run ncp/test-014-ip6-address-add.py
|
||||
run ncp/test-015-same-prefix-on-multiple-nodes.py
|
||||
run ncp/test-016-neighbor-table.py
|
||||
run ncp/test-017-parent-reset-child-recovery.py
|
||||
run ncp/test-018-child-supervision.py
|
||||
run ncp/test-019-inform-previous-parent.py
|
||||
run ncp/test-020-router-table.py
|
||||
run ncp/test-021-address-cache-table.py
|
||||
|
||||
Reference in New Issue
Block a user