diff --git a/Android.mk b/Android.mk index 165d14d40..1dcec863f 100644 --- a/Android.mk +++ b/Android.mk @@ -372,6 +372,7 @@ LOCAL_SRC_FILES := \ src/cli/cli_console.cpp \ src/cli/cli_dataset.cpp \ src/cli/cli_joiner.cpp \ + src/cli/cli_network_data.cpp \ src/cli/cli_uart.cpp \ src/cli/cli_udp.cpp \ $(NULL) diff --git a/examples/platforms/cc1352/README.md b/examples/platforms/cc1352/README.md index 76a40ca60..be5bc7a00 100644 --- a/examples/platforms/cc1352/README.md +++ b/examples/platforms/cc1352/README.md @@ -80,7 +80,7 @@ keysequence leaderweight masterkey mode -netdataregister +netdata register networkidtimeout networkname panid diff --git a/examples/platforms/cc2538/README.md b/examples/platforms/cc2538/README.md index 0106a4730..60cd922c7 100644 --- a/examples/platforms/cc2538/README.md +++ b/examples/platforms/cc2538/README.md @@ -95,7 +95,7 @@ keysequence leaderweight masterkey mode -netdataregister +netdata register networkidtimeout networkname panid diff --git a/examples/platforms/cc2650/README.md b/examples/platforms/cc2650/README.md index f3009a92a..48141a150 100644 --- a/examples/platforms/cc2650/README.md +++ b/examples/platforms/cc2650/README.md @@ -96,7 +96,7 @@ keysequence leaderweight masterkey mode -netdataregister +netdata register networkidtimeout networkname panid diff --git a/examples/platforms/cc2652/README.md b/examples/platforms/cc2652/README.md index c87b8518f..e81bfd4b7 100644 --- a/examples/platforms/cc2652/README.md +++ b/examples/platforms/cc2652/README.md @@ -80,7 +80,7 @@ keysequence leaderweight masterkey mode -netdataregister +netdata register networkidtimeout networkname panid diff --git a/examples/platforms/efr32mg1/README.md b/examples/platforms/efr32mg1/README.md index 4cc416ff5..0aa543e05 100644 --- a/examples/platforms/efr32mg1/README.md +++ b/examples/platforms/efr32mg1/README.md @@ -138,7 +138,7 @@ In the J-Link Device drop-down list select the serial number of the device to fl leaderweight masterkey mode - netdataregister + netdata register networkidtimeout networkname panid diff --git a/examples/platforms/efr32mg12/README.md b/examples/platforms/efr32mg12/README.md index 726632d6f..1facf1fa7 100644 --- a/examples/platforms/efr32mg12/README.md +++ b/examples/platforms/efr32mg12/README.md @@ -151,7 +151,7 @@ In the J-Link Device drop-down list select the serial number of the device to fl leaderweight masterkey mode - netdataregister + netdata register networkidtimeout networkname panid diff --git a/examples/platforms/efr32mg13/README.md b/examples/platforms/efr32mg13/README.md index fe5058f13..d38af3f97 100644 --- a/examples/platforms/efr32mg13/README.md +++ b/examples/platforms/efr32mg13/README.md @@ -144,7 +144,7 @@ In the J-Link Device drop-down list select the serial number of the device to fl leaderweight masterkey mode - netdataregister + netdata register networkidtimeout networkname panid diff --git a/examples/platforms/efr32mg21/README.md b/examples/platforms/efr32mg21/README.md index f7ad90815..b3457a297 100644 --- a/examples/platforms/efr32mg21/README.md +++ b/examples/platforms/efr32mg21/README.md @@ -103,7 +103,7 @@ keysequence leaderweight masterkey mode -netdataregister +netdata register networkidtimeout networkname panid diff --git a/examples/platforms/gp712/README.md b/examples/platforms/gp712/README.md index f9c652650..f8d3aec00 100644 --- a/examples/platforms/gp712/README.md +++ b/examples/platforms/gp712/README.md @@ -54,7 +54,7 @@ keysequence leaderweight masterkey mode -netdataregister +netdata register networkidtimeout networkname panid diff --git a/examples/platforms/samr21/README.md b/examples/platforms/samr21/README.md index 6fc42009a..e5b9dfe60 100644 --- a/examples/platforms/samr21/README.md +++ b/examples/platforms/samr21/README.md @@ -97,7 +97,7 @@ $ (gdb) c leaderweight masterkey mode - netdataregister + netdata register networkidtimeout networkname panid diff --git a/examples/platforms/simulation/README.md b/examples/platforms/simulation/README.md index 4f13c135e..679e4d1bc 100644 --- a/examples/platforms/simulation/README.md +++ b/examples/platforms/simulation/README.md @@ -54,7 +54,7 @@ keysequence leaderweight masterkey mode -netdataregister +netdata register networkidtimeout networkname panid diff --git a/src/cli/BUILD.gn b/src/cli/BUILD.gn index 7c72c6308..1eeb4aa37 100644 --- a/src/cli/BUILD.gn +++ b/src/cli/BUILD.gn @@ -43,6 +43,8 @@ openthread_cli_sources = [ "cli_dataset.hpp", "cli_joiner.cpp", "cli_joiner.hpp", + "cli_network_data.cpp", + "cli_network_data.hpp", "cli_uart.cpp", "cli_uart.hpp", "cli_udp.cpp", diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index 2122c202a..55db02599 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -78,6 +78,7 @@ set(COMMON_SOURCES cli_console.cpp cli_dataset.cpp cli_joiner.cpp + cli_network_data.cpp cli_uart.cpp cli_udp.cpp ) diff --git a/src/cli/Makefile.am b/src/cli/Makefile.am index fb881d9d5..b1b89c221 100644 --- a/src/cli/Makefile.am +++ b/src/cli/Makefile.am @@ -157,6 +157,7 @@ SOURCES_COMMON = \ cli_console.cpp \ cli_dataset.cpp \ cli_joiner.cpp \ + cli_network_data.cpp \ cli_uart.cpp \ cli_udp.cpp \ $(NULL) @@ -178,6 +179,7 @@ noinst_HEADERS = \ cli_console.hpp \ cli_dataset.hpp \ cli_joiner.hpp \ + cli_network_data.hpp \ cli_uart.hpp \ cli_udp.hpp \ x509_cert_key.hpp \ diff --git a/src/cli/README.md b/src/cli/README.md index 6fb528df1..345e09116 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -63,9 +63,7 @@ Done - [mlr](#mlr-reg-ipaddr--timeout) - [mode](#mode) - [neighbor](#neighbor-list) -- [netdata](#netdata-steeringdata-check-eui64discerner) -- [netdataregister](#netdataregister) -- [netdatashow](#netdatashow) +- [netdata](README_NETDATA.md) - [netstat](#netstat) - [networkdiagnostic](#networkdiagnostic-get-addr-type-) - [networkidtimeout](#networkidtimeout) @@ -1177,41 +1175,6 @@ Print table of neighbors. Done ``` -### netdata steeringdata check \|\ - -Check whether the steering data includes a joiner. - -- eui64: The IEEE EUI-64 of the Joiner. -- discerner: The Joiner discerner in format `number/length`. - -```bash -> netdata steeringdata check d45e64fa83f81cf7 -Done -> netdata steeringdata check 0xabc/12 -Done -> netdata steeringdata check 0xdef/12 -Error 23: NotFound -``` - -### netdataregister - -Register local network data with Thread Leader. - -```bash -> netdataregister -Done -``` - -### netdatashow - -Show Thread Leader network data. - -```bash -> netdatashow -08040b020000 -Done -``` - ### netstat List all UDP sockets. @@ -2088,7 +2051,7 @@ Factory Diagnostics module is enabled only when building OpenThread with `OPENTH ### service -Module for controlling service registration in Network Data. Each change in service registration must be sent to leader by `netdataregister` command before taking effect. +Module for controlling service registration in Network Data. Each change in service registration must be sent to leader by `netdata register` command before taking effect. ### service add \ \ \ @@ -2097,7 +2060,7 @@ Add service to the Network Data. ```bash > service add 44970 foo bar Done -> netdataregister +> netdata register Done > ipaddr fdde:ad00:beef:0:0:ff:fe00:fc10 @@ -2115,7 +2078,7 @@ Remove service from Network Data. ```bash > service remove 44970 foo Done -> netdataregister +> netdata register Done > ipaddr fdde:ad00:beef:0:0:ff:fe00:fc00 diff --git a/src/cli/README_NETDATA.md b/src/cli/README_NETDATA.md new file mode 100644 index 000000000..7bebc617a --- /dev/null +++ b/src/cli/README_NETDATA.md @@ -0,0 +1,214 @@ +# OpenThread CLI - Network Data + +## Overview + +Thread Network Data contains information about Border Routers and other servers available in the Thread network. Border Routers and devices offering services register their information with the Leader. The Leader collects and structures this information within the Thread Network Data and distributes the information to all devices in the Thread Network. + +Border Routers may register prefixes assigned to the Thread Network and prefixes that they offer routes for. Services may register any information relevant to the service itself. + +Border Router and service information may be stable or temporary. Stable Thread Network Data is distributed to all devices, including Sleepy End Devices (SEDs). Temporary Network Data is distributed to all nodes except SEDs. + +## Quick Start + +### Form Network and Configure Prefix + +1. Generate and view new network configuration. + + ```bash + > dataset init new + Done + > dataset + Active Timestamp: 1 + Channel: 13 + Channel Mask: 0x07fff800 + Ext PAN ID: d63e8e3e495ebbc3 + Mesh Local Prefix: fd3d:b50b:f96d:722d::/64 + Master Key: dfd34f0f05cad978ec4e32b0413038ff + Network Name: OpenThread-8f28 + PAN ID: 0x8f28 + PSKc: c23a76e98f1a6483639b1ac1271e2e27 + Security Policy: 0, onrcb + Done + ``` + +2. Commit new dataset to the Active Operational Dataset in non-volatile storage. + + ```bash + dataset commit active + Done + ``` + +3. Enable Thread interface + + ```bash + > ifconfig up + Done + > thread start + Done + ``` + +4. Observe IPv6 addresses assigned to the Thread inteface. + + ```bash + > ipaddr + fd3d:b50b:f96d:722d:0:ff:fe00:fc00 + fd3d:b50b:f96d:722d:0:ff:fe00:dc00 + fd3d:b50b:f96d:722d:393c:462d:e8d2:db32 + fe80:0:0:0:a40b:197f:593d:ca61 + Done + ``` + +5. Register an IPv6 prefix assigned to the Thread network. + + ```bash + > prefix add fd00:dead:beef:cafe::/64 paros + Done + > netdata register + Done + ``` + +6. Observe Thread Network Data. + + ```bash + > netdata show + Prefixes: + fd00:dead:beef:cafe::/64 paros med dc00 + Routes: + Services: + Done + ``` + +7. Observe IPv6 addresses assigned to the Thread interface. + + ```bash + > ipaddr + fd00:dead:beef:cafe:4da8:5234:4aa2:4cfa + fd3d:b50b:f96d:722d:0:ff:fe00:fc00 + fd3d:b50b:f96d:722d:0:ff:fe00:dc00 + fd3d:b50b:f96d:722d:393c:462d:e8d2:db32 + fe80:0:0:0:a40b:197f:593d:ca61 + Done + ``` + +### Attach to Existing Network + +Only the Master Key is required for a device to attach to a Thread network. + +While not required, specifying the channel avoids the need to search across multiple channels, improving both latency and efficiency of the attach process. + +After the device successfully attaches to a Thread network, the device will retrieve the complete Active Operational Dataset. + +1. Create a partial Active Operational Dataset. + + ```bash + > dataset masterkey dfd34f0f05cad978ec4e32b0413038ff + Done + > dataset commit active + Done + ``` + +2. Enable Thread interface. + + ```bash + > ifconfig up + Done + > thread start + Done + ``` + +3. After attaching, observe Thread Network Data. + + ```bash + > netdata show + Prefixes: + fd00:dead:beef:cafe::/64 paros med dc00 + Routes: + Services: + Done + ``` + +4. Observe IPv6 addresses assigned to the Thread interface. + + ```bash + > ipaddr + fd00:dead:beef:cafe:4da8:5234:4aa2:4cfa + fd3d:b50b:f96d:722d:0:ff:fe00:fc00 + fd3d:b50b:f96d:722d:0:ff:fe00:dc00 + fd3d:b50b:f96d:722d:393c:462d:e8d2:db32 + fe80:0:0:0:a40b:197f:593d:ca61 + Done + ``` + +## Command List + +- [help](#help) +- [register](#register) +- [show](#show) +- [steeringdata](#steeringdata-check-eui64discerner) + +## Command Details + +### help + +Usage: `netdata help` + +Print netdata help menu. + +```bash +> netdata help +help +register +show +steeringdata +Done +``` + +### register + +Usage: `dataset register` + +Register configured prefixes, routes, and services with the Leader. + +```bash +> netdata register +Done +``` + +### show + +Usage: `dataset show [-x]` + +Print Network Data received from the Leader. + +```bash +> netdata show +Prefixes: +fd00:dead:beef:cafe::/64 paros med dc00 +Routes: +Services: +Done +``` + +Print Network Data as hex-encoded TLVs. + +```bash +> netdata show -x +08040b02174703140040fd00deadbeefcafe0504dc00330007021140 +Done +``` + +### netdata steeringdata check \|\ + +Check whether the steering data includes a joiner. + +- eui64: The IEEE EUI-64 of the Joiner. +- discerner: The Joiner discerner in format `number/length`. + +```bash +> netdata steeringdata check d45e64fa83f81cf7 +Done +> netdata steeringdata check 0xabc/12 +Done +> netdata steeringdata check 0xdef/12 +Error 23: NotFound +``` diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 2009fe4a7..6db23edde 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -41,7 +41,6 @@ #include #include #include -#include #include #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE #include @@ -122,8 +121,9 @@ Interpreter::Interpreter(Instance *aInstance) #if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE , mSntpQueryingInProgress(false) #endif - , mUdp(*this) , mDataset(*this) + , mNetworkData(*this) + , mUdp(*this) #if OPENTHREAD_CONFIG_COAP_API_ENABLE , mCoap(*this) #endif @@ -2132,24 +2132,6 @@ exit: } #endif -void Interpreter::ProcessNetworkDataShow(uint8_t aArgsLength, char *aArgs[]) -{ - OT_UNUSED_VARIABLE(aArgsLength); - OT_UNUSED_VARIABLE(aArgs); - - otError error = OT_ERROR_NONE; - uint8_t data[255]; - uint8_t len = sizeof(data); - - SuccessOrExit(error = otNetDataGet(mInstance, false, data, &len)); - - OutputBytes(data, static_cast(len)); - OutputLine(""); - -exit: - OutputResult(error); -} - #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE void Interpreter::ProcessNetif(uint8_t aArgsLength, char *aArgs[]) { @@ -2232,13 +2214,28 @@ exit: } #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE +otError Interpreter::ProcessServiceList(void) +{ + otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; + otServiceConfig config; + + while (otServerGetNextService(mInstance, &iterator, &config) == OT_ERROR_NONE) + { + mNetworkData.OutputService(config); + } + + return OT_ERROR_NONE; +} + void Interpreter::ProcessService(uint8_t aArgsLength, char *aArgs[]) { otError error = OT_ERROR_NONE; - VerifyOrExit(aArgsLength > 0, error = OT_ERROR_INVALID_ARGS); - - if (strcmp(aArgs[0], "add") == 0) + if (aArgsLength == 0) + { + SuccessOrExit(error = ProcessServiceList()); + } + else if (strcmp(aArgs[0], "add") == 0) { otServiceConfig cfg; long enterpriseNumber; @@ -2288,63 +2285,10 @@ exit: void Interpreter::ProcessNetworkData(uint8_t aArgsLength, char *aArgs[]) { otError error; - - if (aArgsLength > 2 && strcmp(aArgs[0], "steeringdata") == 0) - { - if (strcmp(aArgs[1], "check") == 0) - { - otExtAddress addr; - otJoinerDiscerner discerner; - - discerner.mLength = 0; - - error = Interpreter::ParseJoinerDiscerner(aArgs[2], discerner); - - if (error == OT_ERROR_NOT_FOUND) - { - VerifyOrExit(Interpreter::Hex2Bin(aArgs[2], addr.m8, sizeof(addr)) == sizeof(addr), - error = OT_ERROR_INVALID_ARGS); - } - else if (error != OT_ERROR_NONE) - { - ExitNow(); - } - - if (discerner.mLength) - { - ExitNow(error = otNetDataSteeringDataCheckJoinerWithDiscerner(mInstance, &discerner)); - } - else - { - ExitNow(error = otNetDataSteeringDataCheckJoiner(mInstance, &addr)); - } - } - } - - error = OT_ERROR_INVALID_COMMAND; - -exit: + error = mNetworkData.Process(aArgsLength, aArgs); OutputResult(error); } -#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE -void Interpreter::ProcessNetworkDataRegister(uint8_t aArgsLength, char *aArgs[]) -{ - OT_UNUSED_VARIABLE(aArgsLength); - OT_UNUSED_VARIABLE(aArgs); - - otError error = OT_ERROR_NONE; -#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE - SuccessOrExit(error = otBorderRouterRegister(mInstance)); -#else - SuccessOrExit(error = otServerRegister(mInstance)); -#endif - -exit: - OutputResult(error); -} -#endif - #if OPENTHREAD_FTD void Interpreter::ProcessNetworkIdTimeout(uint8_t aArgsLength, char *aArgs[]) { @@ -2922,75 +2866,6 @@ exit: return error; } -void Interpreter::OutputPrefix(otBorderRouterConfig &aConfig) -{ - OutputFormat("%x:%x:%x:%x::/%d ", HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[0]), - HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[1]), HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[2]), - HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[3]), aConfig.mPrefix.mLength); - - if (aConfig.mPreferred) - { - OutputFormat("p"); - } - - if (aConfig.mSlaac) - { - OutputFormat("a"); - } - - if (aConfig.mDhcp) - { - OutputFormat("d"); - } - - if (aConfig.mConfigure) - { - OutputFormat("c"); - } - - if (aConfig.mDefaultRoute) - { - OutputFormat("r"); - } - - if (aConfig.mOnMesh) - { - OutputFormat("o"); - } - - if (aConfig.mStable) - { - OutputFormat("s"); - } - - if (aConfig.mNdDns) - { - OutputFormat("n"); - } - - if (aConfig.mDp) - { - OutputFormat("D"); - } - - switch (aConfig.mPreference) - { - case OT_ROUTE_PREFERENCE_LOW: - OutputFormat(" low"); - break; - - case OT_ROUTE_PREFERENCE_MED: - OutputFormat(" med"); - break; - - case OT_ROUTE_PREFERENCE_HIGH: - OutputFormat(" high"); - break; - } - - OutputLine(""); -} - otError Interpreter::ProcessPrefixList(void) { otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; @@ -2998,7 +2873,7 @@ otError Interpreter::ProcessPrefixList(void) while (otBorderRouterGetNextOnMeshPrefix(mInstance, &iterator, &config) == OT_ERROR_NONE) { - OutputPrefix(config); + mNetworkData.OutputPrefix(config); } #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE @@ -3006,7 +2881,7 @@ otError Interpreter::ProcessPrefixList(void) { SuccessOrExit(otBackboneRouterGetDomainPrefix(mInstance, &config)); OutputFormat("- "); - OutputPrefix(config); + mNetworkData.OutputPrefix(config); } // Else already printed via above while loop. exit: @@ -3210,30 +3085,7 @@ otError Interpreter::ProcessRouteList(void) while (otBorderRouterGetNextRoute(mInstance, &iterator, &config) == OT_ERROR_NONE) { - OutputFormat("%x:%x:%x:%x::/%d ", HostSwap16(config.mPrefix.mPrefix.mFields.m16[0]), - HostSwap16(config.mPrefix.mPrefix.mFields.m16[1]), - HostSwap16(config.mPrefix.mPrefix.mFields.m16[2]), - HostSwap16(config.mPrefix.mPrefix.mFields.m16[3]), config.mPrefix.mLength); - - if (config.mStable) - { - OutputFormat("s"); - } - - switch (config.mPreference) - { - case OT_ROUTE_PREFERENCE_LOW: - OutputLine(" low"); - break; - - case OT_ROUTE_PREFERENCE_MED: - OutputLine(" med"); - break; - - case OT_ROUTE_PREFERENCE_HIGH: - OutputLine(" high"); - break; - } + mNetworkData.OutputRoute(config); } return OT_ERROR_NONE; diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index 66ccc151d..0cf5b53c6 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -47,6 +47,7 @@ #include "cli/cli_commissioner.hpp" #include "cli/cli_dataset.hpp" #include "cli/cli_joiner.hpp" +#include "cli/cli_network_data.hpp" #include "cli/cli_udp.hpp" #if OPENTHREAD_CONFIG_COAP_API_ENABLE @@ -87,6 +88,7 @@ class Interpreter friend class Commissioner; friend class Dataset; friend class Joiner; + friend class NetworkData; friend class UdpExample; public: @@ -383,17 +385,21 @@ private: void ProcessNeighbor(uint8_t aArgsLength, char *aArgs[]); #endif void ProcessNetworkData(uint8_t aArgsLength, char *aArgs[]); -#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE - void ProcessNetworkDataRegister(uint8_t aArgsLength, char *aArgs[]); -#endif - void ProcessNetworkDataShow(uint8_t aArgsLength, char *aArgs[]); + void ProcessNetworkDataPrefix(void); + void ProcessNetworkDataRoute(void); + void ProcessNetworkDataService(void); + void OutputPrefix(const otBorderRouterConfig &aConfig); + void OutputRoute(const otExternalRouteConfig &aConfig); + void OutputService(const otServiceConfig &aConfig); + #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE void ProcessNetif(uint8_t aArgsLength, char *aArgs[]); #endif void ProcessNetstat(uint8_t aArgsLength, char *aArgs[]); int OutputSocketAddress(const otSockAddr &aAddress); #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE - void ProcessService(uint8_t aArgsLength, char *aArgs[]); + void ProcessService(uint8_t aArgsLength, char *aArgs[]); + otError ProcessServiceList(void); #endif #if OPENTHREAD_FTD || OPENTHREAD_CONFIG_TMF_NETWORK_DIAG_MTD_ENABLE void ProcessNetworkDiagnostic(uint8_t aArgsLength, char *aArgs[]); @@ -426,7 +432,6 @@ private: otError ProcessPrefixAdd(uint8_t aArgsLength, char *aArgs[]); otError ProcessPrefixRemove(uint8_t aArgsLength, char *aArgs[]); otError ProcessPrefixList(void); - void OutputPrefix(otBorderRouterConfig &aConfig); #endif void ProcessPromiscuous(uint8_t aArgsLength, char *aArgs[]); #if OPENTHREAD_FTD @@ -625,10 +630,6 @@ private: {"neighbor", &Interpreter::ProcessNeighbor}, #endif {"netdata", &Interpreter::ProcessNetworkData}, -#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE - {"netdataregister", &Interpreter::ProcessNetworkDataRegister}, -#endif - {"netdatashow", &Interpreter::ProcessNetworkDataShow}, #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE {"netif", &Interpreter::ProcessNetif}, #endif @@ -712,8 +713,9 @@ private: bool mSntpQueryingInProgress; #endif - UdpExample mUdp; - Dataset mDataset; + Dataset mDataset; + NetworkData mNetworkData; + UdpExample mUdp; #if OPENTHREAD_CONFIG_COAP_API_ENABLE Coap mCoap; diff --git a/src/cli/cli_network_data.cpp b/src/cli/cli_network_data.cpp new file mode 100644 index 000000000..714d106d1 --- /dev/null +++ b/src/cli/cli_network_data.cpp @@ -0,0 +1,343 @@ +/* + * 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. + */ + +/** + * @file + * This file implements CLI commands for Network Data. + */ + +#include "cli_network_data.hpp" + +#include +#include + +#include "cli/cli.hpp" +#include "common/encoding.hpp" + +using ot::Encoding::BigEndian::HostSwap16; + +namespace ot { +namespace Cli { + +const struct NetworkData::Command NetworkData::sCommands[] = { + {"help", &NetworkData::ProcessHelp}, +#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE + {"register", &NetworkData::ProcessRegister}, +#endif + {"show", &NetworkData::ProcessShow}, + {"steeringdata", &NetworkData::ProcessSteeringData}, +}; + +NetworkData::NetworkData(Interpreter &aInterpreter) + : mInterpreter(aInterpreter) +{ +} + +void NetworkData::OutputPrefix(const otBorderRouterConfig &aConfig) +{ + mInterpreter.OutputFormat("%x:%x:%x:%x::/%d ", HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[0]), + HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[1]), + HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[2]), + HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[3]), aConfig.mPrefix.mLength); + + if (aConfig.mPreferred) + { + mInterpreter.OutputFormat("p"); + } + + if (aConfig.mSlaac) + { + mInterpreter.OutputFormat("a"); + } + + if (aConfig.mDhcp) + { + mInterpreter.OutputFormat("d"); + } + + if (aConfig.mConfigure) + { + mInterpreter.OutputFormat("c"); + } + + if (aConfig.mDefaultRoute) + { + mInterpreter.OutputFormat("r"); + } + + if (aConfig.mOnMesh) + { + mInterpreter.OutputFormat("o"); + } + + if (aConfig.mStable) + { + mInterpreter.OutputFormat("s"); + } + + if (aConfig.mNdDns) + { + mInterpreter.OutputFormat("n"); + } + + if (aConfig.mDp) + { + mInterpreter.OutputFormat("D"); + } + + switch (aConfig.mPreference) + { + case OT_ROUTE_PREFERENCE_LOW: + mInterpreter.OutputFormat(" low"); + break; + + case OT_ROUTE_PREFERENCE_MED: + mInterpreter.OutputFormat(" med"); + break; + + case OT_ROUTE_PREFERENCE_HIGH: + mInterpreter.OutputFormat(" high"); + break; + } + + mInterpreter.OutputLine(" %04x", aConfig.mRloc16); +} + +void NetworkData::OutputRoute(const otExternalRouteConfig &aConfig) +{ + mInterpreter.OutputFormat("%x:%x:%x:%x::/%d ", HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[0]), + HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[1]), + HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[2]), + HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[3]), aConfig.mPrefix.mLength); + + if (aConfig.mStable) + { + mInterpreter.OutputFormat("s "); + } + + switch (aConfig.mPreference) + { + case OT_ROUTE_PREFERENCE_LOW: + mInterpreter.OutputFormat("low"); + break; + + case OT_ROUTE_PREFERENCE_MED: + mInterpreter.OutputFormat("med"); + break; + + case OT_ROUTE_PREFERENCE_HIGH: + mInterpreter.OutputFormat("high"); + break; + } + + mInterpreter.OutputLine(" %04x", aConfig.mRloc16); +} + +void NetworkData::OutputService(const otServiceConfig &aConfig) +{ + mInterpreter.OutputFormat("%u ", aConfig.mEnterpriseNumber); + mInterpreter.OutputBytes(aConfig.mServiceData, aConfig.mServiceDataLength); + mInterpreter.OutputFormat(" "); + mInterpreter.OutputBytes(aConfig.mServerConfig.mServerData, aConfig.mServerConfig.mServerDataLength); + + if (aConfig.mServerConfig.mStable) + { + mInterpreter.OutputFormat(" s"); + } + + mInterpreter.OutputLine(" %04x", aConfig.mServerConfig.mRloc16); +} + +otError NetworkData::ProcessHelp(uint8_t aArgsLength, char *aArgs[]) +{ + OT_UNUSED_VARIABLE(aArgsLength); + OT_UNUSED_VARIABLE(aArgs); + + for (const Command &command : sCommands) + { + mInterpreter.OutputLine("%s", command.mName); + } + + return OT_ERROR_NONE; +} + +#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE +otError NetworkData::ProcessRegister(uint8_t aArgsLength, char *aArgs[]) +{ + OT_UNUSED_VARIABLE(aArgsLength); + OT_UNUSED_VARIABLE(aArgs); + + otError error = OT_ERROR_NONE; + +#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE + SuccessOrExit(error = otBorderRouterRegister(mInterpreter.mInstance)); +#else + SuccessOrExit(error = otServerRegister(mInterpreter.mInstance)); +#endif + +exit: + return error; +} +#endif + +otError NetworkData::ProcessSteeringData(uint8_t aArgsLength, char *aArgs[]) +{ + otError error = OT_ERROR_INVALID_ARGS; + otExtAddress addr; + otJoinerDiscerner discerner; + + VerifyOrExit((aArgsLength > 1) && (strcmp(aArgs[0], "check") == 0), OT_NOOP); + + discerner.mLength = 0; + + error = Interpreter::ParseJoinerDiscerner(aArgs[1], discerner); + + if (error == OT_ERROR_NOT_FOUND) + { + VerifyOrExit(Interpreter::Hex2Bin(aArgs[1], addr.m8, sizeof(addr)) == sizeof(addr), OT_NOOP); + } + else if (error != OT_ERROR_NONE) + { + ExitNow(); + } + + if (discerner.mLength) + { + error = otNetDataSteeringDataCheckJoinerWithDiscerner(mInterpreter.mInstance, &discerner); + } + else + { + error = otNetDataSteeringDataCheckJoiner(mInterpreter.mInstance, &addr); + } + +exit: + return error; +} + +void NetworkData::OutputPrefixes(void) +{ + otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; + otBorderRouterConfig config; + + mInterpreter.OutputLine("Prefixes:"); + + while (otNetDataGetNextOnMeshPrefix(mInterpreter.mInstance, &iterator, &config) == OT_ERROR_NONE) + { + OutputPrefix(config); + } +} + +void NetworkData::OutputRoutes(void) +{ + otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; + otExternalRouteConfig config; + + mInterpreter.OutputLine("Routes:"); + + while (otNetDataGetNextRoute(mInterpreter.mInstance, &iterator, &config) == OT_ERROR_NONE) + { + OutputRoute(config); + } +} + +void NetworkData::OutputServices(void) +{ + otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; + otServiceConfig config; + + mInterpreter.OutputLine("Services:"); + + while (otNetDataGetNextService(mInterpreter.mInstance, &iterator, &config) == OT_ERROR_NONE) + { + OutputService(config); + } +} + +otError NetworkData::OutputBinary(void) +{ + otError error = OT_ERROR_NONE; + uint8_t data[255]; + uint8_t len = sizeof(data); + + SuccessOrExit(error = otNetDataGet(mInterpreter.mInstance, false, data, &len)); + + mInterpreter.OutputBytes(data, static_cast(len)); + mInterpreter.OutputLine(""); + +exit: + return error; +} + +otError NetworkData::ProcessShow(uint8_t aArgsLength, char *aArgs[]) +{ + otError error; + + if (aArgsLength == 0) + { + OutputPrefixes(); + OutputRoutes(); + OutputServices(); + error = OT_ERROR_NONE; + } + else if (strcmp(aArgs[0], "-x") == 0) + { + error = OutputBinary(); + } + else + { + error = OT_ERROR_INVALID_ARGS; + } + + return error; +} + +otError NetworkData::Process(uint8_t aArgsLength, char *aArgs[]) +{ + otError error = OT_ERROR_INVALID_COMMAND; + + if (aArgsLength < 1) + { + IgnoreError(ProcessHelp(0, nullptr)); + error = OT_ERROR_INVALID_ARGS; + } + else + { + for (const Command &command : sCommands) + { + if (strcmp(aArgs[0], command.mName) == 0) + { + error = (this->*command.mCommand)(aArgsLength - 1, aArgs + 1); + break; + } + } + } + return error; +} + +} // namespace Cli +} // namespace ot diff --git a/src/cli/cli_network_data.hpp b/src/cli/cli_network_data.hpp new file mode 100644 index 000000000..8b0b4761f --- /dev/null +++ b/src/cli/cli_network_data.hpp @@ -0,0 +1,120 @@ +/* + * 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. + */ + +/** + * @file + * This file contains definitions for Network Data CLI commands. + */ + +#ifndef CLI_NETWORK_DATA_HPP_ +#define CLI_NETWORK_DATA_HPP_ + +#include "openthread-core-config.h" + +#include + +namespace ot { +namespace Cli { + +class Interpreter; + +/** + * This class implements the Network Data CLI. + * + */ +class NetworkData +{ +public: + /** + * Constructor + * + * @param[in] aInterpreter The CLI interpreter. + * + */ + explicit NetworkData(Interpreter &aInterpreter); + + /** + * This method interprets a list of CLI arguments. + * + * @param[in] aArgsLength The number of elements in @p aArgs. + * @param[in] aArgs An array of command line arguments. + * + */ + otError Process(uint8_t aArgsLength, char *aArgs[]); + + /** + * This method outputs the prefix config. + * + * @param[in] aConfig The prefix config. + * + */ + void OutputPrefix(const otBorderRouterConfig &aConfig); + + /** + * This method outputs the route config. + * + * @param[in] aConfig The route config. + * + */ + void OutputRoute(const otExternalRouteConfig &aConfig); + + /** + * This method outputs the service config. + * + * @param[in] aConfig The service config. + * + */ + void OutputService(const otServiceConfig &aConfig); + +private: + struct Command + { + const char *mName; + otError (NetworkData::*mCommand)(uint8_t aArgsLength, char *aArgs[]); + }; + + otError ProcessHelp(uint8_t aArgsLength, char *aArgs[]); +#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE + otError ProcessRegister(uint8_t aArgsLength, char *aArgs[]); +#endif + otError ProcessShow(uint8_t aArgsLength, char *aArgs[]); + otError ProcessSteeringData(uint8_t aArgsLength, char *aArgs[]); + + otError OutputBinary(void); + void OutputPrefixes(void); + void OutputRoutes(void); + void OutputServices(void); + + static const Command sCommands[]; + Interpreter & mInterpreter; +}; + +} // namespace Cli +} // namespace ot + +#endif // CLI_NETWORK_DATA_HPP_ diff --git a/src/posix/platform/README.md b/src/posix/platform/README.md index dea7833c6..dc9486729 100644 --- a/src/posix/platform/README.md +++ b/src/posix/platform/README.md @@ -40,7 +40,7 @@ keysequence leaderweight masterkey mode -netdataregister +netdata register networkidtimeout networkname panid diff --git a/tests/scripts/expect/cli-discerner.exp b/tests/scripts/expect/cli-discerner.exp index 46f56c613..32c28c88e 100755 --- a/tests/scripts/expect/cli-discerner.exp +++ b/tests/scripts/expect/cli-discerner.exp @@ -37,7 +37,7 @@ set discerner "0xabc/12" send "netdata typo check $discerner\n" expect "InvalidCommand" send "netdata steeringdata typo $discerner\n" -expect "InvalidCommand" +expect "InvalidArgs" send "netdata steeringdata check $discerner/0\n" expect "InvalidArgs" send "netdata steeringdata check $discerner\n" diff --git a/tests/scripts/expect/cli-misc.exp b/tests/scripts/expect/cli-misc.exp index 3d3fb6581..2b21efeb1 100755 --- a/tests/scripts/expect/cli-misc.exp +++ b/tests/scripts/expect/cli-misc.exp @@ -47,9 +47,6 @@ expect "Done" send "bufferinfo\n" expect "Done" -send "netdatashow\n" -expect "Done" - send "parent\n" expect "Done" diff --git a/tests/scripts/expect/cli-netdata.exp b/tests/scripts/expect/cli-netdata.exp new file mode 100755 index 000000000..4f867a5fc --- /dev/null +++ b/tests/scripts/expect/cli-netdata.exp @@ -0,0 +1,48 @@ +#!/usr/bin/expect -f +# +# 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. +# + +source "tests/scripts/expect/_common.exp" +source "tests/scripts/expect/_multinode.exp" + +setup_nodes +set spawn_id $spawn_1 + +send "netdata help\n" +expect "Done" + +send "netdata register\n" +expect "Done" + +send "netdata show\n" +expect "Done" + +send "netdata show -x\n" +expect "Done" + +dispose_nodes diff --git a/tests/scripts/thread-cert/node.py b/tests/scripts/thread-cert/node.py index 622d6655b..5cfd075b0 100755 --- a/tests/scripts/thread-cert/node.py +++ b/tests/scripts/thread-cert/node.py @@ -1021,7 +1021,7 @@ class Node: self._expect('Done') def register_netdata(self): - self.send_command('netdataregister') + self.send_command('netdata register') self._expect('Done') def send_network_diag_get(self, addr, tlv_types): diff --git a/tools/harness-automation/autothreadharness/open_thread_controller.py b/tools/harness-automation/autothreadharness/open_thread_controller.py index e99f2fd21..21f31bf6a 100644 --- a/tools/harness-automation/autothreadharness/open_thread_controller.py +++ b/tools/harness-automation/autothreadharness/open_thread_controller.py @@ -368,14 +368,14 @@ class OpenThreadController(threading.Thread): """ self._req('prefix add %s %s %s' % (prefix, flags, prf)) time.sleep(1) - self._req('netdataregister') + self._req('netdata register') def remove_prefix(self, prefix): """Remove network prefix. """ self._req('prefix remove %s' % prefix) time.sleep(1) - self._req('netdataregister') + self._req('netdata register') def enable_denylist(self): """Enable denylist feature""" diff --git a/tools/harness-thci/OpenThread.py b/tools/harness-thci/OpenThread.py index 5e43ab92c..a691df9df 100644 --- a/tools/harness-thci/OpenThread.py +++ b/tools/harness-thci/OpenThread.py @@ -1473,7 +1473,7 @@ class OpenThreadTHCI(object): print(cmd) if self.__executeCommand(cmd)[-1] == 'Done': # send server data ntf to leader - return self.__executeCommand('netdataregister')[-1] == 'Done' + return self.__executeCommand('netdata register')[-1] == 'Done' else: return False except Exception as e: @@ -1579,7 +1579,7 @@ class OpenThreadTHCI(object): return True else: # send server data ntf to leader - return self.__executeCommand('netdataregister')[-1] == 'Done' + return self.__executeCommand('netdata register')[-1] == 'Done' else: return False except Exception as e: @@ -1743,7 +1743,7 @@ class OpenThreadTHCI(object): if self.__executeCommand(cmd)[-1] == 'Done': # send server data ntf to leader - return self.__executeCommand('netdataregister')[-1] == 'Done' + return self.__executeCommand('netdata register')[-1] == 'Done' except Exception as e: ModuleHelper.WriteIntoDebugLogger('configExternalRouter() Error: ' + str(e))