diff --git a/etc/cmake/options.cmake b/etc/cmake/options.cmake index 9060bbb4..a8d39058 100644 --- a/etc/cmake/options.cmake +++ b/etc/cmake/options.cmake @@ -146,3 +146,8 @@ if (OTBR_DHCP6_PD) else() target_compile_definitions(otbr-config INTERFACE OTBR_ENABLE_DHCP6_PD=0) endif() + +option(OTBR_VENDOR_SERVER "Enable vendor server" OFF) +if (OTBR_VENDOR_SERVER) + target_compile_definitions(otbr-config INTERFACE OTBR_ENABLE_VENDOR_SERVER=1) +endif() diff --git a/etc/docker/Dockerfile b/etc/docker/Dockerfile index b24bfe39..c72dd856 100644 --- a/etc/docker/Dockerfile +++ b/etc/docker/Dockerfile @@ -42,6 +42,7 @@ ARG RELEASE ARG REST_API ARG WEB_GUI ARG MDNS +ARG FIREWALL ENV INFRA_IF_NAME=${INFRA_IF_NAME:-eth0} ENV BORDER_ROUTING=${BORDER_ROUTING:-1} @@ -59,6 +60,7 @@ ENV NAT64_DYNAMIC_POOL=${NAT64_DYNAMIC_POOL:-192.168.255.0/24} ENV DNS64=${DNS64:-0} ENV WEB_GUI=${WEB_GUI:-1} ENV REST_API=${REST_API:-1} +ENV FIREWALL=${FIREWALL:-1} ENV DOCKER 1 RUN env @@ -94,6 +96,7 @@ RUN apt-get update \ # Copy OTBR scripts COPY ./ot-br-posix/script /app/script +COPY ./ot-br-posix/third_party/mDNSResponder /app/third_party/mDNSResponder WORKDIR /app # Run OTBR bootstrap @@ -119,6 +122,7 @@ RUN ([ "${DNS64}" = "0" ] || chmod 644 /etc/bind/named.conf.options) \ && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $OTBR_BUILD_DEPS \ && ([ "${RELEASE}" = 1 ] || apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false "$OTBR_NORELEASE_DEPS";) \ && rm -rf /var/lib/apt/lists/* \ + && rm -rf /tmp/* \ )) ENTRYPOINT ["/app/etc/docker/docker_entrypoint.sh"] diff --git a/etc/openwrt/openthread-br/Makefile b/etc/openwrt/openthread-br/Makefile index 1a328c06..cf0fdfb4 100644 --- a/etc/openwrt/openthread-br/Makefile +++ b/etc/openwrt/openthread-br/Makefile @@ -51,7 +51,9 @@ CMAKE_OPTIONS+= \ -DOTBR_SRP_ADVERTISING_PROXY=ON \ -DOT_FIREWALL=ON \ -DOT_POSIX_SETTINGS_PATH=\"/etc/openthread\" \ - -DOT_READLINE=OFF + -DOT_READLINE=OFF \ + -DOTBR_NAT64=ON \ + -DNAT64_SERVICE=\"openthread\" TARGET_CFLAGS += -DOPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME=\\\"/var/run/openthread-%s\\\" diff --git a/script/_firewall b/script/_firewall index 0a29c369..28344d24 100755 --- a/script/_firewall +++ b/script/_firewall @@ -31,8 +31,12 @@ FIREWALL_SERVICE=/etc/init.d/otbr-firewall sudo modprobe ip6table_filter || true +FIREWALL="${FIREWALL:-1}" + firewall_uninstall() { + with FIREWALL || return 0 + firewall_stop if have systemctl; then sudo systemctl disable otbr-firewall || true @@ -46,6 +50,8 @@ firewall_uninstall() firewall_install() { + with FIREWALL || return 0 + sudo cp script/otbr-firewall $FIREWALL_SERVICE sudo chmod a+x $FIREWALL_SERVICE if have systemctl; then @@ -56,6 +62,8 @@ firewall_install() firewall_start() { + with FIREWALL || return 0 + if with DOCKER; then service otbr-firewall start || die 'Failed to start firewall service' elif have systemctl; then @@ -65,6 +73,8 @@ firewall_start() firewall_stop() { + with FIREWALL || return 0 + if with DOCKER; then service otbr-firewall stop || true elif have systemctl; then diff --git a/script/_otbr b/script/_otbr index 790ab10a..dbccc73c 100644 --- a/script/_otbr +++ b/script/_otbr @@ -128,6 +128,16 @@ otbr_install() ) fi + if with FIREWALL; then + otbr_options+=( + "-DOT_FIREWALL=ON" + ) + else + otbr_options+=( + "-DOT_FIREWALL=OFF" + ) + fi + (./script/cmake-build "${otbr_options[@]}" \ && cd "${OTBR_TOP_BUILDDIR}" \ && ninja \ diff --git a/script/bootstrap b/script/bootstrap index 0b72aa49..67d194b1 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -35,6 +35,8 @@ NAT64_SERVICE="${NAT64_SERVICE:-openthread}" +FIREWALL="${FIREWALL:-1}" + install_packages_apt() { sudo apt-get update @@ -56,16 +58,20 @@ install_packages_apt() # mDNS sudo apt-get install --no-install-recommends -y libavahi-client3 libavahi-common-dev libavahi-client-dev avahi-daemon - (MDNS_RESPONDER_SOURCE_NAME=mDNSResponder-1310.80.1 \ + (MDNS_RESPONDER_SOURCE_NAME=mDNSResponder-1790.80.10 \ + && MDNS_RESPONDER_PATCH_PATH=$(realpath "$(dirname "$0")"/../third_party/mDNSResponder) \ && cd /tmp \ && wget --no-check-certificate https://github.com/apple-oss-distributions/mDNSResponder/archive/refs/tags/$MDNS_RESPONDER_SOURCE_NAME.tar.gz \ && mkdir -p $MDNS_RESPONDER_SOURCE_NAME \ && tar xvf $MDNS_RESPONDER_SOURCE_NAME.tar.gz -C $MDNS_RESPONDER_SOURCE_NAME --strip-components=1 \ - && cd /tmp/$MDNS_RESPONDER_SOURCE_NAME/Clients \ - && sed -i '/#include /a #include ' dns-sd.c \ - && sed -i '/#include /a #include ' dns-sd.c \ - && cd /tmp/$MDNS_RESPONDER_SOURCE_NAME/mDNSPosix \ - && make os=linux && sudo make install os=linux) + && cd /tmp/"$MDNS_RESPONDER_SOURCE_NAME" \ + && ( + for patch in "$MDNS_RESPONDER_PATCH_PATH"/*.patch; do + patch -p1 <"$patch" + done + ) \ + && cd mDNSPosix \ + && make os=linux tls=no && sudo make install os=linux tls=no) # Boost sudo apt-get install --no-install-recommends -y libboost-dev libboost-filesystem-dev libboost-system-dev diff --git a/src/agent/CMakeLists.txt b/src/agent/CMakeLists.txt index 9a8b7102..60d19b7e 100644 --- a/src/agent/CMakeLists.txt +++ b/src/agent/CMakeLists.txt @@ -68,9 +68,9 @@ set(OTBR_AGENT_USER "root" CACHE STRING "set the username running otbr-agent ser set(OTBR_AGENT_GROUP "root" CACHE STRING "set the group using otbr-agent client") if(OTBR_MDNS STREQUAL "mDNSResponder") - set(EXEC_START_PRE "ExecStartPre=service mdns start\n") + set(EXEC_START_PRE "ExecStartPre=/usr/sbin/service mdns start\n") elseif(OTBR_MDNS STREQUAL "avahi") - set(EXEC_START_PRE "ExecStartPre=service avahi-daemon start\n") + set(EXEC_START_PRE "ExecStartPre=/usr/sbin/service avahi-daemon start\n") else() message(WARNING "OTBR_MDNS=\"${OTBR_MDNS}\" is not supported") endif() diff --git a/src/agent/application.cpp b/src/agent/application.cpp index 6d749967..33696024 100644 --- a/src/agent/application.cpp +++ b/src/agent/application.cpp @@ -77,7 +77,7 @@ Application::Application(const std::string &aInterfaceName, , mDBusAgent(mNcp, mBorderAgent.GetPublisher()) #endif #if OTBR_ENABLE_VENDOR_SERVER - , mVendorServer(mNcp) + , mVendorServer(vendor::VendorServer::newInstance(*this)) #endif { OTBR_UNUSED_VARIABLE(aRestListenAddress); @@ -104,7 +104,7 @@ void Application::Init(void) mDBusAgent.Init(); #endif #if OTBR_ENABLE_VENDOR_SERVER - mVendorServer.Init(); + mVendorServer->Init(); #endif } diff --git a/src/agent/application.hpp b/src/agent/application.hpp index 9bfeee33..55b39ee6 100644 --- a/src/agent/application.hpp +++ b/src/agent/application.hpp @@ -64,6 +64,14 @@ namespace otbr { +#if OTBR_ENABLE_VENDOR_SERVER +namespace vendor { + +class VendorServer; + +} +#endif + /** * @addtogroup border-router-agent * @@ -119,6 +127,73 @@ class Application : private NonCopyable */ otbrError Run(void); + /** + * Get the OpenThread controller object the application is using. + * + * @returns The OpenThread controller object. + */ + Ncp::ControllerOpenThread &GetNcp(void) { return mNcp; } + +#if OTBR_ENABLE_BORDER_AGENT + /** + * Get the border agent the application is using. + * + * @returns The border agent. + */ + BorderAgent &GetBorderAgent(void) + { + return mBorderAgent; + } +#endif + +#if OTBR_ENABLE_BACKBONE_ROUTER + /** + * Get the backbone agent the application is using. + * + * @returns The backbone agent. + */ + BackboneRouter::BackboneAgent &GetBackboneAgent(void) + { + return mBackboneAgent; + } +#endif + +#if OTBR_ENABLE_OPENWRT + /** + * Get the UBus agent the application is using. + * + * @returns The UBus agent. + */ + ubus::UBusAgent &GetUBusAgent(void) + { + return mUbusAgent; + } +#endif + +#if OTBR_ENABLE_REST_SERVER + /** + * Get the rest web server the application is using. + * + * @returns The rest web server. + */ + rest::RestWebServer &GetRestWebServer(void) + { + return mRestWebServer; + } +#endif + +#if OTBR_ENABLE_DBUS_SERVER + /** + * Get the DBus agent the application is using. + * + * @returns The DBus agent. + */ + DBus::DBusAgent &GetDBusAgent(void) + { + return mDBusAgent; + } +#endif + private: // Default poll timeout. static const struct timeval kPollTimeout; @@ -147,7 +222,7 @@ class Application : private NonCopyable DBus::DBusAgent mDBusAgent; #endif #if OTBR_ENABLE_VENDOR_SERVER - vendor::VendorServer mVendorServer; + std::shared_ptr mVendorServer; #endif static std::atomic_bool sShouldTerminate; diff --git a/src/agent/main.cpp b/src/agent/main.cpp index bc082ca6..5409671d 100644 --- a/src/agent/main.cpp +++ b/src/agent/main.cpp @@ -58,7 +58,6 @@ #include "common/types.hpp" #include "ncp/ncp_openthread.hpp" -static const char kSyslogIdent[] = "otbr-agent"; static const char kDefaultInterfaceName[] = "wpan0"; // Port number used by Rest server. @@ -268,7 +267,7 @@ static int realmain(int argc, char *argv[]) } } - otbrLogInit(kSyslogIdent, logLevel, verbose); + otbrLogInit(argv[0], logLevel, verbose); otbrLogNotice("Running %s", OTBR_PACKAGE_VERSION); otbrLogNotice("Thread version: %s", otbr::Ncp::ControllerOpenThread::GetThreadVersion()); otbrLogNotice("Thread interface: %s", interfaceName); diff --git a/src/agent/vendor.hpp b/src/agent/vendor.hpp index 40deca6c..8e2ecb3a 100644 --- a/src/agent/vendor.hpp +++ b/src/agent/vendor.hpp @@ -36,28 +36,42 @@ #include "openthread-br/config.h" -#include "ncp/ncp_openthread.hpp" +#include "agent/application.hpp" namespace otbr { + +class Application; + namespace vendor { +/** + * An interface for customized behavior depending on OpenThread API and state. + */ class VendorServer { public: + virtual ~VendorServer(void) = default; + /** - * The constructor of vendor server. + * Creates a new instance of VendorServer. + * + * Custom vendor servers should implement this method to return an object of the derived class. * - * @param[in] aNcp A reference to the NCP controller. + * @param[in] aApplication The OTBR application. * + * @returns New derived VendorServer instance. */ - VendorServer(otbr::Ncp::ControllerOpenThread &aNcp); + static std::shared_ptr newInstance(Application &aApplication); /** - * This method initializes the vendor server. + * Initializes the vendor server. * + * This will be called by `Application::Init()` after OpenThread instance and other built-in + * servers have been created and initialized. */ - void Init(void); + virtual void Init(void) = 0; }; + } // namespace vendor } // namespace otbr #endif // OTBR_AGENT_VENDOR_HPP_ diff --git a/src/border_agent/border_agent.cpp b/src/border_agent/border_agent.cpp index 065421f7..78053b10 100644 --- a/src/border_agent/border_agent.cpp +++ b/src/border_agent/border_agent.cpp @@ -343,10 +343,11 @@ void AppendVendorTxtEntries(const std::map> &a for (auto &addedEntry : aTxtList) { - if (addedEntry.mName == key) + if (addedEntry.mKey == key) { - addedEntry.mValue = value; - found = true; + addedEntry.mValue = value; + addedEntry.mIsBooleanAttribute = false; + found = true; break; } } @@ -367,7 +368,11 @@ void BorderAgent::PublishMeshCopService(void) const otExtAddress *extAddr = otLinkGetExtendedAddress(instance); const char *networkName = otThreadGetNetworkName(instance); Mdns::Publisher::TxtList txtList{{"rv", "1"}}; + Mdns::Publisher::TxtData txtData; int port; + otbrError error; + + OTBR_UNUSED_VARIABLE(error); otbrLogInfo("Publish meshcop service %s.%s.local.", mServiceInstanceName.c_str(), kBorderAgentServiceType); @@ -433,8 +438,11 @@ void BorderAgent::PublishMeshCopService(void) port = kBorderAgentServiceDummyPort; } + error = Mdns::Publisher::EncodeTxtData(txtList, txtData); + assert(error == OTBR_ERROR_NONE); + mPublisher->PublishService(/* aHostName */ "", mServiceInstanceName, kBorderAgentServiceType, - Mdns::Publisher::SubTypeList{}, port, txtList, [this](otbrError aError) { + Mdns::Publisher::SubTypeList{}, port, txtData, [this](otbrError aError) { if (aError == OTBR_ERROR_ABORTED) { // OTBR_ERROR_ABORTED is thrown when an ongoing service registration is diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index d5bc1d31..5badd6f6 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -29,6 +29,7 @@ add_library(otbr-common api_strings.cpp byteswap.hpp + code_utils.cpp code_utils.hpp dns_utils.cpp logging.cpp @@ -49,4 +50,6 @@ target_link_libraries(otbr-common PUBLIC otbr-config openthread-ftd openthread-posix + $<$:otbr-proto> + $<$:otbr-proto> ) diff --git a/src/common/code_utils.cpp b/src/common/code_utils.cpp new file mode 100644 index 00000000..35b8a25e --- /dev/null +++ b/src/common/code_utils.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023, 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. + */ + +#include "common/code_utils.hpp" + +uint64_t ConvertOpenThreadUint64(const uint8_t *aValue) +{ + uint64_t val = 0; + + for (size_t i = 0; i < sizeof(uint64_t); i++) + { + val = (val << 8) | aValue[i]; + } + return val; +} diff --git a/src/common/code_utils.hpp b/src/common/code_utils.hpp index 06bf8cb5..87791a2b 100644 --- a/src/common/code_utils.hpp +++ b/src/common/code_utils.hpp @@ -58,6 +58,10 @@ reinterpret_cast( \ ((reinterpret_cast(aMem) + sizeof(aAlignType) - 1) / sizeof(aAlignType)) * sizeof(aAlignType)) +// Allocate the structure using "raw" storage. +#define OT_DEFINE_ALIGNED_VAR(name, size, align_type) \ + align_type name[(((size) + (sizeof(align_type) - 1)) / sizeof(align_type))] + #ifndef CONTAINING_RECORD #define BASE 0x1 #define myoffsetof(s, m) (((size_t) & (((s *)BASE)->m)) - BASE) @@ -165,6 +169,14 @@ template std::unique_ptr MakeUnique(Args &&... return std::unique_ptr(new T(std::forward(args)...)); } +/** + * This method converts 8 uint8_t bytes into uint64_t using big-endian. + * + * @param[in] aValue The input 8 uint8_t bytes. + * @returns The converted uint64_t. + */ +uint64_t ConvertOpenThreadUint64(const uint8_t *aValue); + /** * This class makes any class that derives from it non-copyable. It is intended to be used as a private base class. * diff --git a/src/common/logging.cpp b/src/common/logging.cpp index 5398e471..5a787e82 100644 --- a/src/common/logging.cpp +++ b/src/common/logging.cpp @@ -78,12 +78,17 @@ void otbrLogSetLevel(otbrLogLevel aLevel) } /** Initialize logging */ -void otbrLogInit(const char *aIdent, otbrLogLevel aLevel, bool aPrintStderr) +void otbrLogInit(const char *aProgramName, otbrLogLevel aLevel, bool aPrintStderr) { - assert(aIdent); + const char *ident; + + assert(aProgramName != nullptr); assert(aLevel >= OTBR_LOG_EMERG && aLevel <= OTBR_LOG_DEBUG); - openlog(aIdent, (LOG_CONS | LOG_PID) | (aPrintStderr ? LOG_PERROR : 0), OTBR_SYSLOG_FACILITY_ID); + ident = strrchr(aProgramName, '/'); + ident = (ident != nullptr) ? ident + 1 : aProgramName; + + openlog(ident, (LOG_CONS | LOG_PID) | (aPrintStderr ? LOG_PERROR : 0), OTBR_SYSLOG_FACILITY_ID); sLevel = aLevel; sDefaultLevel = sLevel; } diff --git a/src/common/logging.hpp b/src/common/logging.hpp index d8dc4182..0acdf87a 100644 --- a/src/common/logging.hpp +++ b/src/common/logging.hpp @@ -86,12 +86,12 @@ void otbrLogEnableSyslog(bool aEnabled); /** * This function initialize the logging service. * - * @param[in] aIdent Identity of the logger. + * @param[in] aProgramName The name of this runnable program. * @param[in] aLevel Log level of the logger. * @param[in] aPrintStderr Whether to log to stderr. * */ -void otbrLogInit(const char *aIdent, otbrLogLevel aLevel, bool aPrintStderr); +void otbrLogInit(const char *aProgramName, otbrLogLevel aLevel, bool aPrintStderr); /** * This function log at level @p aLevel. diff --git a/src/dbus/client/thread_api_dbus.cpp b/src/dbus/client/thread_api_dbus.cpp index fc7671ae..0a6c36e6 100644 --- a/src/dbus/client/thread_api_dbus.cpp +++ b/src/dbus/client/thread_api_dbus.cpp @@ -639,6 +639,11 @@ ClientError ThreadApiDBus::GetActiveDatasetTlvs(std::vector &aDataset) return GetProperty(OTBR_DBUS_PROPERTY_ACTIVE_DATASET_TLVS, aDataset); } +ClientError ThreadApiDBus::GetPendingDatasetTlvs(std::vector &aDataset) +{ + return GetProperty(OTBR_DBUS_PROPERTY_PENDING_DATASET_TLVS, aDataset); +} + ClientError ThreadApiDBus::GetFeatureFlagListData(std::vector &aFeatureFlagListData) { return GetProperty(OTBR_DBUS_PROPERTY_FEATURE_FLAG_LIST_DATA, aFeatureFlagListData); diff --git a/src/dbus/client/thread_api_dbus.hpp b/src/dbus/client/thread_api_dbus.hpp index 666b3ebb..622faec7 100644 --- a/src/dbus/client/thread_api_dbus.hpp +++ b/src/dbus/client/thread_api_dbus.hpp @@ -720,6 +720,18 @@ class ThreadApiDBus */ ClientError GetActiveDatasetTlvs(std::vector &aDataset); + /** + * This method gets the pending operational dataset + * + * @param[out] aDataset The pending operational dataset + * + * @retval ERROR_NONE Successfully performed the dbus function call + * @retval ERROR_DBUS dbus encode/decode error + * @retval ... OpenThread defined error value otherwise + * + */ + ClientError GetPendingDatasetTlvs(std::vector &aDataset); + /** * This method gets the feature flag list proto serialized byte data. * diff --git a/src/dbus/common/constants.hpp b/src/dbus/common/constants.hpp index 75398216..1d99f1d7 100644 --- a/src/dbus/common/constants.hpp +++ b/src/dbus/common/constants.hpp @@ -93,6 +93,7 @@ #define OTBR_DBUS_PROPERTY_EXTERNAL_ROUTES "ExternalRoutes" #define OTBR_DBUS_PROPERTY_ON_MESH_PREFIXES "OnMeshPrefixes" #define OTBR_DBUS_PROPERTY_ACTIVE_DATASET_TLVS "ActiveDatasetTlvs" +#define OTBR_DBUS_PROPERTY_PENDING_DATASET_TLVS "PendingDatasetTlvs" #define OTBR_DBUS_PROPERTY_FEATURE_FLAG_LIST_DATA "FeatureFlagListData" #define OTBR_DBUS_PROPERTY_RADIO_REGION "RadioRegion" #define OTBR_DBUS_PROPERTY_SRP_SERVER_INFO "SrpServerInfo" diff --git a/src/dbus/server/dbus_object.cpp b/src/dbus/server/dbus_object.cpp index 65e09353..64c384a6 100644 --- a/src/dbus/server/dbus_object.cpp +++ b/src/dbus/server/dbus_object.cpp @@ -115,7 +115,7 @@ DBusHandlerResult DBusObject::MessageHandler(DBusConnection *aConnection, DBusMe if (dbus_message_get_type(aMessage) == DBUS_MESSAGE_TYPE_METHOD_CALL && iter != mMethodHandlers.end()) { - otbrLogInfo("Handling method %s", memberName.c_str()); + otbrLogDebug("Handling method %s", memberName.c_str()); if (otbrLogGetLevel() >= OTBR_LOG_DEBUG) { DumpDBusMessage(*aMessage); @@ -144,7 +144,7 @@ void DBusObject::GetPropertyMethodHandler(DBusRequest &aRequest) { auto propertyIter = mGetPropertyHandlers.find(interfaceName); - otbrLogInfo("GetProperty %s.%s", interfaceName.c_str(), propertyName.c_str()); + otbrLogDebug("GetProperty %s.%s", interfaceName.c_str(), propertyName.c_str()); VerifyOrExit(propertyIter != mGetPropertyHandlers.end(), error = OT_ERROR_NOT_FOUND); { DBusMessageIter replyIter; diff --git a/src/dbus/server/dbus_thread_object.cpp b/src/dbus/server/dbus_thread_object.cpp index cc03327e..b183c650 100644 --- a/src/dbus/server/dbus_thread_object.cpp +++ b/src/dbus/server/dbus_thread_object.cpp @@ -46,6 +46,7 @@ #include "common/api_strings.hpp" #include "common/byteswap.hpp" +#include "common/code_utils.hpp" #include "dbus/common/constants.hpp" #include "dbus/server/dbus_agent.hpp" #include "dbus/server/dbus_thread_object.hpp" @@ -85,58 +86,6 @@ static std::string GetNat64StateName(otNat64State aState) } #endif // OTBR_ENABLE_NAT64 -static uint64_t ConvertOpenThreadUint64(const uint8_t *aValue) -{ - uint64_t val = 0; - - for (size_t i = 0; i < sizeof(uint64_t); i++) - { - val = (val << 8) | aValue[i]; - } - return val; -} - -#if OTBR_ENABLE_TELEMETRY_DATA_API -static uint32_t TelemetryNodeTypeFromRoleAndLinkMode(const otDeviceRole &aRole, const otLinkModeConfig &aLinkModeCfg) -{ - uint32_t nodeType; - - switch (aRole) - { - case OT_DEVICE_ROLE_DISABLED: - nodeType = threadnetwork::TelemetryData::NODE_TYPE_DISABLED; - break; - case OT_DEVICE_ROLE_DETACHED: - nodeType = threadnetwork::TelemetryData::NODE_TYPE_DETACHED; - break; - case OT_DEVICE_ROLE_ROUTER: - nodeType = threadnetwork::TelemetryData::NODE_TYPE_ROUTER; - break; - case OT_DEVICE_ROLE_LEADER: - nodeType = threadnetwork::TelemetryData::NODE_TYPE_LEADER; - break; - case OT_DEVICE_ROLE_CHILD: - if (!aLinkModeCfg.mRxOnWhenIdle) - { - nodeType = threadnetwork::TelemetryData::NODE_TYPE_SLEEPY_END; - } - else if (!aLinkModeCfg.mDeviceType) - { // If it's not an FTD, return as minimal end device. - nodeType = threadnetwork::TelemetryData::NODE_TYPE_MINIMAL_END; - } - else - { - nodeType = threadnetwork::TelemetryData::NODE_TYPE_END; - } - break; - default: - nodeType = threadnetwork::TelemetryData::NODE_TYPE_UNSPECIFIED; - } - - return nodeType; -} -#endif // OTBR_ENABLE_TELEMETRY_DATA_API - namespace otbr { namespace DBus { @@ -279,6 +228,8 @@ otbrError DBusThreadObject::Init(void) std::bind(&DBusThreadObject::GetOnMeshPrefixesHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_ACTIVE_DATASET_TLVS, std::bind(&DBusThreadObject::GetActiveDatasetTlvsHandler, this, _1)); + RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_PENDING_DATASET_TLVS, + std::bind(&DBusThreadObject::GetPendingDatasetTlvsHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_FEATURE_FLAG_LIST_DATA, std::bind(&DBusThreadObject::GetFeatureFlagListDataHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_RADIO_REGION, @@ -1237,6 +1188,22 @@ otError DBusThreadObject::GetActiveDatasetTlvsHandler(DBusMessageIter &aIter) return error; } +otError DBusThreadObject::GetPendingDatasetTlvsHandler(DBusMessageIter &aIter) +{ + auto threadHelper = mNcp->GetThreadHelper(); + otError error = OT_ERROR_NONE; + std::vector data; + otOperationalDatasetTlvs datasetTlvs; + + SuccessOrExit(error = otDatasetGetPendingTlvs(threadHelper->GetInstance(), &datasetTlvs)); + data = std::vector{std::begin(datasetTlvs.mTlvs), std::begin(datasetTlvs.mTlvs) + datasetTlvs.mLength}; + + VerifyOrExit(DBusMessageEncodeToVariant(&aIter, data) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); + +exit: + return error; +} + otError DBusThreadObject::SetFeatureFlagListDataHandler(DBusMessageIter &aIter) { #if OTBR_ENABLE_FEATURE_FLAGS @@ -1443,77 +1410,9 @@ otError DBusThreadObject::GetTelemetryDataHandler(DBusMessageIter &aIter) #if OTBR_ENABLE_TELEMETRY_DATA_API otError error = OT_ERROR_NONE; threadnetwork::TelemetryData telemetryData; + auto threadHelper = mNcp->GetThreadHelper(); - auto threadHelper = mNcp->GetThreadHelper(); - - // Begin of WpanStats section. - auto wpanStats = telemetryData.mutable_wpan_stats(); - - { - otDeviceRole role = otThreadGetDeviceRole(threadHelper->GetInstance()); - otLinkModeConfig otCfg = otThreadGetLinkMode(threadHelper->GetInstance()); - - wpanStats->set_node_type(TelemetryNodeTypeFromRoleAndLinkMode(role, otCfg)); - } - - wpanStats->set_channel(otLinkGetChannel(threadHelper->GetInstance())); - - { - uint16_t ccaFailureRate = otLinkGetCcaFailureRate(threadHelper->GetInstance()); - - wpanStats->set_mac_cca_fail_rate(static_cast(ccaFailureRate) / 0xffff); - } - - { - int8_t radioTxPower; - - SuccessOrExit(error = otPlatRadioGetTransmitPower(threadHelper->GetInstance(), &radioTxPower)); - wpanStats->set_radio_tx_power(radioTxPower); - } - - { - const otMacCounters *linkCounters = otLinkGetCounters(threadHelper->GetInstance()); - - wpanStats->set_phy_rx(linkCounters->mRxTotal); - wpanStats->set_phy_tx(linkCounters->mTxTotal); - wpanStats->set_mac_unicast_rx(linkCounters->mRxUnicast); - wpanStats->set_mac_unicast_tx(linkCounters->mTxUnicast); - wpanStats->set_mac_broadcast_rx(linkCounters->mRxBroadcast); - wpanStats->set_mac_broadcast_tx(linkCounters->mTxBroadcast); - wpanStats->set_mac_tx_ack_req(linkCounters->mTxAckRequested); - wpanStats->set_mac_tx_no_ack_req(linkCounters->mTxNoAckRequested); - wpanStats->set_mac_tx_acked(linkCounters->mTxAcked); - wpanStats->set_mac_tx_data(linkCounters->mTxData); - wpanStats->set_mac_tx_data_poll(linkCounters->mTxDataPoll); - wpanStats->set_mac_tx_beacon(linkCounters->mTxBeacon); - wpanStats->set_mac_tx_beacon_req(linkCounters->mTxBeaconRequest); - wpanStats->set_mac_tx_other_pkt(linkCounters->mTxOther); - wpanStats->set_mac_tx_retry(linkCounters->mTxRetry); - wpanStats->set_mac_rx_data(linkCounters->mRxData); - wpanStats->set_mac_rx_data_poll(linkCounters->mRxDataPoll); - wpanStats->set_mac_rx_beacon(linkCounters->mRxBeacon); - wpanStats->set_mac_rx_beacon_req(linkCounters->mRxBeaconRequest); - wpanStats->set_mac_rx_other_pkt(linkCounters->mRxOther); - wpanStats->set_mac_rx_filter_whitelist(linkCounters->mRxAddressFiltered); - wpanStats->set_mac_rx_filter_dest_addr(linkCounters->mRxDestAddrFiltered); - wpanStats->set_mac_tx_fail_cca(linkCounters->mTxErrCca); - wpanStats->set_mac_rx_fail_decrypt(linkCounters->mRxErrSec); - wpanStats->set_mac_rx_fail_no_frame(linkCounters->mRxErrNoFrame); - wpanStats->set_mac_rx_fail_unknown_neighbor(linkCounters->mRxErrUnknownNeighbor); - wpanStats->set_mac_rx_fail_invalid_src_addr(linkCounters->mRxErrInvalidSrcAddr); - wpanStats->set_mac_rx_fail_fcs(linkCounters->mRxErrFcs); - wpanStats->set_mac_rx_fail_other(linkCounters->mRxErrOther); - } - - { - const otIpCounters *ipCounters = otThreadGetIp6Counters(threadHelper->GetInstance()); - - wpanStats->set_ip_tx_success(ipCounters->mTxSuccess); - wpanStats->set_ip_rx_success(ipCounters->mRxSuccess); - wpanStats->set_ip_tx_failure(ipCounters->mTxFailure); - wpanStats->set_ip_rx_failure(ipCounters->mRxFailure); - } - // End of WpanStats section. + VerifyOrExit(threadHelper->RetrieveTelemetryData(mPublisher, telemetryData) == OT_ERROR_NONE); { const std::string telemetryDataBytes = telemetryData.SerializeAsString(); diff --git a/src/dbus/server/dbus_thread_object.hpp b/src/dbus/server/dbus_thread_object.hpp index b10cd346..9b23bd6e 100644 --- a/src/dbus/server/dbus_thread_object.hpp +++ b/src/dbus/server/dbus_thread_object.hpp @@ -149,6 +149,7 @@ class DBusThreadObject : public DBusObject otError GetExternalRoutesHandler(DBusMessageIter &aIter); otError GetOnMeshPrefixesHandler(DBusMessageIter &aIter); otError GetActiveDatasetTlvsHandler(DBusMessageIter &aIter); + otError GetPendingDatasetTlvsHandler(DBusMessageIter &aIter); otError GetFeatureFlagListDataHandler(DBusMessageIter &aIter); otError GetRadioRegionHandler(DBusMessageIter &aIter); otError GetSrpServerInfoHandler(DBusMessageIter &aIter); diff --git a/src/dbus/server/introspect.xml b/src/dbus/server/introspect.xml index 7f57bcb4..0a898181 100644 --- a/src/dbus/server/introspect.xml +++ b/src/dbus/server/introspect.xml @@ -536,6 +536,11 @@ + + + + + diff --git a/src/mdns/mdns.cpp b/src/mdns/mdns.cpp index c2c692c4..83ccaecc 100644 --- a/src/mdns/mdns.cpp +++ b/src/mdns/mdns.cpp @@ -52,23 +52,21 @@ void Publisher::PublishService(const std::string &aHostName, const std::string &aType, const SubTypeList &aSubTypeList, uint16_t aPort, - const TxtList &aTxtList, + const TxtData &aTxtData, ResultCallback &&aCallback) { otbrError error; mServiceRegistrationBeginTime[std::make_pair(aName, aType)] = Clock::now(); - error = PublishServiceImpl(aHostName, aName, aType, aSubTypeList, aPort, aTxtList, std::move(aCallback)); + error = PublishServiceImpl(aHostName, aName, aType, aSubTypeList, aPort, aTxtData, std::move(aCallback)); if (error != OTBR_ERROR_NONE) { UpdateMdnsResponseCounters(mTelemetryInfo.mServiceRegistrations, error); } } -void Publisher::PublishHost(const std::string &aName, - const std::vector &aAddresses, - ResultCallback &&aCallback) +void Publisher::PublishHost(const std::string &aName, const AddressList &aAddresses, ResultCallback &&aCallback) { otbrError error; @@ -99,18 +97,32 @@ otbrError Publisher::EncodeTxtData(const TxtList &aTxtList, std::vector { otbrError error = OTBR_ERROR_NONE; - for (const auto &txtEntry : aTxtList) + aTxtData.clear(); + + for (const TxtEntry &txtEntry : aTxtList) { - const auto &name = txtEntry.mName; - const auto &value = txtEntry.mValue; - const size_t entryLength = name.length() + 1 + value.size(); + size_t entryLength = txtEntry.mKey.length(); + + if (!txtEntry.mIsBooleanAttribute) + { + entryLength += txtEntry.mValue.size() + sizeof(uint8_t); // for `=` char. + } VerifyOrExit(entryLength <= kMaxTextEntrySize, error = OTBR_ERROR_INVALID_ARGS); aTxtData.push_back(static_cast(entryLength)); - aTxtData.insert(aTxtData.end(), name.begin(), name.end()); - aTxtData.push_back('='); - aTxtData.insert(aTxtData.end(), value.begin(), value.end()); + aTxtData.insert(aTxtData.end(), txtEntry.mKey.begin(), txtEntry.mKey.end()); + + if (!txtEntry.mIsBooleanAttribute) + { + aTxtData.push_back('='); + aTxtData.insert(aTxtData.end(), txtEntry.mValue.begin(), txtEntry.mValue.end()); + } + } + + if (aTxtData.empty()) + { + aTxtData.push_back(0); } exit: @@ -121,30 +133,39 @@ otbrError Publisher::DecodeTxtData(Publisher::TxtList &aTxtList, const uint8_t * { otbrError error = OTBR_ERROR_NONE; + aTxtList.clear(); + for (uint16_t r = 0; r < aTxtLength;) { uint16_t entrySize = aTxtData[r]; uint16_t keyStart = r + 1; uint16_t entryEnd = keyStart + entrySize; uint16_t keyEnd = keyStart; - uint16_t valStart; + + VerifyOrExit(entryEnd <= aTxtLength, error = OTBR_ERROR_PARSE); while (keyEnd < entryEnd && aTxtData[keyEnd] != '=') { keyEnd++; } - valStart = keyEnd; - if (valStart < entryEnd && aTxtData[valStart] == '=') + if (keyEnd == entryEnd) { - valStart++; + if (keyEnd > keyStart) + { + // No `=`, treat as a boolean attribute. + aTxtList.emplace_back(reinterpret_cast(&aTxtData[keyStart]), keyEnd - keyStart); + } } + else + { + uint16_t valStart = keyEnd + 1; // To skip over `=` - aTxtList.emplace_back(reinterpret_cast(&aTxtData[keyStart]), keyEnd - keyStart, - &aTxtData[valStart], entryEnd - valStart); + aTxtList.emplace_back(reinterpret_cast(&aTxtData[keyStart]), keyEnd - keyStart, + &aTxtData[valStart], entryEnd - valStart); + } r += entrySize + 1; - VerifyOrExit(r <= aTxtLength, error = OTBR_ERROR_PARSE); } exit: @@ -153,31 +174,24 @@ otbrError Publisher::DecodeTxtData(Publisher::TxtList &aTxtList, const uint8_t * void Publisher::RemoveSubscriptionCallbacks(uint64_t aSubscriberId) { - size_t erased; - - OTBR_UNUSED_VARIABLE(erased); - - assert(aSubscriberId > 0); - - erased = mDiscoveredCallbacks.erase(aSubscriberId); - - assert(erased == 1); + mDiscoverCallbacks.remove_if( + [aSubscriberId](const DiscoverCallback &aCallback) { return (aCallback.mId == aSubscriberId); }); } uint64_t Publisher::AddSubscriptionCallbacks(Publisher::DiscoveredServiceInstanceCallback aInstanceCallback, Publisher::DiscoveredHostCallback aHostCallback) { - uint64_t subscriberId = mNextSubscriberId++; + uint64_t id = mNextSubscriberId++; - assert(subscriberId > 0); + assert(id > 0); + mDiscoverCallbacks.emplace_back(id, aInstanceCallback, aHostCallback); - mDiscoveredCallbacks.emplace(subscriberId, std::make_pair(std::move(aInstanceCallback), std::move(aHostCallback))); - return subscriberId; + return id; } void Publisher::OnServiceResolved(std::string aType, DiscoveredInstanceInfo aInstanceInfo) { - std::vector subscriberIds; + bool checkToInvoke = false; otbrLogInfo("Service %s is resolved successfully: %s %s host %s addresses %zu", aType.c_str(), aInstanceInfo.mRemoved ? "remove" : "add", aInstanceInfo.mName.c_str(), aInstanceInfo.mHostName.c_str(), @@ -195,22 +209,33 @@ void Publisher::OnServiceResolved(std::string aType, DiscoveredInstanceInfo aIns UpdateMdnsResponseCounters(mTelemetryInfo.mServiceResolutions, OTBR_ERROR_NONE); UpdateServiceInstanceResolutionEmaLatency(aInstanceInfo.mName, aType, OTBR_ERROR_NONE); - // In a callback, the mDiscoveredCallbacks may get changed which invalidates the running iterator. We need to refer - // to the callbacks by subscriberId to avoid invalid memory access. - subscriberIds.reserve(mDiscoveredCallbacks.size()); - for (const auto &subCallback : mDiscoveredCallbacks) + // The `mDiscoverCallbacks` list can get updated as the callbacks + // are invoked. We first mark `mShouldInvoke` on all non-null + // service callbacks. We clear it before invoking the callback + // and restart the iteration over the `mDiscoverCallbacks` list + // to find the next one to signal, since the list may have changed. + + for (DiscoverCallback &callback : mDiscoverCallbacks) { - subscriberIds.push_back(subCallback.first); + if (callback.mServiceCallback != nullptr) + { + callback.mShouldInvoke = true; + checkToInvoke = true; + } } - for (const auto &subscriberId : subscriberIds) + + while (checkToInvoke) { - auto it = mDiscoveredCallbacks.find(subscriberId); - if (it != mDiscoveredCallbacks.end()) + checkToInvoke = false; + + for (DiscoverCallback &callback : mDiscoverCallbacks) { - const auto &subCallback = *it; - if (subCallback.second.first != nullptr) + if (callback.mShouldInvoke) { - subCallback.second.first(aType, aInstanceInfo); + callback.mShouldInvoke = false; + checkToInvoke = true; + callback.mServiceCallback(aType, aInstanceInfo); + break; } } } @@ -231,6 +256,8 @@ void Publisher::OnServiceRemoved(uint32_t aNetifIndex, std::string aType, std::s void Publisher::OnHostResolved(std::string aHostName, Publisher::DiscoveredHostInfo aHostInfo) { + bool checkToInvoke = false; + otbrLogInfo("Host %s is resolved successfully: host %s addresses %zu ttl %u", aHostName.c_str(), aHostInfo.mHostName.c_str(), aHostInfo.mAddresses.size(), aHostInfo.mTtl); @@ -242,11 +269,34 @@ void Publisher::OnHostResolved(std::string aHostName, Publisher::DiscoveredHostI UpdateMdnsResponseCounters(mTelemetryInfo.mHostResolutions, OTBR_ERROR_NONE); UpdateHostResolutionEmaLatency(aHostName, OTBR_ERROR_NONE); - for (const auto &subCallback : mDiscoveredCallbacks) + // The `mDiscoverCallbacks` list can get updated as the callbacks + // are invoked. We first mark `mShouldInvoke` on all non-null + // host callbacks. We clear it before invoking the callback + // and restart the iteration over the `mDiscoverCallbacks` list + // to find the next one to signal, since the list may have changed. + + for (DiscoverCallback &callback : mDiscoverCallbacks) { - if (subCallback.second.second != nullptr) + if (callback.mHostCallback != nullptr) { - subCallback.second.second(aHostName, aHostInfo); + callback.mShouldInvoke = true; + checkToInvoke = true; + } + } + + while (checkToInvoke) + { + checkToInvoke = false; + + for (DiscoverCallback &callback : mDiscoverCallbacks) + { + if (callback.mShouldInvoke) + { + callback.mShouldInvoke = false; + checkToInvoke = true; + callback.mHostCallback(aHostName, aHostInfo); + break; + } } } } @@ -257,13 +307,6 @@ Publisher::SubTypeList Publisher::SortSubTypeList(SubTypeList aSubTypeList) return aSubTypeList; } -Publisher::TxtList Publisher::SortTxtList(TxtList aTxtList) -{ - std::sort(aTxtList.begin(), aTxtList.end(), - [](const TxtEntry &aLhs, const TxtEntry &aRhs) { return aLhs.mName < aRhs.mName; }); - return aTxtList; -} - Publisher::AddressList Publisher::SortAddressList(AddressList aAddressList) { std::sort(aAddressList.begin(), aAddressList.end()); @@ -316,14 +359,14 @@ Publisher::ResultCallback Publisher::HandleDuplicateServiceRegistration(const st const std::string &aType, const SubTypeList &aSubTypeList, uint16_t aPort, - const TxtList &aTxtList, + const TxtData &aTxtData, ResultCallback &&aCallback) { ServiceRegistration *serviceReg = FindServiceRegistration(aName, aType); VerifyOrExit(serviceReg != nullptr); - if (serviceReg->IsOutdated(aHostName, aName, aType, aSubTypeList, aPort, aTxtList)) + if (serviceReg->IsOutdated(aHostName, aName, aType, aSubTypeList, aPort, aTxtData)) { otbrLogInfo("Removing existing service %s.%s: outdated", aName.c_str(), aType.c_str()); RemoveServiceRegistration(aName, aType, OTBR_ERROR_ABORTED); @@ -352,9 +395,9 @@ Publisher::ResultCallback Publisher::HandleDuplicateServiceRegistration(const st return std::move(aCallback); } -Publisher::ResultCallback Publisher::HandleDuplicateHostRegistration(const std::string &aName, - const std::vector &aAddresses, - ResultCallback &&aCallback) +Publisher::ResultCallback Publisher::HandleDuplicateHostRegistration(const std::string &aName, + const AddressList &aAddresses, + ResultCallback &&aCallback) { HostRegistration *hostReg = FindHostRegistration(aName); @@ -431,10 +474,10 @@ bool Publisher::ServiceRegistration::IsOutdated(const std::string &aHostName, const std::string &aType, const SubTypeList &aSubTypeList, uint16_t aPort, - const TxtList &aTxtList) const + const TxtData &aTxtData) const { return !(mHostName == aHostName && mName == aName && mType == aType && mSubTypeList == aSubTypeList && - mPort == aPort && mTxtList == aTxtList); + mPort == aPort && mTxtData == aTxtData); } void Publisher::ServiceRegistration::Complete(otbrError aError) @@ -452,7 +495,7 @@ void Publisher::ServiceRegistration::OnComplete(otbrError aError) } } -bool Publisher::HostRegistration::IsOutdated(const std::string &aName, const std::vector &aAddresses) const +bool Publisher::HostRegistration::IsOutdated(const std::string &aName, const AddressList &aAddresses) const { return !(mName == aName && mAddresses == aAddresses); } @@ -577,5 +620,4 @@ void Publisher::UpdateHostResolutionEmaLatency(const std::string &aHostName, otb } } // namespace Mdns - } // namespace otbr diff --git a/src/mdns/mdns.hpp b/src/mdns/mdns.hpp index 0159009d..2cb41053 100644 --- a/src/mdns/mdns.hpp +++ b/src/mdns/mdns.hpp @@ -37,6 +37,7 @@ #include "openthread-br/config.h" #include +#include #include #include #include @@ -70,33 +71,51 @@ class Publisher : private NonCopyable { public: /** - * This structure represents a name/value pair of the TXT record. + * This structure represents a key/value pair of the TXT record. * */ struct TxtEntry { - std::string mName; ///< The name of the TXT entry. - std::vector mValue; ///< The value of the TXT entry. + std::string mKey; ///< The key of the TXT entry. + std::vector mValue; ///< The value of the TXT entry. Can be empty. + bool mIsBooleanAttribute; ///< This entry is boolean attribute (encoded as `key` without `=`). - TxtEntry(const char *aName, const char *aValue) - : TxtEntry(aName, reinterpret_cast(aValue), strlen(aValue)) + TxtEntry(const char *aKey, const char *aValue) + : TxtEntry(aKey, reinterpret_cast(aValue), strlen(aValue)) { } - TxtEntry(const char *aName, const uint8_t *aValue, size_t aValueLength) - : TxtEntry(aName, strlen(aName), aValue, aValueLength) + TxtEntry(const char *aKey, const uint8_t *aValue, size_t aValueLength) + : TxtEntry(aKey, strlen(aKey), aValue, aValueLength) { } - TxtEntry(const char *aName, size_t aNameLength, const uint8_t *aValue, size_t aValueLength) - : mName(aName, aNameLength) + TxtEntry(const char *aKey, size_t aKeyLength, const uint8_t *aValue, size_t aValueLength) + : mKey(aKey, aKeyLength) , mValue(aValue, aValue + aValueLength) + , mIsBooleanAttribute(false) { } - bool operator==(const TxtEntry &aOther) const { return mName == aOther.mName && mValue == aOther.mValue; } + TxtEntry(const char *aKey) + : TxtEntry(aKey, strlen(aKey)) + { + } + + TxtEntry(const char *aKey, size_t aKeyLength) + : mKey(aKey, aKeyLength) + , mIsBooleanAttribute(true) + { + } + + bool operator==(const TxtEntry &aOther) const + { + return (mKey == aOther.mKey) && (mValue == aOther.mValue) && + (mIsBooleanAttribute == aOther.mIsBooleanAttribute); + } }; + typedef std::vector TxtData; typedef std::vector TxtList; typedef std::vector SubTypeList; typedef std::vector AddressList; @@ -107,16 +126,16 @@ class Publisher : private NonCopyable */ struct DiscoveredInstanceInfo { - bool mRemoved = false; ///< The Service Instance is removed. - uint32_t mNetifIndex = 0; ///< Network interface. - std::string mName; ///< Instance name. - std::string mHostName; ///< Full host name. - std::vector mAddresses; ///< IPv6 addresses. - uint16_t mPort = 0; ///< Port. - uint16_t mPriority = 0; ///< Service priority. - uint16_t mWeight = 0; ///< Service weight. - std::vector mTxtData; ///< TXT RDATA bytes. - uint32_t mTtl = 0; ///< Service TTL. + bool mRemoved = false; ///< The Service Instance is removed. + uint32_t mNetifIndex = 0; ///< Network interface. + std::string mName; ///< Instance name. + std::string mHostName; ///< Full host name. + AddressList mAddresses; ///< IPv6 addresses. + uint16_t mPort = 0; ///< Port. + uint16_t mPriority = 0; ///< Service priority. + uint16_t mWeight = 0; ///< Service weight. + TxtData mTxtData; ///< TXT RDATA bytes. + uint32_t mTtl = 0; ///< Service TTL. }; /** @@ -125,9 +144,10 @@ class Publisher : private NonCopyable */ struct DiscoveredHostInfo { - std::string mHostName; ///< Full host name. - std::vector mAddresses; ///< IP6 addresses. - uint32_t mTtl = 0; ///< Host TTL. + std::string mHostName; ///< Full host name. + AddressList mAddresses; ///< IP6 addresses. + uint32_t mNetifIndex = 0; ///< Network interface. + uint32_t mTtl = 0; ///< Host TTL. }; /** @@ -193,10 +213,10 @@ class Publisher : private NonCopyable * with method PublishHost. * @param[in] aName The name of this service. If an empty string is provided, the service's name will be the * same as the platform's hostname. - * @param[in] aType The type of this service. + * @param[in] aType The type of this service, e.g., "_srv._udp" (MUST NOT end with dot). * @param[in] aSubTypeList A list of service subtypes. * @param[in] aPort The port number of this service. - * @param[in] aTxtList A list of TXT name/value pairs. + * @param[in] aTxtData The encoded TXT data for this service. * @param[in] aCallback The callback for receiving the publishing result. `OTBR_ERROR_NONE` will be * returned if the operation is successful and all other values indicate a * failure. Specifically, `OTBR_ERROR_DUPLICATED` indicates that the name has @@ -209,14 +229,14 @@ class Publisher : private NonCopyable const std::string &aType, const SubTypeList &aSubTypeList, uint16_t aPort, - const TxtList &aTxtList, + const TxtData &aTxtData, ResultCallback &&aCallback); /** * This method un-publishes a service. * * @param[in] aName The name of this service. - * @param[in] aType The type of this service. + * @param[in] aType The type of this service, e.g., "_srv._udp" (MUST NOT end with dot). * @param[in] aCallback The callback for receiving the publishing result. * */ @@ -237,12 +257,12 @@ class Publisher : private NonCopyable * alternative name is available/acceptable. * */ - void PublishHost(const std::string &aName, const std::vector &aAddresses, ResultCallback &&aCallback); + void PublishHost(const std::string &aName, const AddressList &aAddresses, ResultCallback &&aCallback); /** * This method un-publishes a host. * - * @param[in] aName A host name. + * @param[in] aName A host name (MUST not end with dot). * @param[in] aCallback The callback for receiving the publishing result. * */ @@ -258,7 +278,7 @@ class Publisher : private NonCopyable * @note Discovery Proxy implementation guarantees no duplicate subscriptions for the same service or service * instance. * - * @param[in] aType The service type. + * @param[in] aType The service type, e.g., "_srv._udp" (MUST NOT end with dot). * @param[in] aInstanceName The service instance to subscribe, or empty to subscribe the service. * */ @@ -272,7 +292,7 @@ class Publisher : private NonCopyable * * @note Discovery Proxy implementation guarantees no redundant unsubscription for a service or service instance. * - * @param[in] aType The service type. + * @param[in] aType The service type, e.g., "_srv._udp" (MUST NOT end with dot). * @param[in] aInstanceName The service instance to unsubscribe, or empty to unsubscribe the service. * */ @@ -326,7 +346,7 @@ class Publisher : private NonCopyable * @returns The MdnsTelemetryInfo of the publisher. * */ - const MdnsTelemetryInfo &GetMdnsTelemetryInfo() const { return mTelemetryInfo; } + const MdnsTelemetryInfo &GetMdnsTelemetryInfo(void) const { return mTelemetryInfo; } virtual ~Publisher(void) = default; @@ -356,7 +376,7 @@ class Publisher : private NonCopyable * See RFC 6763 for details: https://tools.ietf.org/html/rfc6763#section-6. * * @param[in] aTxtList A TXT entry list. - * @param[out] aTxtData A TXT data buffer. + * @param[out] aTxtData A TXT data buffer. Will be cleared. * * @retval OTBR_ERROR_NONE Successfully write the TXT entry list. * @retval OTBR_ERROR_INVALID_ARGS The @p aTxtList includes invalid TXT entry. @@ -364,7 +384,7 @@ class Publisher : private NonCopyable * @sa DecodeTxtData * */ - static otbrError EncodeTxtData(const TxtList &aTxtList, std::vector &aTxtData); + static otbrError EncodeTxtData(const TxtList &aTxtList, TxtData &aTxtData); /** * This function decodes a TXT entry list from a TXT data buffer. @@ -424,14 +444,14 @@ class Publisher : private NonCopyable std::string mType; SubTypeList mSubTypeList; uint16_t mPort; - TxtList mTxtList; + TxtData mTxtData; ServiceRegistration(std::string aHostName, std::string aName, std::string aType, SubTypeList aSubTypeList, uint16_t aPort, - TxtList aTxtList, + TxtData aTxtData, ResultCallback &&aCallback, Publisher *aPublisher) : Registration(std::move(aCallback), aPublisher) @@ -440,29 +460,30 @@ class Publisher : private NonCopyable , mType(std::move(aType)) , mSubTypeList(SortSubTypeList(std::move(aSubTypeList))) , mPort(aPort) - , mTxtList(SortTxtList(std::move(aTxtList))) + , mTxtData(std::move(aTxtData)) { } ~ServiceRegistration(void) override { OnComplete(OTBR_ERROR_ABORTED); } void Complete(otbrError aError); - void OnComplete(otbrError aError); - // Tells whether this `ServiceRegistration` object is outdated comparing to the given parameters. bool IsOutdated(const std::string &aHostName, const std::string &aName, const std::string &aType, const SubTypeList &aSubTypeList, uint16_t aPort, - const TxtList &aTxtList) const; + const TxtData &aTxtData) const; + + private: + void OnComplete(otbrError aError); }; class HostRegistration : public Registration { public: - std::string mName; - std::vector mAddresses; + std::string mName; + AddressList mAddresses; HostRegistration(std::string aName, AddressList aAddresses, ResultCallback &&aCallback, Publisher *aPublisher) : Registration(std::move(aCallback), aPublisher) @@ -471,14 +492,15 @@ class Publisher : private NonCopyable { } - ~HostRegistration(void) { OnComplete(OTBR_ERROR_ABORTED); } + ~HostRegistration(void) override { OnComplete(OTBR_ERROR_ABORTED); } void Complete(otbrError aError); - void OnComplete(otbrError); - // Tells whether this `HostRegistration` object is outdated comparing to the given parameters. - bool IsOutdated(const std::string &aName, const std::vector &aAddresses) const; + bool IsOutdated(const std::string &aName, const AddressList &aAddresses) const; + + private: + void OnComplete(otbrError aError); }; using ServiceRegistrationPtr = std::unique_ptr; @@ -487,7 +509,6 @@ class Publisher : private NonCopyable using HostRegistrationMap = std::map; static SubTypeList SortSubTypeList(SubTypeList aSubTypeList); - static TxtList SortTxtList(TxtList aTxtList); static AddressList SortAddressList(AddressList aAddressList); static std::string MakeFullServiceName(const std::string &aName, const std::string &aType); static std::string MakeFullHostName(const std::string &aName); @@ -497,15 +518,18 @@ class Publisher : private NonCopyable const std::string &aType, const SubTypeList &aSubTypeList, uint16_t aPort, - const TxtList &aTxtList, - ResultCallback &&aCallback) = 0; - virtual otbrError PublishHostImpl(const std::string &aName, - const std::vector &aAddresses, - ResultCallback &&aCallback) = 0; - virtual void OnServiceResolveFailedImpl(const std::string &aType, - const std::string &aInstanceName, - int32_t aErrorCode) = 0; - virtual void OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode) = 0; + const TxtData &aTxtData, + ResultCallback &&aCallback) = 0; + + virtual otbrError PublishHostImpl(const std::string &aName, + const AddressList &aAddresses, + ResultCallback &&aCallback) = 0; + + virtual void OnServiceResolveFailedImpl(const std::string &aType, + const std::string &aInstanceName, + int32_t aErrorCode) = 0; + + virtual void OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode) = 0; virtual otbrError DnsErrorToOtbrError(int32_t aError) = 0; @@ -527,18 +551,18 @@ class Publisher : private NonCopyable const std::string &aType, const SubTypeList &aSubTypeList, uint16_t aPort, - const TxtList &aTxtList, + const TxtData &aTxtData, ResultCallback &&aCallback); - ResultCallback HandleDuplicateHostRegistration(const std::string &aName, - const std::vector &aAddresses, - ResultCallback &&aCallback); + ResultCallback HandleDuplicateHostRegistration(const std::string &aName, + const AddressList &aAddresses, + ResultCallback &&aCallback); void AddHostRegistration(HostRegistrationPtr &&aHostReg); void RemoveHostRegistration(const std::string &aName, otbrError aError); HostRegistration *FindHostRegistration(const std::string &aName); - static void UpdateMdnsResponseCounters(otbr::MdnsResponseCounters &aCounters, otbrError aError); + static void UpdateMdnsResponseCounters(MdnsResponseCounters &aCounters, otbrError aError); static void UpdateEmaLatency(uint32_t &aEmaLatency, uint32_t aLatency, otbrError aError); void UpdateServiceRegistrationEmaLatency(const std::string &aInstanceName, @@ -553,9 +577,28 @@ class Publisher : private NonCopyable ServiceRegistrationMap mServiceRegistrations; HostRegistrationMap mHostRegistrations; + struct DiscoverCallback + { + DiscoverCallback(uint64_t aId, + DiscoveredServiceInstanceCallback aServiceCallback, + DiscoveredHostCallback aHostCallback) + : mId(aId) + , mServiceCallback(std::move(aServiceCallback)) + , mHostCallback(std::move(aHostCallback)) + , mShouldInvoke(false) + { + } + + uint64_t mId; + DiscoveredServiceInstanceCallback mServiceCallback; + DiscoveredHostCallback mHostCallback; + bool mShouldInvoke; + }; + uint64_t mNextSubscriberId = 1; - std::map> mDiscoveredCallbacks; + std::list mDiscoverCallbacks; + // {instance name, service type} -> the timepoint to begin service registration std::map, Timepoint> mServiceRegistrationBeginTime; // host name -> the timepoint to begin host registration @@ -565,7 +608,7 @@ class Publisher : private NonCopyable // host name -> the timepoint to begin host resolution std::map mHostResolutionBeginTime; - otbr::MdnsTelemetryInfo mTelemetryInfo{}; + MdnsTelemetryInfo mTelemetryInfo{}; }; /** diff --git a/src/mdns/mdns_avahi.cpp b/src/mdns/mdns_avahi.cpp index e982f12f..c0d8762d 100644 --- a/src/mdns/mdns_avahi.cpp +++ b/src/mdns/mdns_avahi.cpp @@ -53,30 +53,42 @@ #include "common/logging.hpp" #include "common/time.hpp" +namespace otbr { +namespace Mdns { + +class AvahiPoller; + +} // namespace Mdns +} // namespace otbr + struct AvahiWatch { - int mFd; ///< The file descriptor to watch. - AvahiWatchEvent mEvents; ///< The interested events. - int mHappened; ///< The events happened. - AvahiWatchCallback mCallback; ///< The function to be called when interested events happened on mFd. - void *mContext; ///< A pointer to application-specific context. - void *mPoller; ///< The poller created this watch. + typedef otbr::Mdns::AvahiPoller AvahiPoller; + + int mFd; ///< The file descriptor to watch. + AvahiWatchEvent mEvents; ///< The interested events. + int mHappened; ///< The events happened. + AvahiWatchCallback mCallback; ///< The function to be called to report events happened on `mFd`. + void *mContext; ///< A pointer to application-specific context to use with `mCallback`. + bool mShouldReport; ///< Whether or not we need to report events (invoking callback). + AvahiPoller &mPoller; ///< The poller owning this watch. /** * The constructor to initialize an Avahi watch. * * @param[in] aFd The file descriptor to watch. * @param[in] aEvents The events to watch. - * @param[in] aCallback The function to be called when events happend on this file descriptor. + * @param[in] aCallback The function to be called when events happened on this file descriptor. * @param[in] aContext A pointer to application-specific context. * @param[in] aPoller The AvahiPoller this watcher belongs to. * */ - AvahiWatch(int aFd, AvahiWatchEvent aEvents, AvahiWatchCallback aCallback, void *aContext, void *aPoller) + AvahiWatch(int aFd, AvahiWatchEvent aEvents, AvahiWatchCallback aCallback, void *aContext, AvahiPoller &aPoller) : mFd(aFd) , mEvents(aEvents) , mCallback(aCallback) , mContext(aContext) + , mShouldReport(false) , mPoller(aPoller) { } @@ -88,10 +100,13 @@ struct AvahiWatch */ struct AvahiTimeout { - otbr::Timepoint mTimeout; ///< Absolute time when this timer timeout. - AvahiTimeoutCallback mCallback; ///< The function to be called when timeout. - void *mContext; ///< The pointer to application-specific context. - void *mPoller; ///< The poller created this timer. + typedef otbr::Mdns::AvahiPoller AvahiPoller; + + otbr::Timepoint mTimeout; ///< Absolute time when this timer timeout. + AvahiTimeoutCallback mCallback; ///< The function to be called when timeout. + void *mContext; ///< The pointer to application-specific context. + bool mShouldReport; ///< Whether or not timeout occurred and need to reported (invoking callback). + AvahiPoller &mPoller; ///< The poller created this timer. /** * The constructor to initialize an AvahiTimeout. @@ -102,9 +117,10 @@ struct AvahiTimeout * @param[in] aPoller The AvahiPoller this timeout belongs to. * */ - AvahiTimeout(const struct timeval *aTimeout, AvahiTimeoutCallback aCallback, void *aContext, void *aPoller) + AvahiTimeout(const struct timeval *aTimeout, AvahiTimeoutCallback aCallback, void *aContext, AvahiPoller &aPoller) : mCallback(aCallback) , mContext(aContext) + , mShouldReport(false) , mPoller(aPoller) { if (aTimeout) @@ -168,13 +184,13 @@ class AvahiPoller : public MainloopProcessor void Update(MainloopContext &aMainloop) override; void Process(const MainloopContext &aMainloop) override; - const AvahiPoll *GetAvahiPoll(void) const { return &mAvahiPoller; } + const AvahiPoll *GetAvahiPoll(void) const { return &mAvahiPoll; } private: typedef std::vector Watches; typedef std::vector Timers; - static AvahiWatch *WatchNew(const struct AvahiPoll *aPoller, + static AvahiWatch *WatchNew(const struct AvahiPoll *aPoll, int aFd, AvahiWatchEvent aEvent, AvahiWatchCallback aCallback, @@ -184,7 +200,7 @@ class AvahiPoller : public MainloopProcessor static AvahiWatchEvent WatchGetEvents(AvahiWatch *aWatch); static void WatchFree(AvahiWatch *aWatch); void WatchFree(AvahiWatch &aWatch); - static AvahiTimeout *TimeoutNew(const AvahiPoll *aPoller, + static AvahiTimeout *TimeoutNew(const AvahiPoll *aPoll, const struct timeval *aTimeout, AvahiTimeoutCallback aCallback, void *aContext); @@ -195,36 +211,36 @@ class AvahiPoller : public MainloopProcessor Watches mWatches; Timers mTimers; - AvahiPoll mAvahiPoller; + AvahiPoll mAvahiPoll; }; AvahiPoller::AvahiPoller(void) { - mAvahiPoller.userdata = this; - mAvahiPoller.watch_new = WatchNew; - mAvahiPoller.watch_update = WatchUpdate; - mAvahiPoller.watch_get_events = WatchGetEvents; - mAvahiPoller.watch_free = WatchFree; - - mAvahiPoller.timeout_new = TimeoutNew; - mAvahiPoller.timeout_update = TimeoutUpdate; - mAvahiPoller.timeout_free = TimeoutFree; + mAvahiPoll.userdata = this; + mAvahiPoll.watch_new = WatchNew; + mAvahiPoll.watch_update = WatchUpdate; + mAvahiPoll.watch_get_events = WatchGetEvents; + mAvahiPoll.watch_free = WatchFree; + + mAvahiPoll.timeout_new = TimeoutNew; + mAvahiPoll.timeout_update = TimeoutUpdate; + mAvahiPoll.timeout_free = TimeoutFree; } -AvahiWatch *AvahiPoller::WatchNew(const struct AvahiPoll *aPoller, +AvahiWatch *AvahiPoller::WatchNew(const struct AvahiPoll *aPoll, int aFd, AvahiWatchEvent aEvent, AvahiWatchCallback aCallback, void *aContext) { - return reinterpret_cast(aPoller->userdata)->WatchNew(aFd, aEvent, aCallback, aContext); + return reinterpret_cast(aPoll->userdata)->WatchNew(aFd, aEvent, aCallback, aContext); } AvahiWatch *AvahiPoller::WatchNew(int aFd, AvahiWatchEvent aEvent, AvahiWatchCallback aCallback, void *aContext) { assert(aEvent && aCallback && aFd >= 0); - mWatches.push_back(new AvahiWatch(aFd, aEvent, aCallback, aContext, this)); + mWatches.push_back(new AvahiWatch(aFd, aEvent, aCallback, aContext, *this)); return mWatches.back(); } @@ -241,7 +257,7 @@ AvahiWatchEvent AvahiPoller::WatchGetEvents(AvahiWatch *aWatch) void AvahiPoller::WatchFree(AvahiWatch *aWatch) { - reinterpret_cast(aWatch->mPoller)->WatchFree(*aWatch); + aWatch->mPoller.WatchFree(*aWatch); } void AvahiPoller::WatchFree(AvahiWatch &aWatch) @@ -257,18 +273,18 @@ void AvahiPoller::WatchFree(AvahiWatch &aWatch) } } -AvahiTimeout *AvahiPoller::TimeoutNew(const AvahiPoll *aPoller, +AvahiTimeout *AvahiPoller::TimeoutNew(const AvahiPoll *aPoll, const struct timeval *aTimeout, AvahiTimeoutCallback aCallback, void *aContext) { - assert(aPoller && aCallback); - return static_cast(aPoller->userdata)->TimeoutNew(aTimeout, aCallback, aContext); + assert(aPoll && aCallback); + return static_cast(aPoll->userdata)->TimeoutNew(aTimeout, aCallback, aContext); } AvahiTimeout *AvahiPoller::TimeoutNew(const struct timeval *aTimeout, AvahiTimeoutCallback aCallback, void *aContext) { - mTimers.push_back(new AvahiTimeout(aTimeout, aCallback, aContext, this)); + mTimers.push_back(new AvahiTimeout(aTimeout, aCallback, aContext, *this)); return mTimers.back(); } @@ -286,7 +302,7 @@ void AvahiPoller::TimeoutUpdate(AvahiTimeout *aTimer, const struct timeval *aTim void AvahiPoller::TimeoutFree(AvahiTimeout *aTimer) { - static_cast(aTimer->mPoller)->TimeoutFree(*aTimer); + aTimer->mPoller.TimeoutFree(*aTimer); } void AvahiPoller::TimeoutFree(AvahiTimeout &aTimer) @@ -306,10 +322,10 @@ void AvahiPoller::Update(MainloopContext &aMainloop) { Timepoint now = Clock::now(); - for (Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it) + for (AvahiWatch *watch : mWatches) { - int fd = (*it)->mFd; - AvahiWatchEvent events = (*it)->mEvents; + int fd = watch->mFd; + AvahiWatchEvent events = watch->mEvents; if (AVAHI_WATCH_IN & events) { @@ -333,12 +349,12 @@ void AvahiPoller::Update(MainloopContext &aMainloop) aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd); - (*it)->mHappened = 0; + watch->mHappened = 0; } - for (Timers::iterator it = mTimers.begin(); it != mTimers.end(); ++it) + for (AvahiTimeout *timer : mTimers) { - Timepoint timeout = (*it)->mTimeout; + Timepoint timeout = timer->mTimeout; if (timeout == Timepoint::min()) { @@ -364,56 +380,92 @@ void AvahiPoller::Update(MainloopContext &aMainloop) void AvahiPoller::Process(const MainloopContext &aMainloop) { - Timepoint now = Clock::now(); - std::vector expired; + Timepoint now = Clock::now(); + bool shouldReport = false; - for (Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it) + for (AvahiWatch *watch : mWatches) { - int fd = (*it)->mFd; - AvahiWatchEvent events = (*it)->mEvents; + int fd = watch->mFd; + AvahiWatchEvent events = watch->mEvents; - (*it)->mHappened = 0; + watch->mHappened = 0; if ((AVAHI_WATCH_IN & events) && FD_ISSET(fd, &aMainloop.mReadFdSet)) { - (*it)->mHappened |= AVAHI_WATCH_IN; + watch->mHappened |= AVAHI_WATCH_IN; } if ((AVAHI_WATCH_OUT & events) && FD_ISSET(fd, &aMainloop.mWriteFdSet)) { - (*it)->mHappened |= AVAHI_WATCH_OUT; + watch->mHappened |= AVAHI_WATCH_OUT; } if ((AVAHI_WATCH_ERR & events) && FD_ISSET(fd, &aMainloop.mErrorFdSet)) { - (*it)->mHappened |= AVAHI_WATCH_ERR; + watch->mHappened |= AVAHI_WATCH_ERR; } - // TODO hup events - if ((*it)->mHappened) + if (watch->mHappened != 0) { - (*it)->mCallback(*it, (*it)->mFd, static_cast((*it)->mHappened), (*it)->mContext); + watch->mShouldReport = true; + shouldReport = true; } } - for (Timers::iterator it = mTimers.begin(); it != mTimers.end(); ++it) + // When we invoke the callback for an `AvahiWatch` or `AvahiTimeout`, + // the Avahi module can call any of `mAvahiPoll` APIs we provided to + // it. For example, it can update or free any of `AvahiWatch/Timeout` + // entries, which in turn, modifies our `mWatches` or `mTimers` list. + // So, before invoking the callback, we update the entry's state and + // then restart the iteration over the `mWacthes` list to find the + // next entry to report, as the list may have changed. + + while (shouldReport) + { + shouldReport = false; + + for (AvahiWatch *watch : mWatches) + { + if (watch->mShouldReport) + { + shouldReport = true; + watch->mShouldReport = false; + watch->mCallback(watch, watch->mFd, WatchGetEvents(watch), watch->mContext); + + break; + } + } + } + + for (AvahiTimeout *timer : mTimers) { - if ((*it)->mTimeout == Timepoint::min()) + if (timer->mTimeout == Timepoint::min()) { continue; } - if ((*it)->mTimeout <= now) + if (timer->mTimeout <= now) { - expired.push_back(*it); + timer->mShouldReport = true; + shouldReport = true; } } - for (std::vector::iterator it = expired.begin(); it != expired.end(); ++it) + while (shouldReport) { - AvahiTimeout *avahiTimeout = *it; + shouldReport = false; + + for (AvahiTimeout *timer : mTimers) + { + if (timer->mShouldReport) + { + shouldReport = true; + timer->mShouldReport = false; + timer->mCallback(timer, timer->mContext); - avahiTimeout->mCallback(avahiTimeout, avahiTimeout->mContext); + break; + } + } } } @@ -639,13 +691,12 @@ otbrError PublisherAvahi::PublishServiceImpl(const std::string &aHostName, const std::string &aType, const SubTypeList &aSubTypeList, uint16_t aPort, - const TxtList &aTxtList, + const TxtData &aTxtData, ResultCallback &&aCallback) { otbrError error = OTBR_ERROR_NONE; int avahiError = AVAHI_OK; SubTypeList sortedSubTypeList = SortSubTypeList(aSubTypeList); - TxtList sortedTxtList = SortTxtList(aTxtList); const std::string logHostName = !aHostName.empty() ? aHostName : "localhost"; std::string fullHostName; std::string serviceName = aName; @@ -667,11 +718,11 @@ otbrError PublisherAvahi::PublishServiceImpl(const std::string &aHostName, serviceName = avahi_client_get_host_name(mClient); } - aCallback = HandleDuplicateServiceRegistration(aHostName, serviceName, aType, sortedSubTypeList, aPort, - sortedTxtList, std::move(aCallback)); + aCallback = HandleDuplicateServiceRegistration(aHostName, serviceName, aType, sortedSubTypeList, aPort, aTxtData, + std::move(aCallback)); VerifyOrExit(!aCallback.IsNull()); - SuccessOrExit(error = TxtListToAvahiStringList(aTxtList, txtBuffer, sizeof(txtBuffer), txtHead)); + SuccessOrExit(error = TxtDataToAvahiStringList(aTxtData, txtBuffer, sizeof(txtBuffer), txtHead)); VerifyOrExit((group = CreateGroup(mClient)) != nullptr, error = OTBR_ERROR_MDNS); avahiError = avahi_entry_group_add_service_strlst(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags{}, serviceName.c_str(), aType.c_str(), @@ -693,7 +744,7 @@ otbrError PublisherAvahi::PublishServiceImpl(const std::string &aHostName, VerifyOrExit(avahiError == AVAHI_OK); AddServiceRegistration(std::unique_ptr(new AvahiServiceRegistration( - aHostName, serviceName, aType, sortedSubTypeList, aPort, sortedTxtList, std::move(aCallback), group, this))); + aHostName, serviceName, aType, sortedSubTypeList, aPort, aTxtData, std::move(aCallback), group, this))); exit: if (avahiError != AVAHI_OK || error != OTBR_ERROR_NONE) @@ -724,9 +775,9 @@ void PublisherAvahi::UnpublishService(const std::string &aName, const std::strin std::move(aCallback)(error); } -otbrError PublisherAvahi::PublishHostImpl(const std::string &aName, - const std::vector &aAddresses, - ResultCallback &&aCallback) +otbrError PublisherAvahi::PublishHostImpl(const std::string &aName, + const AddressList &aAddresses, + ResultCallback &&aCallback) { otbrError error = OTBR_ERROR_NONE; int avahiError = AVAHI_OK; @@ -790,7 +841,7 @@ void PublisherAvahi::UnpublishHost(const std::string &aName, ResultCallback &&aC std::move(aCallback)(error); } -otbrError PublisherAvahi::TxtListToAvahiStringList(const TxtList &aTxtList, +otbrError PublisherAvahi::TxtDataToAvahiStringList(const TxtData &aTxtData, AvahiStringList *aBuffer, size_t aBufferSize, AvahiStringList *&aHead) @@ -799,32 +850,40 @@ otbrError PublisherAvahi::TxtListToAvahiStringList(const TxtList &aTxtList, size_t used = 0; AvahiStringList *last = nullptr; AvahiStringList *curr = aBuffer; + const uint8_t *next; + const uint8_t *data = aTxtData.data(); + const uint8_t *dataEnd = aTxtData.data() + aTxtData.size(); aHead = nullptr; - for (const auto &txtEntry : aTxtList) + + while (data < dataEnd) { - const char *name = txtEntry.mName.c_str(); - size_t nameLength = txtEntry.mName.length(); - const uint8_t *value = txtEntry.mValue.data(); - size_t valueLength = txtEntry.mValue.size(); - // +1 for the size of "=", avahi doesn't need '\0' at the end of the entry - size_t needed = sizeof(AvahiStringList) - sizeof(AvahiStringList::text) + nameLength + valueLength + 1; + uint8_t entryLength = *data++; + size_t needed = sizeof(AvahiStringList) - sizeof(AvahiStringList::text) + entryLength; + + if (entryLength == 0) + { + continue; + } + + VerifyOrExit(data + entryLength <= dataEnd, error = OTBR_ERROR_PARSE); VerifyOrExit(used + needed <= aBufferSize, error = OTBR_ERROR_INVALID_ARGS); curr->next = last; last = curr; - memcpy(curr->text, name, nameLength); - curr->text[nameLength] = '='; - memcpy(curr->text + nameLength + 1, value, valueLength); - curr->size = nameLength + valueLength + 1; - { - const uint8_t *next = curr->text + curr->size; - curr = OTBR_ALIGNED(next, AvahiStringList *); - } + + memcpy(curr->text, data, entryLength); + curr->size = entryLength; + + data += entryLength; + + next = curr->text + curr->size; + curr = OTBR_ALIGNED(next, AvahiStringList *); used = static_cast(reinterpret_cast(curr) - reinterpret_cast(aBuffer)); } - SuccessOrExit(error); + aHead = last; + exit: return error; } @@ -1349,7 +1408,6 @@ void PublisherAvahi::HostSubscription::HandleResolveResult(AvahiRecordBrowser AvahiLookupResultFlags aFlags) { OTBR_UNUSED_VARIABLE(aRecordBrowser); - OTBR_UNUSED_VARIABLE(aInterfaceIndex); OTBR_UNUSED_VARIABLE(aProtocol); OTBR_UNUSED_VARIABLE(aEvent); OTBR_UNUSED_VARIABLE(aClazz); @@ -1378,6 +1436,7 @@ void PublisherAvahi::HostSubscription::HandleResolveResult(AvahiRecordBrowser mHostInfo.mHostName = std::string(aName) + "."; mHostInfo.mAddresses.push_back(std::move(address)); + mHostInfo.mNetifIndex = static_cast(aInterfaceIndex); // TODO: Use a more proper TTL mHostInfo.mTtl = kDefaultTtl; resolved = true; diff --git a/src/mdns/mdns_avahi.hpp b/src/mdns/mdns_avahi.hpp index f1f48b0f..844e2429 100644 --- a/src/mdns/mdns_avahi.hpp +++ b/src/mdns/mdns_avahi.hpp @@ -92,11 +92,11 @@ class PublisherAvahi : public Publisher const std::string &aType, const SubTypeList &aSubTypeList, uint16_t aPort, - const TxtList &aTxtList, + const TxtData &aTxtData, ResultCallback &&aCallback) override; - otbrError PublishHostImpl(const std::string &aName, - const std::vector &aAddresses, - ResultCallback &&aCallback) override; + otbrError PublishHostImpl(const std::string &aName, + const AddressList &aAddresses, + ResultCallback &&aCallback) override; void OnServiceResolveFailedImpl(const std::string &aType, const std::string &aInstanceName, int32_t aErrorCode) override; @@ -115,7 +115,7 @@ class PublisherAvahi : public Publisher const std::string &aType, const SubTypeList &aSubTypeList, uint16_t aPort, - const TxtList &aTxtList, + const TxtData &aTxtData, ResultCallback &&aCallback, AvahiEntryGroup *aEntryGroup, PublisherAvahi *aPublisher) @@ -124,7 +124,7 @@ class PublisherAvahi : public Publisher aType, aSubTypeList, aPort, - aTxtList, + aTxtData, std::move(aCallback), aPublisher) , mEntryGroup(aEntryGroup) @@ -141,11 +141,11 @@ class PublisherAvahi : public Publisher class AvahiHostRegistration : public HostRegistration { public: - AvahiHostRegistration(const std::string &aName, - const std::vector &aAddresses, - ResultCallback &&aCallback, - AvahiEntryGroup *aEntryGroup, - PublisherAvahi *aPublisher) + AvahiHostRegistration(const std::string &aName, + const AddressList &aAddresses, + ResultCallback &&aCallback, + AvahiEntryGroup *aEntryGroup, + PublisherAvahi *aPublisher) : HostRegistration(aName, aAddresses, std::move(aCallback), aPublisher) , mEntryGroup(aEntryGroup) { @@ -340,7 +340,7 @@ class PublisherAvahi : public Publisher void HandleGroupState(AvahiEntryGroup *aGroup, AvahiEntryGroupState aState); void CallHostOrServiceCallback(AvahiEntryGroup *aGroup, otbrError aError); - static otbrError TxtListToAvahiStringList(const TxtList &aTxtList, + static otbrError TxtDataToAvahiStringList(const TxtData &aTxtData, AvahiStringList *aBuffer, size_t aBufferSize, AvahiStringList *&aHead); diff --git a/src/mdns/mdns_mdnssd.cpp b/src/mdns/mdns_mdnssd.cpp index f95d2f50..2dc4c27a 100644 --- a/src/mdns/mdns_mdnssd.cpp +++ b/src/mdns/mdns_mdnssd.cpp @@ -222,7 +222,7 @@ PublisherMDnsSd::PublisherMDnsSd(StateCallback aCallback) PublisherMDnsSd::~PublisherMDnsSd(void) { - Stop(); + Stop(kNormalStop); } otbrError PublisherMDnsSd::Start(void) @@ -237,25 +237,31 @@ bool PublisherMDnsSd::IsStarted(void) const return mState == State::kReady; } -void PublisherMDnsSd::Stop(void) +void PublisherMDnsSd::Stop(StopMode aStopMode) { - ServiceRegistrationMap serviceRegistrations; - HostRegistrationMap hostRegistrations; - VerifyOrExit(mState == State::kReady); - std::swap(mServiceRegistrations, serviceRegistrations); - std::swap(mHostRegistrations, hostRegistrations); + // If we get a `kDNSServiceErr_ServiceNotRunning` and need to + // restart the `Publisher`, we should immediately de-allocate + // all `ServiceRef`. Otherwise, we first clear the `Registrations` + // list so that `DnssdHostRegisteration` destructor gets the chance + // to update registered records if needed. - if (mHostsRef != nullptr) + switch (aStopMode) { - DNSServiceRefDeallocate(mHostsRef); - otbrLogDebug("Deallocated DNSServiceRef for hosts: %p", mHostsRef); - mHostsRef = nullptr; + case kNormalStop: + break; + + case kStopOnServiceNotRunningError: + DeallocateHostsRef(); + break; } - mSubscribedServices.clear(); + mServiceRegistrations.clear(); + mHostRegistrations.clear(); + DeallocateHostsRef(); + mSubscribedServices.clear(); mSubscribedHosts.clear(); mState = State::kIdle; @@ -264,21 +270,39 @@ void PublisherMDnsSd::Stop(void) return; } +DNSServiceErrorType PublisherMDnsSd::CreateSharedHostsRef(void) +{ + DNSServiceErrorType dnsError = kDNSServiceErr_NoError; + + VerifyOrExit(mHostsRef == nullptr); + + dnsError = DNSServiceCreateConnection(&mHostsRef); + otbrLogDebug("Created new shared DNSServiceRef: %p", mHostsRef); + +exit: + return dnsError; +} + +void PublisherMDnsSd::DeallocateHostsRef(void) +{ + VerifyOrExit(mHostsRef != nullptr); + + HandleServiceRefDeallocating(mHostsRef); + DNSServiceRefDeallocate(mHostsRef); + otbrLogDebug("Deallocated DNSServiceRef for hosts: %p", mHostsRef); + mHostsRef = nullptr; + +exit: + return; +} + void PublisherMDnsSd::Update(MainloopContext &aMainloop) { for (auto &kv : mServiceRegistrations) { auto &serviceReg = static_cast(*kv.second); - assert(serviceReg.GetServiceRef() != nullptr); - - int fd = DNSServiceRefSockFD(serviceReg.GetServiceRef()); - - if (fd != -1) - { - FD_SET(fd, &aMainloop.mReadFdSet); - aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd); - } + serviceReg.Update(aMainloop); } if (mHostsRef != nullptr) @@ -305,17 +329,13 @@ void PublisherMDnsSd::Update(MainloopContext &aMainloop) void PublisherMDnsSd::Process(const MainloopContext &aMainloop) { - std::vector readyServices; + mServiceRefsToProcess.clear(); for (auto &kv : mServiceRegistrations) { auto &serviceReg = static_cast(*kv.second); - int fd = DNSServiceRefSockFD(serviceReg.GetServiceRef()); - if (FD_ISSET(fd, &aMainloop.mReadFdSet)) - { - readyServices.push_back(serviceReg.GetServiceRef()); - } + serviceReg.Process(aMainloop, mServiceRefsToProcess); } if (mHostsRef != nullptr) @@ -324,23 +344,41 @@ void PublisherMDnsSd::Process(const MainloopContext &aMainloop) if (FD_ISSET(fd, &aMainloop.mReadFdSet)) { - readyServices.push_back(mHostsRef); + mServiceRefsToProcess.push_back(mHostsRef); } } for (const auto &service : mSubscribedServices) { - service->ProcessAll(aMainloop, readyServices); + service->ProcessAll(aMainloop, mServiceRefsToProcess); } for (const auto &host : mSubscribedHosts) { - host->Process(aMainloop, readyServices); + host->Process(aMainloop, mServiceRefsToProcess); } - for (DNSServiceRef serviceRef : readyServices) + for (DNSServiceRef serviceRef : mServiceRefsToProcess) { - DNSServiceErrorType error = DNSServiceProcessResult(serviceRef); + DNSServiceErrorType error; + + // As we go through the list of `mServiceRefsToProcess` the call + // to `DNSServiceProcessResult()` can itself invoke callbacks + // into `PublisherMDnsSd` and OT, which in turn, may change the + // state of `Publisher` and potentially trigger a previously + // valid `ServiceRef` in the list to be deallocated. We use + // `HandleServiceRefDeallocating()` which is called whenever a + // `ServiceRef` is being deallocated and from this we update + // the entry in `mServiceRefsToProcess` list to `nullptr` so to + // avoid calling `DNSServiceProcessResult()` on an already + // freed `ServiceRef`. + + if (serviceRef == nullptr) + { + continue; + } + + error = DNSServiceProcessResult(serviceRef); if (error != kDNSServiceErr_NoError) { @@ -351,7 +389,7 @@ void PublisherMDnsSd::Process(const MainloopContext &aMainloop) if (error == kDNSServiceErr_ServiceNotRunning) { otbrLogWarning("Need to reconnect to mdnsd"); - Stop(); + Stop(kStopOnServiceNotRunningError); Start(); ExitNow(); } @@ -360,129 +398,235 @@ void PublisherMDnsSd::Process(const MainloopContext &aMainloop) return; } -PublisherMDnsSd::DnssdServiceRegistration::~DnssdServiceRegistration(void) +void PublisherMDnsSd::HandleServiceRefDeallocating(const DNSServiceRef &aServiceRef) { - if (mServiceRef != nullptr) + for (DNSServiceRef &entry : mServiceRefsToProcess) { - DNSServiceRefDeallocate(mServiceRef); + if (entry == aServiceRef) + { + entry = nullptr; + } } } -PublisherMDnsSd::DnssdHostRegistration::~DnssdHostRegistration(void) +void PublisherMDnsSd::DnssdServiceRegistration::Update(MainloopContext &aMainloop) const { - int dnsError; + int fd; VerifyOrExit(mServiceRef != nullptr); - for (const auto &recordRefAndAddress : GetRecordRefMap()) - { - const DNSRecordRef &recordRef = recordRefAndAddress.first; - const Ip6Address &address = recordRefAndAddress.second; - if (IsCompleted()) - { - // The Bonjour mDNSResponder somehow doesn't send goodbye message for the AAAA record when it is - // removed by `DNSServiceRemoveRecord`. Per RFC 6762, a goodbye message of a record sets its TTL - // to zero but the receiver should record the TTL of 1 and flushes the cache 1 second later. Here - // we remove the AAAA record after updating its TTL to 1 second. This has the same effect as - // sending a goodbye message. - // TODO: resolve the goodbye issue with Bonjour mDNSResponder. - dnsError = DNSServiceUpdateRecord(mServiceRef, recordRef, kDNSServiceFlagsUnique, sizeof(address.m8), - address.m8, /* ttl */ 1); - otbrLogResult(DNSErrorToOtbrError(dnsError), "Send goodbye message for host %s address %s: %s", - MakeFullHostName(mName).c_str(), address.ToString().c_str(), DNSErrorToString(dnsError)); - } - dnsError = DNSServiceRemoveRecord(mServiceRef, recordRef, /* flags */ 0); - otbrLogResult(DNSErrorToOtbrError(dnsError), "Remove record for host %s address %s: %s", - MakeFullHostName(mName).c_str(), address.ToString().c_str(), DNSErrorToString(dnsError)); - // TODO: ? - // DNSRecordRefDeallocate(recordRef); - } + fd = DNSServiceRefSockFD(mServiceRef); + VerifyOrExit(fd != -1); + + FD_SET(fd, &aMainloop.mReadFdSet); + aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd); exit: return; } -Publisher::ServiceRegistration *PublisherMDnsSd::FindServiceRegistration(const DNSServiceRef &aServiceRef) +void PublisherMDnsSd::DnssdServiceRegistration::Process(const MainloopContext &aMainloop, + std::vector &aReadyServices) const { - ServiceRegistration *result = nullptr; + int fd; - for (auto &kv : mServiceRegistrations) - { - // We are sure that the service registrations must be instances of `DnssdServiceRegistration`. - auto &serviceReg = static_cast(*kv.second); + VerifyOrExit(mServiceRef != nullptr); - if (serviceReg.GetServiceRef() == aServiceRef) - { - result = kv.second.get(); - break; - } - } + fd = DNSServiceRefSockFD(mServiceRef); + VerifyOrExit(fd != -1); - return result; + VerifyOrExit(FD_ISSET(fd, &aMainloop.mReadFdSet)); + aReadyServices.push_back(mServiceRef); + +exit: + return; } -Publisher::HostRegistration *PublisherMDnsSd::FindHostRegistration(const DNSServiceRef &aServiceRef, - const DNSRecordRef &aRecordRef) +otbrError PublisherMDnsSd::DnssdServiceRegistration::Register(void) { - HostRegistration *result = nullptr; + std::string fullHostName; + std::string regType = MakeRegType(mType, mSubTypeList); + const char *hostNameCString = nullptr; + const char *serviceNameCString = nullptr; + DNSServiceErrorType dnsError; + + if (!mHostName.empty()) + { + fullHostName = MakeFullHostName(mHostName); + hostNameCString = fullHostName.c_str(); + } - for (auto &kv : mHostRegistrations) + if (!mName.empty()) { - // We are sure that the host registrations must be instances of `DnssdHostRegistration`. - auto &hostReg = static_cast(*kv.second); + serviceNameCString = mName.c_str(); + } - if (hostReg.GetServiceRef() == aServiceRef && hostReg.GetRecordRefMap().count(aRecordRef)) - { - result = kv.second.get(); - break; - } + otbrLogInfo("Registering service %s.%s", mName.c_str(), regType.c_str()); + + dnsError = DNSServiceRegister(&mServiceRef, kDNSServiceFlagsNoAutoRename, kDNSServiceInterfaceIndexAny, + serviceNameCString, regType.c_str(), + /* domain */ nullptr, hostNameCString, htons(mPort), mTxtData.size(), mTxtData.data(), + HandleRegisterResult, this); + + if (dnsError != kDNSServiceErr_NoError) + { + HandleRegisterResult(/* aFlags */ 0, dnsError); } - return result; + return GetPublisher().DnsErrorToOtbrError(dnsError); } -void PublisherMDnsSd::HandleServiceRegisterResult(DNSServiceRef aService, - const DNSServiceFlags aFlags, - DNSServiceErrorType aError, - const char *aName, - const char *aType, - const char *aDomain, - void *aContext) +void PublisherMDnsSd::DnssdServiceRegistration::Unregister(void) { - static_cast(aContext)->HandleServiceRegisterResult(aService, aFlags, aError, aName, aType, - aDomain); + if (mServiceRef != nullptr) + { + GetPublisher().HandleServiceRefDeallocating(mServiceRef); + DNSServiceRefDeallocate(mServiceRef); + mServiceRef = nullptr; + } } -void PublisherMDnsSd::HandleServiceRegisterResult(DNSServiceRef aServiceRef, - const DNSServiceFlags aFlags, - DNSServiceErrorType aError, - const char *aName, - const char *aType, - const char *aDomain) +void PublisherMDnsSd::DnssdServiceRegistration::HandleRegisterResult(DNSServiceRef aServiceRef, + DNSServiceFlags aFlags, + DNSServiceErrorType aError, + const char *aName, + const char *aType, + const char *aDomain, + void *aContext) { + OTBR_UNUSED_VARIABLE(aServiceRef); + OTBR_UNUSED_VARIABLE(aName); + OTBR_UNUSED_VARIABLE(aType); OTBR_UNUSED_VARIABLE(aDomain); - otbrError error = DNSErrorToOtbrError(aError); - ServiceRegistration *serviceReg = FindServiceRegistration(aServiceRef); - serviceReg->mName = aName; + static_cast(aContext)->HandleRegisterResult(aFlags, aError); +} - otbrLogInfo("Received reply for service %s.%s, serviceRef = %p", aName, aType, aServiceRef); +void PublisherMDnsSd::DnssdServiceRegistration::HandleRegisterResult(DNSServiceFlags aFlags, DNSServiceErrorType aError) +{ + if ((aError == kDNSServiceErr_NoError) && (aFlags & kDNSServiceFlagsAdd)) + { + otbrLogInfo("Successfully registered service %s.%s", mName.c_str(), mType.c_str()); + Complete(OTBR_ERROR_NONE); + } + else + { + otbrLogErr("Failed to register service %s.%s: %s", mName.c_str(), mType.c_str(), DNSErrorToString(aError)); + GetPublisher().RemoveServiceRegistration(mName, mType, DNSErrorToOtbrError(aError)); + } +} + +otbrError PublisherMDnsSd::DnssdHostRegistration::Register(void) +{ + DNSServiceErrorType dnsError = kDNSServiceErr_NoError; - VerifyOrExit(serviceReg != nullptr); + otbrLogInfo("Registering new host %s", mName.c_str()); - if (aError == kDNSServiceErr_NoError && (aFlags & kDNSServiceFlagsAdd)) + for (const Ip6Address &address : mAddresses) { - otbrLogInfo("Successfully registered service %s.%s", aName, aType); - serviceReg->Complete(OTBR_ERROR_NONE); + DNSRecordRef recordRef = nullptr; + + dnsError = GetPublisher().CreateSharedHostsRef(); + VerifyOrExit(dnsError == kDNSServiceErr_NoError); + + dnsError = DNSServiceRegisterRecord(GetPublisher().mHostsRef, &recordRef, kDNSServiceFlagsShared, + kDNSServiceInterfaceIndexAny, MakeFullHostName(mName).c_str(), + kDNSServiceType_AAAA, kDNSServiceClass_IN, sizeof(address.m8), address.m8, + /* ttl */ 0, HandleRegisterResult, this); + VerifyOrExit(dnsError == kDNSServiceErr_NoError); + + mAddrRecordRefs.push_back(recordRef); + mAddrRegistered.push_back(false); } - else + +exit: + if ((dnsError != kDNSServiceErr_NoError) || mAddresses.empty()) { - otbrLogErr("Failed to register service %s.%s: %s", aName, aType, DNSErrorToString(aError)); - RemoveServiceRegistration(serviceReg->mName, serviceReg->mType, error); + HandleRegisterResult(/* aRecordRef */ nullptr, dnsError); + } + + return GetPublisher().DnsErrorToOtbrError(dnsError); +} + +void PublisherMDnsSd::DnssdHostRegistration::Unregister(void) +{ + DNSServiceErrorType dnsError; + + VerifyOrExit(GetPublisher().mHostsRef != nullptr); + + for (size_t index = 0; index < mAddrRecordRefs.size(); index++) + { + const Ip6Address &address = mAddresses[index]; + + if (mAddrRegistered[index]) + { + // The Bonjour mDNSResponder somehow doesn't send goodbye message for the AAAA record when it is + // removed by `DNSServiceRemoveRecord`. Per RFC 6762, a goodbye message of a record sets its TTL + // to zero but the receiver should record the TTL of 1 and flushes the cache 1 second later. Here + // we remove the AAAA record after updating its TTL to 1 second. This has the same effect as + // sending a goodbye message. + // TODO: resolve the goodbye issue with Bonjour mDNSResponder. + dnsError = DNSServiceUpdateRecord(GetPublisher().mHostsRef, mAddrRecordRefs[index], kDNSServiceFlagsUnique, + sizeof(address.m8), address.m8, /* ttl */ 1); + otbrLogResult(DNSErrorToOtbrError(dnsError), "Send goodbye message for host %s address %s: %s", + MakeFullHostName(mName).c_str(), address.ToString().c_str(), DNSErrorToString(dnsError)); + } + + dnsError = DNSServiceRemoveRecord(GetPublisher().mHostsRef, mAddrRecordRefs[index], /* flags */ 0); + + otbrLogResult(DNSErrorToOtbrError(dnsError), "Remove record for host %s address %s: %s", + MakeFullHostName(mName).c_str(), address.ToString().c_str(), DNSErrorToString(dnsError)); } exit: - return; + mAddrRegistered.clear(); + mAddrRecordRefs.clear(); +} + +void PublisherMDnsSd::DnssdHostRegistration::HandleRegisterResult(DNSServiceRef aServiceRef, + DNSRecordRef aRecordRef, + DNSServiceFlags aFlags, + DNSServiceErrorType aError, + void *aContext) +{ + OT_UNUSED_VARIABLE(aServiceRef); + OT_UNUSED_VARIABLE(aFlags); + + static_cast(aContext)->HandleRegisterResult(aRecordRef, aError); +} + +void PublisherMDnsSd::DnssdHostRegistration::HandleRegisterResult(DNSRecordRef aRecordRef, DNSServiceErrorType aError) +{ + if (aError != kDNSServiceErr_NoError) + { + otbrLogErr("Failed to register host %s: %s", mName.c_str(), DNSErrorToString(aError)); + GetPublisher().RemoveHostRegistration(mName, DNSErrorToOtbrError(aError)); + } + else + { + bool shouldComplete = !IsCompleted(); + + for (size_t index = 0; index < mAddrRecordRefs.size(); index++) + { + if ((mAddrRecordRefs[index] == aRecordRef) && !mAddrRegistered[index]) + { + mAddrRegistered[index] = true; + otbrLogInfo("Successfully registered host %s address %s", mName.c_str(), + mAddresses[index].ToString().c_str()); + } + + if (!mAddrRegistered[index]) + { + shouldComplete = false; + } + } + + if (shouldComplete) + { + otbrLogInfo("Successfully registered all host %s addresses", mName.c_str()); + Complete(OTBR_ERROR_NONE); + } + } } otbrError PublisherMDnsSd::PublishServiceImpl(const std::string &aHostName, @@ -490,62 +634,33 @@ otbrError PublisherMDnsSd::PublishServiceImpl(const std::string &aHostName, const std::string &aType, const SubTypeList &aSubTypeList, uint16_t aPort, - const TxtList &aTxtList, + const TxtData &aTxtData, ResultCallback &&aCallback) { - otbrError ret = OTBR_ERROR_NONE; - int error = 0; - std::vector txt; - SubTypeList sortedSubTypeList = SortSubTypeList(aSubTypeList); - TxtList sortedTxtList = SortTxtList(aTxtList); - std::string regType = MakeRegType(aType, sortedSubTypeList); - DNSServiceRef serviceRef = nullptr; - std::string fullHostName; - const char *hostNameCString = nullptr; - const char *serviceNameCString = nullptr; - - VerifyOrExit(mState == State::kReady, ret = OTBR_ERROR_INVALID_STATE); - - if (!aHostName.empty()) - { - fullHostName = MakeFullHostName(aHostName); - hostNameCString = fullHostName.c_str(); - } - if (!aName.empty()) + otbrError error = OTBR_ERROR_NONE; + SubTypeList sortedSubTypeList = SortSubTypeList(aSubTypeList); + std::string regType = MakeRegType(aType, sortedSubTypeList); + DnssdServiceRegistration *serviceReg; + + if (mState != State::kReady) { - serviceNameCString = aName.c_str(); + error = OTBR_ERROR_INVALID_STATE; + std::move(aCallback)(error); + ExitNow(); } - aCallback = HandleDuplicateServiceRegistration(aHostName, aName, aType, sortedSubTypeList, aPort, sortedTxtList, + aCallback = HandleDuplicateServiceRegistration(aHostName, aName, aType, sortedSubTypeList, aPort, aTxtData, std::move(aCallback)); VerifyOrExit(!aCallback.IsNull()); - SuccessOrExit(ret = EncodeTxtData(aTxtList, txt)); - otbrLogInfo("Registering new service %s.%s.local, serviceRef = %p", aName.c_str(), regType.c_str(), serviceRef); - SuccessOrExit(error = DNSServiceRegister(&serviceRef, kDNSServiceFlagsNoAutoRename, kDNSServiceInterfaceIndexAny, - serviceNameCString, regType.c_str(), - /* domain */ nullptr, hostNameCString, htons(aPort), txt.size(), - txt.data(), HandleServiceRegisterResult, this)); - AddServiceRegistration(std::unique_ptr(new DnssdServiceRegistration( - aHostName, aName, aType, sortedSubTypeList, aPort, sortedTxtList, std::move(aCallback), serviceRef, this))); + serviceReg = new DnssdServiceRegistration(aHostName, aName, aType, sortedSubTypeList, aPort, aTxtData, + std::move(aCallback), this); + AddServiceRegistration(std::unique_ptr(serviceReg)); -exit: - if (error != kDNSServiceErr_NoError || ret != OTBR_ERROR_NONE) - { - if (error != kDNSServiceErr_NoError) - { - ret = DNSErrorToOtbrError(error); - otbrLogErr("Failed to publish service %s.%s for mdnssd error: %s!", aName.c_str(), aType.c_str(), - DNSErrorToString(error)); - } + error = serviceReg->Register(); - if (serviceRef != nullptr) - { - DNSServiceRefDeallocate(serviceRef); - } - std::move(aCallback)(ret); - } - return ret; +exit: + return error; } void PublisherMDnsSd::UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback) @@ -559,58 +674,30 @@ void PublisherMDnsSd::UnpublishService(const std::string &aName, const std::stri std::move(aCallback)(error); } -otbrError PublisherMDnsSd::PublishHostImpl(const std::string &aName, - const std::vector &aAddresses, - ResultCallback &&aCallback) +otbrError PublisherMDnsSd::PublishHostImpl(const std::string &aName, + const AddressList &aAddresses, + ResultCallback &&aCallback) { - otbrError ret = OTBR_ERROR_NONE; - int error = 0; - std::string fullName; - DnssdHostRegistration *registration; - - VerifyOrExit(mState == Publisher::State::kReady, ret = OTBR_ERROR_INVALID_STATE); + otbrError error = OTBR_ERROR_NONE; + DnssdHostRegistration *hostReg; - fullName = MakeFullHostName(aName); - - aCallback = HandleDuplicateHostRegistration(aName, aAddresses, std::move(aCallback)); - VerifyOrExit(!aCallback.IsNull()); - VerifyOrExit(!aAddresses.empty(), std::move(aCallback)(OTBR_ERROR_NONE)); - - if (mHostsRef == nullptr) + if (mState != State::kReady) { - SuccessOrExit(error = DNSServiceCreateConnection(&mHostsRef)); - otbrLogDebug("Created new DNSServiceRef for hosts: %p", mHostsRef); + error = OTBR_ERROR_INVALID_STATE; + std::move(aCallback)(error); + ExitNow(); } - registration = new DnssdHostRegistration(aName, aAddresses, std::move(aCallback), mHostsRef, this); + aCallback = HandleDuplicateHostRegistration(aName, aAddresses, std::move(aCallback)); + VerifyOrExit(!aCallback.IsNull()); - otbrLogInfo("Registering new host %s", aName.c_str()); - for (const auto &address : aAddresses) - { - DNSRecordRef recordRef = nullptr; - // Supports only IPv6 for now, may support IPv4 in the future. - SuccessOrExit(error = DNSServiceRegisterRecord(mHostsRef, &recordRef, kDNSServiceFlagsShared, - kDNSServiceInterfaceIndexAny, fullName.c_str(), - kDNSServiceType_AAAA, kDNSServiceClass_IN, sizeof(address.m8), - address.m8, /* ttl */ 0, HandleRegisterHostResult, this)); - registration->GetRecordRefMap()[recordRef] = address; - } + hostReg = new DnssdHostRegistration(aName, aAddresses, std::move(aCallback), this); + AddHostRegistration(std::unique_ptr(hostReg)); - AddHostRegistration(std::unique_ptr(registration)); + error = hostReg->Register(); exit: - if (error != kDNSServiceErr_NoError || ret != OTBR_ERROR_NONE) - { - if (error != kDNSServiceErr_NoError) - { - ret = DNSErrorToOtbrError(error); - otbrLogErr("Failed to publish/update host %s for mdnssd error: %s!", aName.c_str(), - DNSErrorToString(error)); - } - - std::move(aCallback)(ret); - } - return ret; + return error; } void PublisherMDnsSd::UnpublishHost(const std::string &aName, ResultCallback &&aCallback) @@ -627,52 +714,6 @@ void PublisherMDnsSd::UnpublishHost(const std::string &aName, ResultCallback &&a std::move(aCallback)(error); } -void PublisherMDnsSd::HandleRegisterHostResult(DNSServiceRef aServiceRef, - DNSRecordRef aRecordRef, - DNSServiceFlags aFlags, - DNSServiceErrorType aError, - void *aContext) -{ - static_cast(aContext)->HandleRegisterHostResult(aServiceRef, aRecordRef, aFlags, aError); -} - -void PublisherMDnsSd::HandleRegisterHostResult(DNSServiceRef aServiceRef, - DNSRecordRef aRecordRef, - DNSServiceFlags aFlags, - DNSServiceErrorType aError) -{ - OTBR_UNUSED_VARIABLE(aFlags); - - otbrError error = DNSErrorToOtbrError(aError); - auto *hostReg = static_cast(FindHostRegistration(aServiceRef, aRecordRef)); - - std::string hostName; - - VerifyOrExit(hostReg != nullptr); - - hostName = MakeFullHostName(hostReg->mName); - - otbrLogInfo("Received reply for host %s: %s", hostName.c_str(), DNSErrorToString(aError)); - - if (error == OTBR_ERROR_NONE) - { - --hostReg->mCallbackCount; - if (!hostReg->mCallbackCount) - { - otbrLogInfo("Successfully registered host %s", hostName.c_str()); - hostReg->Complete(OTBR_ERROR_NONE); - } - } - else - { - otbrLogWarning("Failed to register host %s for mdnssd error: %s", hostName.c_str(), DNSErrorToString(aError)); - RemoveHostRegistration(hostReg->mName, error); - } - -exit: - return; -} - // See `regtype` parameter of the DNSServiceRegister() function for more information. std::string PublisherMDnsSd::MakeRegType(const std::string &aType, SubTypeList aSubTypeList) { @@ -797,6 +838,7 @@ void PublisherMDnsSd::ServiceRef::DeallocateServiceRef(void) { if (mServiceRef != nullptr) { + mPublisher.HandleServiceRefDeallocating(mServiceRef); DNSServiceRefDeallocate(mServiceRef); mServiceRef = nullptr; } @@ -878,13 +920,13 @@ void PublisherMDnsSd::ServiceSubscription::HandleBrowseResult(DNSServiceRef } else { - mMDnsSd->OnServiceRemoved(aInterfaceIndex, mType, aInstanceName); + mPublisher.OnServiceRemoved(aInterfaceIndex, mType, aInstanceName); } exit: if (aErrorCode != kDNSServiceErr_NoError) { - mMDnsSd->OnServiceResolveFailed(mType, mInstanceName, aErrorCode); + mPublisher.OnServiceResolveFailed(mType, mInstanceName, aErrorCode); Release(); } } @@ -937,12 +979,11 @@ void PublisherMDnsSd::ServiceInstanceResolution::Resolve(void) { assert(mServiceRef == nullptr); - mSubscription->mMDnsSd->mServiceInstanceResolutionBeginTime[std::make_pair(mInstanceName, mTypeEndWithDot)] = - Clock::now(); + mSubscription->mPublisher.mServiceInstanceResolutionBeginTime[std::make_pair(mInstanceName, mType)] = Clock::now(); - otbrLogInfo("DNSServiceResolve %s %s inf %u", mInstanceName.c_str(), mTypeEndWithDot.c_str(), mNetifIndex); + otbrLogInfo("DNSServiceResolve %s %s inf %u", mInstanceName.c_str(), mType.c_str(), mNetifIndex); DNSServiceResolve(&mServiceRef, /* flags */ kDNSServiceFlagsTimeout, mNetifIndex, mInstanceName.c_str(), - mTypeEndWithDot.c_str(), mDomain.c_str(), HandleResolveResult, this); + mType.c_str(), mDomain.c_str(), HandleResolveResult, this); } void PublisherMDnsSd::ServiceInstanceResolution::HandleResolveResult(DNSServiceRef aServiceRef, @@ -1002,7 +1043,7 @@ void PublisherMDnsSd::ServiceInstanceResolution::HandleResolveResult(DNSServiceR if (aErrorCode != kDNSServiceErr_NoError || error != OTBR_ERROR_NONE) { - mSubscription->mMDnsSd->OnServiceResolveFailed(mSubscription->mType, mInstanceName, aErrorCode); + mSubscription->mPublisher.OnServiceResolveFailed(mSubscription->mType, mInstanceName, aErrorCode); FinishResolution(); } } @@ -1087,7 +1128,7 @@ void PublisherMDnsSd::ServiceInstanceResolution::FinishResolution(void) subscription->RemoveInstanceResolution(*this); // NOTE: The `ServiceSubscription` object may be freed in `OnServiceResolved`. - subscription->mMDnsSd->OnServiceResolved(serviceName, instanceInfo); + subscription->mPublisher.OnServiceResolved(serviceName, instanceInfo); } void PublisherMDnsSd::HostSubscription::Resolve(void) @@ -1096,7 +1137,7 @@ void PublisherMDnsSd::HostSubscription::Resolve(void) assert(mServiceRef == nullptr); - mMDnsSd->mHostResolutionBeginTime[mHostName] = Clock::now(); + mPublisher.mHostResolutionBeginTime[mHostName] = Clock::now(); otbrLogInfo("DNSServiceGetAddrInfo %s inf %d", fullHostName.c_str(), kDNSServiceInterfaceIndexAny); @@ -1127,7 +1168,6 @@ void PublisherMDnsSd::HostSubscription::HandleResolveResult(DNSServiceRef uint32_t aTtl) { OTBR_UNUSED_VARIABLE(aServiceRef); - OTBR_UNUSED_VARIABLE(aInterfaceIndex); Ip6Address address; @@ -1144,17 +1184,18 @@ void PublisherMDnsSd::HostSubscription::HandleResolveResult(DNSServiceRef mHostInfo.mHostName = aHostName; mHostInfo.mAddresses.push_back(address); - mHostInfo.mTtl = aTtl; + mHostInfo.mNetifIndex = aInterfaceIndex; + mHostInfo.mTtl = aTtl; otbrLogInfo("DNSServiceGetAddrInfo reply: address=%s, ttl=%" PRIu32, address.ToString().c_str(), aTtl); // NOTE: This `HostSubscription` object may be freed in `OnHostResolved`. - mMDnsSd->OnHostResolved(mHostName, mHostInfo); + mPublisher.OnHostResolved(mHostName, mHostInfo); exit: if (aErrorCode != kDNSServiceErr_NoError) { - mMDnsSd->OnHostResolveFailed(aHostName, aErrorCode); + mPublisher.OnHostResolveFailed(aHostName, aErrorCode); } } diff --git a/src/mdns/mdns_mdnssd.hpp b/src/mdns/mdns_mdnssd.hpp index 76347df6..fa4bf4d1 100644 --- a/src/mdns/mdns_mdnssd.hpp +++ b/src/mdns/mdns_mdnssd.hpp @@ -76,7 +76,7 @@ class PublisherMDnsSd : public MainloopProcessor, public Publisher void UnsubscribeHost(const std::string &aHostName) override; otbrError Start(void) override; bool IsStarted(void) const override; - void Stop(void) override; + void Stop(void) override { Stop(kNormalStop); } // Implementation of MainloopProcessor. @@ -89,11 +89,11 @@ class PublisherMDnsSd : public MainloopProcessor, public Publisher const std::string &aType, const SubTypeList &aSubTypeList, uint16_t aPort, - const TxtList &aTxtList, + const TxtData &aTxtData, ResultCallback &&aCallback) override; - otbrError PublishHostImpl(const std::string &aName, - const std::vector &aAddress, - ResultCallback &&aCallback) override; + otbrError PublishHostImpl(const std::string &aName, + const AddressList &aAddress, + ResultCallback &&aCallback) override; void OnServiceResolveFailedImpl(const std::string &aType, const std::string &aInstanceName, int32_t aErrorCode) override; @@ -103,71 +103,69 @@ class PublisherMDnsSd : public MainloopProcessor, public Publisher private: static constexpr uint32_t kDefaultTtl = 10; + enum StopMode : uint8_t + { + kNormalStop, + kStopOnServiceNotRunningError, + }; + class DnssdServiceRegistration : public ServiceRegistration { public: - DnssdServiceRegistration(const std::string &aHostName, - const std::string &aName, - const std::string &aType, - const SubTypeList &aSubTypeList, - uint16_t aPort, - const TxtList &aTxtList, - ResultCallback &&aCallback, - DNSServiceRef aServiceRef, - PublisherMDnsSd *aPublisher) - : ServiceRegistration(aHostName, - aName, - aType, - aSubTypeList, - aPort, - aTxtList, - std::move(aCallback), - aPublisher) - , mServiceRef(aServiceRef) - { - } + using ServiceRegistration::ServiceRegistration; // Inherit base constructor - ~DnssdServiceRegistration(void) override; - const DNSServiceRef &GetServiceRef() const { return mServiceRef; } + ~DnssdServiceRegistration(void) override { Unregister(); } + + void Update(MainloopContext &aMainloop) const; + void Process(const MainloopContext &aMainloop, std::vector &aReadyServices) const; + otbrError Register(void); private: - DNSServiceRef mServiceRef; + void Unregister(void); + PublisherMDnsSd &GetPublisher(void) { return *static_cast(mPublisher); } + void HandleRegisterResult(DNSServiceFlags aFlags, DNSServiceErrorType aError); + static void HandleRegisterResult(DNSServiceRef aServiceRef, + DNSServiceFlags aFlags, + DNSServiceErrorType aError, + const char *aName, + const char *aType, + const char *aDomain, + void *aContext); + + DNSServiceRef mServiceRef = nullptr; }; class DnssdHostRegistration : public HostRegistration { public: - DnssdHostRegistration(const std::string &aName, - const std::vector &aAddresses, - ResultCallback &&aCallback, - DNSServiceRef aServiceRef, - Publisher *aPublisher) - : HostRegistration(aName, aAddresses, std::move(aCallback), aPublisher) - , mServiceRef(aServiceRef) - , mRecordRefMap() - , mCallbackCount(aAddresses.size()) - { - } + using HostRegistration::HostRegistration; // Inherit base class constructor - ~DnssdHostRegistration(void) override; - const DNSServiceRef &GetServiceRef() const { return mServiceRef; } - const std::map &GetRecordRefMap() const { return mRecordRefMap; } - std::map &GetRecordRefMap() { return mRecordRefMap; } + ~DnssdHostRegistration(void) override { Unregister(); } - private: - DNSServiceRef mServiceRef; + otbrError Register(void); - public: - std::map mRecordRefMap; - uint32_t mCallbackCount; + private: + void Unregister(void); + PublisherMDnsSd &GetPublisher(void) { return *static_cast(mPublisher); } + void HandleRegisterResult(DNSRecordRef aRecordRef, DNSServiceErrorType aError); + static void HandleRegisterResult(DNSServiceRef aServiceRef, + DNSRecordRef aRecordRef, + DNSServiceFlags aFlags, + DNSServiceErrorType aErrorCode, + void *aContext); + + std::vector mAddrRecordRefs; + std::vector mAddrRegistered; }; struct ServiceRef : private ::NonCopyable { - DNSServiceRef mServiceRef; + DNSServiceRef mServiceRef; + PublisherMDnsSd &mPublisher; - explicit ServiceRef(void) + explicit ServiceRef(PublisherMDnsSd &aPublisher) : mServiceRef(nullptr) + , mPublisher(aPublisher) { } @@ -188,10 +186,10 @@ class PublisherMDnsSd : public MainloopProcessor, public Publisher std::string aType, std::string aDomain, uint32_t aNetifIndex) - : ServiceRef() + : ServiceRef(aSubscription.mPublisher) , mSubscription(&aSubscription) , mInstanceName(std::move(aInstanceName)) - , mTypeEndWithDot(std::move(aType)) + , mType(std::move(aType)) , mDomain(std::move(aDomain)) , mNetifIndex(aNetifIndex) { @@ -238,7 +236,7 @@ class PublisherMDnsSd : public MainloopProcessor, public Publisher ServiceSubscription *mSubscription; std::string mInstanceName; - std::string mTypeEndWithDot; + std::string mType; std::string mDomain; uint32_t mNetifIndex; DiscoveredInstanceInfo mInstanceInfo; @@ -246,9 +244,8 @@ class PublisherMDnsSd : public MainloopProcessor, public Publisher struct ServiceSubscription : public ServiceRef { - explicit ServiceSubscription(PublisherMDnsSd &aMDnsSd, std::string aType, std::string aInstanceName) - : ServiceRef() - , mMDnsSd(&aMDnsSd) + explicit ServiceSubscription(PublisherMDnsSd &aPublisher, std::string aType, std::string aInstanceName) + : ServiceRef(aPublisher) , mType(std::move(aType)) , mInstanceName(std::move(aInstanceName)) { @@ -279,18 +276,16 @@ class PublisherMDnsSd : public MainloopProcessor, public Publisher const char *aType, const char *aDomain); - PublisherMDnsSd *mMDnsSd; - std::string mType; - std::string mInstanceName; + std::string mType; + std::string mInstanceName; std::vector> mResolvingInstances; }; struct HostSubscription : public ServiceRef { - explicit HostSubscription(PublisherMDnsSd &aMDnsSd, std::string aHostName) - : ServiceRef() - , mMDnsSd(&aMDnsSd) + explicit HostSubscription(PublisherMDnsSd &aPublisher, std::string aHostName) + : ServiceRef(aPublisher) , mHostName(std::move(aHostName)) { } @@ -312,7 +307,6 @@ class PublisherMDnsSd : public MainloopProcessor, public Publisher const struct sockaddr *aAddress, uint32_t aTtl); - PublisherMDnsSd *mMDnsSd; std::string mHostName; DiscoveredHostInfo mHostInfo; }; @@ -320,33 +314,12 @@ class PublisherMDnsSd : public MainloopProcessor, public Publisher using ServiceSubscriptionList = std::vector>; using HostSubscriptionList = std::vector>; - static void HandleServiceRegisterResult(DNSServiceRef aService, - const DNSServiceFlags aFlags, - DNSServiceErrorType aError, - const char *aName, - const char *aType, - const char *aDomain, - void *aContext); - void HandleServiceRegisterResult(DNSServiceRef aService, - const DNSServiceFlags aFlags, - DNSServiceErrorType aError, - const char *aName, - const char *aType, - const char *aDomain); - static void HandleRegisterHostResult(DNSServiceRef aHostsConnection, - DNSRecordRef aHostRecord, - DNSServiceFlags aFlags, - DNSServiceErrorType aErrorCode, - void *aContext); - void HandleRegisterHostResult(DNSServiceRef aHostsConnection, - DNSRecordRef aHostRecord, - DNSServiceFlags aFlags, - DNSServiceErrorType aErrorCode); - static std::string MakeRegType(const std::string &aType, SubTypeList aSubTypeList); - ServiceRegistration *FindServiceRegistration(const DNSServiceRef &aServiceRef); - HostRegistration *FindHostRegistration(const DNSServiceRef &aServiceRef, const DNSRecordRef &aRecordRef); + void Stop(StopMode aStopMode); + DNSServiceErrorType CreateSharedHostsRef(void); + void DeallocateHostsRef(void); + void HandleServiceRefDeallocating(const DNSServiceRef &aServiceRef); DNSServiceRef mHostsRef; State mState; @@ -354,6 +327,8 @@ class PublisherMDnsSd : public MainloopProcessor, public Publisher ServiceSubscriptionList mSubscribedServices; HostSubscriptionList mSubscribedHosts; + + std::vector mServiceRefsToProcess; }; /** diff --git a/src/ncp/CMakeLists.txt b/src/ncp/CMakeLists.txt index c2eac7a6..1540225b 100644 --- a/src/ncp/CMakeLists.txt +++ b/src/ncp/CMakeLists.txt @@ -34,10 +34,5 @@ add_library(otbr-ncp target_link_libraries(otbr-ncp PRIVATE otbr-common $<$:otbr-proto> + $<$:otbr-proto> ) - -if(OTBR_FEATURE_FLAGS) - target_include_directories(otbr-ncp PRIVATE - ${PROJECT_SOURCE_DIR}/build/src - ) -endif() diff --git a/src/ncp/ncp_openthread.cpp b/src/ncp/ncp_openthread.cpp index ef1627e6..efd3e7f0 100644 --- a/src/ncp/ncp_openthread.cpp +++ b/src/ncp/ncp_openthread.cpp @@ -60,9 +60,10 @@ namespace otbr { namespace Ncp { -static const uint16_t kThreadVersion11 = 2; ///< Thread Version 1.1 -static const uint16_t kThreadVersion12 = 3; ///< Thread Version 1.2 -static const uint16_t kThreadVersion13 = 4; ///< Thread Version 1.3 +static const uint16_t kThreadVersion11 = 2; ///< Thread Version 1.1 +static const uint16_t kThreadVersion12 = 3; ///< Thread Version 1.2 +static const uint16_t kThreadVersion13 = 4; ///< Thread Version 1.3 +static const uint16_t kThreadVersion131 = 5; ///< Thread Version 1.3.1 ControllerOpenThread::ControllerOpenThread(const char *aInterfaceName, const std::vector &aRadioUrls, @@ -384,6 +385,9 @@ const char *ControllerOpenThread::GetThreadVersion(void) case kThreadVersion13: version = "1.3.0"; break; + case kThreadVersion131: + version = "1.3.1"; + break; default: otbrLogEmerg("Unexpected thread version %hu", otThreadGetVersion()); exit(-1); diff --git a/src/ncp/ncp_openthread.hpp b/src/ncp/ncp_openthread.hpp index 196a628d..51ba31f4 100644 --- a/src/ncp/ncp_openthread.hpp +++ b/src/ncp/ncp_openthread.hpp @@ -97,16 +97,12 @@ class ControllerOpenThread : public MainloopProcessor void Deinit(void); /** - * This method get mInstance pointer. - * - * @retval The pointer of mInstance. + * Returns an OpenThread instance. * + * @retval Non-null OpenThread instance if `ControllerOpenThread::Init()` has been called. + * Otherwise, it's guaranteed to be `null` */ - otInstance *GetInstance(void) - { - assert(mInstance != nullptr); - return mInstance; - } + otInstance *GetInstance(void) { return mInstance; } /** * This method gets the thread functionality helper. diff --git a/src/openwrt/otbr-agent.init.in b/src/openwrt/otbr-agent.init.in index 2c1de2f2..46505ff4 100755 --- a/src/openwrt/otbr-agent.init.in +++ b/src/openwrt/otbr-agent.init.in @@ -34,8 +34,11 @@ USE_PROCD=1 start_service() { local uci_thread_if_name=$(uci -q get otbr-agent.service.thread_if_name) + local uci_infra_if_name=$(uci -q get otbr-agent.service.infra_if_name) + local uci_uart_device=$(uci -q get otbr-agent.service.uart_device) + local uci_uart_baudrate=$(uci -q get otbr-agent.service.uart_baudrate) procd_open_instance - procd_set_param command @CMAKE_INSTALL_FULL_SBINDIR@/otbr-agent -I $uci_thread_if_name spinel+hdlc+uart:///dev/ttyACM0 + procd_set_param command @CMAKE_INSTALL_FULL_SBINDIR@/otbr-agent -I $uci_thread_if_name -B $uci_infra_if_name spinel+hdlc+uart://$uci_uart_device?uart-baudrate=$uci_uart_baudrate trel://$uci_infra_if_name procd_close_instance } diff --git a/src/openwrt/otbr-agent.uci-config.in b/src/openwrt/otbr-agent.uci-config.in index 7d8473c5..855d7088 100644 --- a/src/openwrt/otbr-agent.uci-config.in +++ b/src/openwrt/otbr-agent.uci-config.in @@ -1,2 +1,5 @@ config otbr-agent 'service' option thread_if_name "wpan0" + option infra_if_name "eth0" + option uart_device "/dev/ttyACM0" + option uart_baudrate 115200 diff --git a/src/proto/CMakeLists.txt b/src/proto/CMakeLists.txt index 0fd2103f..e982d52a 100644 --- a/src/proto/CMakeLists.txt +++ b/src/proto/CMakeLists.txt @@ -58,6 +58,11 @@ add_library(otbr-proto STATIC ) find_package(Protobuf REQUIRED) -target_link_libraries(otbr-proto + +target_link_libraries(otbr-proto PUBLIC protobuf::libprotobuf-lite ) + +target_include_directories(otbr-proto PUBLIC + ${PROJECT_SOURCE_DIR}/build/src +) diff --git a/src/proto/thread_telemetry.proto b/src/proto/thread_telemetry.proto index c8207a3a..8ffcadf9 100644 --- a/src/proto/thread_telemetry.proto +++ b/src/proto/thread_telemetry.proto @@ -1,3 +1,30 @@ +/* + * Copyright (c) 2023, 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. + */ syntax = "proto2"; option optimize_for = LITE_RUNTIME; @@ -14,20 +41,19 @@ package threadnetwork; // Usage: // Delete field: do not directly delete field. Deprecate it instead. message TelemetryData { - enum NodeType { - NODE_TYPE_UNSPECIFIED = 0; - NODE_TYPE_ROUTER = 1; - NODE_TYPE_END = 2; - NODE_TYPE_SLEEPY_END = 3; - NODE_TYPE_MINIMAL_END = 4; + message Duration { + // Signed seconds of the span of time. Must be from -315,576,000,000 + // to +315,576,000,000 inclusive. Note: these bounds are computed from: + // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + optional int64 seconds = 1; - NODE_TYPE_OFFLINE = 5; - NODE_TYPE_DISABLED = 6; - NODE_TYPE_DETACHED = 7; - - NODE_TYPE_NL_LURKER = 0x10; - NODE_TYPE_COMMISSIONER = 0x20; - NODE_TYPE_LEADER = 0x40; + // Signed fractions of a second at nanosecond resolution of the span + // of time. Durations less than one second are represented with a 0 + // `seconds` field and a positive or negative `nanos` field. For durations + // of one second or more, a non-zero value for the `nanos` field must be + // of the same sign as the `seconds` field. Must be from -999,999,999 + // to +999,999,999 inclusive. + optional int32 nanos = 2; } message WpanStats { @@ -70,7 +96,394 @@ message TelemetryData { optional float mac_cca_fail_rate = 37; } + message WpanTopoFull { + optional uint32 rloc16 = 1; + optional uint32 router_id = 2; + optional uint32 leader_router_id = 3; + // Deprecate bytes ext_address. + reserved 4; + optional bytes leader_address = 5; + optional uint32 leader_weight = 6; + optional uint32 leader_local_weight = 7; + optional bytes network_data = 8; + optional uint32 network_data_version = 9; + optional bytes stable_network_data = 10; + optional uint32 stable_network_data_version = 11; + optional uint32 preferred_router_id = 12; + optional uint32 partition_id = 13; + optional uint32 child_table_size = 14; + optional uint32 neighbor_table_size = 15; + optional int32 instant_rssi = 16; + optional uint64 extended_pan_id = 17; + } + + message TopoEntry { + // deprecate bytes ext_address. + reserved 1; + optional uint32 rloc16 = 2; + // link quality with data range: 0~3. + optional uint32 link_quality_in = 3; + // the most recent RSSI measurement (8 bit). + optional int32 average_rssi = 4; + optional Duration age = 5; + optional bool rx_on_when_idle = 6; + optional bool full_function = 7; + optional bool secure_data_request = 8; + optional bool full_network_data = 9; + optional int32 last_rssi = 10; + optional uint32 link_frame_counter = 11; + optional uint32 mle_frame_counter = 12; + optional bool is_child = 13; + optional Duration timeout = 14; + optional uint32 network_data_version = 15; + optional float mac_frame_error_rate = 16; + optional float ip_message_error_rate = 17; + optional int32 version = 18; + } + + enum NodeType { + NODE_TYPE_UNSPECIFIED = 0; + NODE_TYPE_ROUTER = 1; + NODE_TYPE_END = 2; + NODE_TYPE_SLEEPY_END = 3; + NODE_TYPE_MINIMAL_END = 4; + + NODE_TYPE_OFFLINE = 5; + NODE_TYPE_DISABLED = 6; + NODE_TYPE_DETACHED = 7; + + NODE_TYPE_NL_LURKER = 0x10; + NODE_TYPE_COMMISSIONER = 0x20; + NODE_TYPE_LEADER = 0x40; + } + + message PacketsAndBytes { + optional int64 packet_count = 1; + optional int64 byte_count = 2; + } + + message Nat64TrafficCounters { + optional int64 ipv4_to_ipv6_packets = 1; + optional int64 ipv4_to_ipv6_bytes = 2; + optional int64 ipv6_to_ipv4_packets = 3; + optional int64 ipv6_to_ipv4_bytes = 4; + } + + message Nat64ProtocolCounters { + optional Nat64TrafficCounters tcp = 1; + optional Nat64TrafficCounters udp = 2; + optional Nat64TrafficCounters icmp = 3; + } + + message Nat64PacketCounters { + optional int64 ipv4_to_ipv6_packets = 1; + optional int64 ipv6_to_ipv4_packets = 2; + } + + message Nat64ErrorCounters { + optional Nat64PacketCounters unknown = 1; + optional Nat64PacketCounters illegal_packet = 2; + optional Nat64PacketCounters unsupported_protocol = 3; + optional Nat64PacketCounters no_mapping = 4; + } + + message BorderRoutingCounters { + reserved 1 to 8; + // The number of Router Advertisement packets received by otbr-agent on the + // infra link + optional int64 ra_rx = 9; + + // The number of Router Advertisement packets successfully transmitted by + // otbr-agent on the infra link. + optional int64 ra_tx_success = 10; + + // The number of Router Advertisement packets failed to transmit by + // otbr-agent on the infra link. + optional int64 ra_tx_failure = 11; + + // The number of Router Solicitation packets received by otbr-agent on the + // infra link + optional int64 rs_rx = 12; + + // The number of Router Solicitation packets successfully transmitted by + // otbr-agent on the infra link. + optional int64 rs_tx_success = 13; + + // The number of Router Solicitation packets failed to transmit by + // otbr-agent on the infra link. + optional int64 rs_tx_failure = 14; + + // The counters for inbound unicast packets + optional PacketsAndBytes inbound_unicast = 15; + + // The counters for inbound multicast packets + optional PacketsAndBytes inbound_multicast = 16; + + // The counters for outbound unicast packets + optional PacketsAndBytes outbound_unicast = 17; + + // The counters for outbound multicast packets + optional PacketsAndBytes outbound_multicast = 18; + + // The inbound and outbound NAT64 traffic through the border router + optional Nat64ProtocolCounters nat64_protocol_counters = 19; + + // Error counters for NAT64 translator on the border router + optional Nat64ErrorCounters nat64_error_counters = 20; + } + + message SrpServerRegistrationInfo { + // The number of active hosts/services registered on the SRP server. + optional uint32 fresh_count = 1; + + // The number of hosts/services in 'Deleted' state on the SRP server. + optional uint32 deleted_count = 2; + + // The sum of lease time in milliseconds of all active hosts/services on the + // SRP server. + optional uint64 lease_time_total_ms = 3; + + // The sum of key lease time in milliseconds of all active hosts/services on + // the SRP server. + optional uint64 key_lease_time_total_ms = 4; + + // The sum of remaining lease time in milliseconds of all active + // hosts/services on the SRP server. + optional uint64 remaining_lease_time_total_ms = 5; + + // The sum of remaining key lease time in milliseconds of all active + // hosts/services on the SRP server. + optional uint64 remaining_key_lease_time_total_ms = 6; + } + + message SrpServerResponseCounters { + // The number of successful responses + optional uint32 success_count = 1; + + // The number of server failure responses + optional uint32 server_failure_count = 2; + + // The number of format error responses + optional uint32 format_error_count = 3; + + // The number of 'name exists' responses + optional uint32 name_exists_count = 4; + + // The number of refused responses + optional uint32 refused_count = 5; + + // The number of other responses + optional uint32 other_count = 6; + } + + enum SrpServerState { + SRP_SERVER_STATE_UNSPECIFIED = 0; + SRP_SERVER_STATE_DISABLED = 1; + SRP_SERVER_STATE_RUNNING = 2; + SRP_SERVER_STATE_STOPPED = 3; + } + + // The address mode used by the SRP server + enum SrpServerAddressMode { + SRP_SERVER_ADDRESS_MODE_UNSPECIFIED = 0; + SRP_SERVER_ADDRESS_MODE_UNICAST = 1; + SRP_SERVER_ADDRESS_MODE_STATE_ANYCAST = 2; + } + + message SrpServerInfo { + // The state of the SRP server + optional SrpServerState state = 1; + + // Listening port number + optional uint32 port = 2; + // The address mode {unicast, anycast} of the SRP server + optional SrpServerAddressMode address_mode = 3; + + // The registration information of hosts on the SRP server + optional SrpServerRegistrationInfo hosts = 4; + + // The registration information of services on the SRP server + optional SrpServerRegistrationInfo services = 5; + + // The counters of response codes sent by the SRP server + optional SrpServerResponseCounters response_counters = 6; + } + + message DnsServerResponseCounters { + // The number of successful responses + optional uint32 success_count = 1; + + // The number of server failure responses + optional uint32 server_failure_count = 2; + + // The number of format error responses + optional uint32 format_error_count = 3; + + // The number of name error responses + optional uint32 name_error_count = 4; + + // The number of 'not implemented' responses + optional uint32 not_implemented_count = 5; + + // The number of other responses + optional uint32 other_count = 6; + } + + message DnsServerInfo { + // The counters of response codes sent by the DNS server + optional DnsServerResponseCounters response_counters = 1; + + // The number of DNS queries resolved at the local SRP server + optional uint32 resolved_by_local_srp_count = 2; + } + + message MdnsResponseCounters { + // The number of successful responses + optional uint32 success_count = 1; + + // The number of 'not found' responses + optional uint32 not_found_count = 2; + + // The number of 'invalid arg' responses + optional uint32 invalid_args_count = 3; + + // The number of 'duplicated' responses + optional uint32 duplicated_count = 4; + + // The number of 'not implemented' responses + optional uint32 not_implemented_count = 5; + + // The number of unknown error responses + optional uint32 unknown_error_count = 6; + + // The number of aborted responses + optional uint32 aborted_count = 7; + + // The number of invalid state responses + optional uint32 invalid_state_count = 8; + } + + message MdnsInfo { + // The response counters of host registrations + optional MdnsResponseCounters host_registration_responses = 1; + + // The response counters of service registrations + optional MdnsResponseCounters service_registration_responses = 2; + + // The response counters of host resolutions + optional MdnsResponseCounters host_resolution_responses = 3; + + // The response counters of service resolutions + optional MdnsResponseCounters service_resolution_responses = 4; + + // The EMA (Exponential Moving Average) latencies of mDNS operations + + // The EMA latency of host registrations in milliseconds + optional uint32 host_registration_ema_latency_ms = 5; + + // The EMA latency of service registrations in milliseconds + optional uint32 service_registration_ema_latency_ms = 6; + + // The EMA latency of host resolutions in milliseconds + optional uint32 host_resolution_ema_latency_ms = 7; + + // The EMA latency of service resolutions in milliseconds + optional uint32 service_resolution_ema_latency_ms = 8; + } + + enum Nat64State { + NAT64_STATE_UNSPECIFIED = 0; + NAT64_STATE_DISABLED = 1; + NAT64_STATE_NOT_RUNNING = 2; + NAT64_STATE_IDLE = 3; + NAT64_STATE_ACTIVE = 4; + } + + message BorderRoutingNat64State { + optional Nat64State prefix_manager_state = 1; + optional Nat64State translator_state = 2; + } + + message Nat64Mapping { + optional uint64 mapping_id = 1; + optional bytes hashed_ipv6_address = 2; + optional Nat64ProtocolCounters counters = 3; + } + + message WpanBorderRouter { + // Border routing counters + optional BorderRoutingCounters border_routing_counters = 1; + + // Information about the SRP server + optional SrpServerInfo srp_server = 2; + + // Information about the DNS server + optional DnsServerInfo dns_server = 3; + + // Information about the mDNS publisher + optional MdnsInfo mdns = 4; + + // TODO(b/285457467): remove this reserved proto field. + reserved 5; + + // Information about the state of components of NAT64 + optional BorderRoutingNat64State nat64_state = 6; + + // Information about the mappings of NAT64 translator + repeated Nat64Mapping nat64_mappings = 7; + } + + message RcpStabilityStatistics { + optional uint32 rcp_timeout_count = 1; + optional uint32 rcp_reset_count = 2; + optional uint32 rcp_restoration_count = 3; + optional uint32 spinel_parse_error_count = 4; + optional int32 rcp_firmware_update_count = 5; + optional uint32 thread_stack_uptime = 6; + } + + message RcpInterfaceStatistics { + optional uint32 rcp_interface_type = 1; + optional uint64 transferred_frames_count = 2; + optional uint64 transferred_valid_frames_count = 3; + optional uint64 transferred_garbage_frames_count = 4; + optional uint64 rx_frames_count = 5; + optional uint64 rx_bytes_count = 6; + optional uint64 tx_frames_count = 7; + optional uint64 tx_bytes_count = 8; + } + + message WpanRcp { + optional RcpStabilityStatistics rcp_stability_statistics = 1; + optional RcpInterfaceStatistics rcp_interface_statistics = 2; + } + + message CoexMetrics { + // Use uint32 instead of int64 to save space for payload, and align with the + // raw data size. + optional uint32 count_tx_request = 1; + optional uint32 count_tx_grant_immediate = 2; + optional uint32 count_tx_grant_wait = 3; + optional uint32 count_tx_grant_wait_activated = 4; + optional uint32 count_tx_grant_wait_timeout = 5; + optional uint32 count_tx_grant_deactivated_during_request = 6; + optional uint32 tx_average_request_to_grant_time_us = 7; + optional uint32 count_rx_request = 8; + optional uint32 count_rx_grant_immediate = 9; + optional uint32 count_rx_grant_wait = 10; + optional uint32 count_rx_grant_wait_activated = 11; + optional uint32 count_rx_grant_wait_timeout = 12; + optional uint32 count_rx_grant_deactivated_during_request = 13; + optional uint32 count_rx_grant_none = 14; + optional uint32 rx_average_request_to_grant_time_us = 15; + } + optional WpanStats wpan_stats = 1; - // TODO: add fields for topo, border_router, rcp, and coex. - reserved 2, 3, 4, 5, 6; + optional WpanTopoFull wpan_topo_full = 2; + repeated TopoEntry topo_entries = 3; + optional WpanBorderRouter wpan_border_router = 4; + optional WpanRcp wpan_rcp = 5; + // Deprecate CoexMetrics with int64 as its fields types to save storage. + reserved 6; + optional CoexMetrics coex_metrics = 7; } diff --git a/src/rest/openapi.yaml b/src/rest/openapi.yaml index 43747e2e..2ba2a4dd 100644 --- a/src/rest/openapi.yaml +++ b/src/rest/openapi.yaml @@ -43,6 +43,15 @@ paths: application/json: schema: type: object + delete: + tags: + - node + summary: Erase all persistent information, essentially factory reset the Border Router. + responses: + "200": + description: Successful operation + "409": + description: Thread interface is in wrong state. /node/ba-id: get: tags: diff --git a/src/rest/resource.cpp b/src/rest/resource.cpp index 1139a2d7..a60e9d94 100644 --- a/src/rest/resource.cpp +++ b/src/rest/resource.cpp @@ -257,16 +257,46 @@ void Resource::GetNodeInfo(Response &aResponse) const } } -void Resource::NodeInfo(const Request &aRequest, Response &aResponse) const +void Resource::DeleteNodeInfo(Response &aResponse) const { + otbrError error = OTBR_ERROR_NONE; std::string errorCode; - if (aRequest.GetMethod() == HttpMethod::kGet) + + VerifyOrExit(mNcp->GetThreadHelper()->Detach() == OT_ERROR_NONE, error = OTBR_ERROR_INVALID_STATE); + VerifyOrExit(otInstanceErasePersistentInfo(mInstance) == OT_ERROR_NONE, error = OTBR_ERROR_REST); + mNcp->Reset(); + +exit: + if (error == OTBR_ERROR_NONE) { - GetNodeInfo(aResponse); + errorCode = GetHttpStatus(HttpStatusCode::kStatusOk); + aResponse.SetResponsCode(errorCode); } - else + else if (error == OTBR_ERROR_INVALID_STATE) + { + ErrorHandler(aResponse, HttpStatusCode::kStatusConflict); + } + else if (error != OTBR_ERROR_NONE) { + ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError); + } +} + +void Resource::NodeInfo(const Request &aRequest, Response &aResponse) const +{ + std::string errorCode; + + switch (aRequest.GetMethod()) + { + case HttpMethod::kGet: + GetNodeInfo(aResponse); + break; + case HttpMethod::kDelete: + DeleteNodeInfo(aResponse); + break; + default: ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed); + break; } } diff --git a/src/rest/resource.hpp b/src/rest/resource.hpp index 0c089c72..d79085db 100644 --- a/src/rest/resource.hpp +++ b/src/rest/resource.hpp @@ -137,6 +137,7 @@ class Resource void HandleDiagnosticCallback(const Request &aRequest, Response &aResponse); void GetNodeInfo(Response &aResponse) const; + void DeleteNodeInfo(Response &aResponse) const; void GetDataBaId(Response &aResponse) const; void GetDataExtendedAddr(Response &aResponse) const; void GetDataState(Response &aResponse) const; diff --git a/src/rest/response.cpp b/src/rest/response.cpp index 93cbe0b6..3460b90e 100644 --- a/src/rest/response.cpp +++ b/src/rest/response.cpp @@ -34,7 +34,7 @@ #define OT_REST_RESPONSE_ACCESS_CONTROL_ALLOW_HEADERS \ "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, " \ "Access-Control-Request-Headers" -#define OT_REST_RESPONSE_ACCESS_CONTROL_ALLOW_METHOD "GET, OPTIONS, PUT" +#define OT_REST_RESPONSE_ACCESS_CONTROL_ALLOW_METHOD "DELETE, GET, OPTIONS, PUT" #define OT_REST_RESPONSE_CONNECTION "close" namespace otbr { diff --git a/src/sdp_proxy/advertising_proxy.cpp b/src/sdp_proxy/advertising_proxy.cpp index d254ed0d..7eac4d0c 100644 --- a/src/sdp_proxy/advertising_proxy.cpp +++ b/src/sdp_proxy/advertising_proxy.cpp @@ -247,18 +247,16 @@ otbrError AdvertisingProxy::PublishHostAndItsServices(const otSrpServerHost *aHo aUpdate->mCallbackCount++; aUpdate->mHostName = hostName; service = nullptr; - while ((service = otSrpServerHostFindNextService(aHost, service, OT_SRP_SERVER_FLAGS_BASE_TYPE_SERVICE_ONLY, - /* aServiceName */ nullptr, /* aInstanceName */ nullptr))) + while ((service = otSrpServerHostGetNextService(aHost, service)) != nullptr) { aUpdate->mCallbackCount++; } } service = nullptr; - while ((service = otSrpServerHostFindNextService(aHost, service, OT_SRP_SERVER_FLAGS_BASE_TYPE_SERVICE_ONLY, - /* aServiceName */ nullptr, /* aInstanceName */ nullptr))) + while ((service = otSrpServerHostGetNextService(aHost, service)) != nullptr) { - std::string fullServiceName = otSrpServerServiceGetFullName(service); + std::string fullServiceName = otSrpServerServiceGetInstanceName(service); std::string serviceName; std::string serviceType; std::string serviceDomain; @@ -267,12 +265,12 @@ otbrError AdvertisingProxy::PublishHostAndItsServices(const otSrpServerHost *aHo if (!hostDeleted && !otSrpServerServiceIsDeleted(service)) { - Mdns::Publisher::TxtList txtList = MakeTxtList(service); + Mdns::Publisher::TxtData txtData = MakeTxtData(service); Mdns::Publisher::SubTypeList subTypeList = MakeSubTypeList(service); otbrLogDebug("Publish SRP service '%s'", fullServiceName.c_str()); mPublisher.PublishService( - hostName, serviceName, serviceType, subTypeList, otSrpServerServiceGetPort(service), txtList, + hostName, serviceName, serviceType, subTypeList, otSrpServerServiceGetPort(service), txtData, [this, hasUpdate, updateId, fullServiceName](otbrError aError) { otbrLogResult(aError, "Handle publish SRP service '%s'", fullServiceName.c_str()); if (hasUpdate) @@ -340,49 +338,31 @@ otbrError AdvertisingProxy::PublishHostAndItsServices(const otSrpServerHost *aHo return error; } -Mdns::Publisher::TxtList AdvertisingProxy::MakeTxtList(const otSrpServerService *aSrpService) +Mdns::Publisher::TxtData AdvertisingProxy::MakeTxtData(const otSrpServerService *aSrpService) { - const uint8_t *txtData; - uint16_t txtDataLength = 0; - otDnsTxtEntryIterator iterator; - otDnsTxtEntry txtEntry; - Mdns::Publisher::TxtList txtList; + const uint8_t *data; + uint16_t length = 0; - txtData = otSrpServerServiceGetTxtData(aSrpService, &txtDataLength); + data = otSrpServerServiceGetTxtData(aSrpService, &length); - otDnsInitTxtEntryIterator(&iterator, txtData, txtDataLength); - - while (otDnsGetNextTxtEntry(&iterator, &txtEntry) == OT_ERROR_NONE) - { - txtList.emplace_back(txtEntry.mKey, txtEntry.mValue, txtEntry.mValueLength); - } - - return txtList; + return Mdns::Publisher::TxtData(data, data + length); } Mdns::Publisher::SubTypeList AdvertisingProxy::MakeSubTypeList(const otSrpServerService *aSrpService) { - const otSrpServerHost *host = otSrpServerServiceGetHost(aSrpService); - const char *instanceName = otSrpServerServiceGetInstanceName(aSrpService); - const otSrpServerService *subService = nullptr; Mdns::Publisher::SubTypeList subTypeList; - while ((subService = otSrpServerHostFindNextService( - host, subService, (OT_SRP_SERVER_SERVICE_FLAG_SUB_TYPE | OT_SRP_SERVER_SERVICE_FLAG_ACTIVE), - /* aServiceName */ nullptr, instanceName)) != nullptr) + for (uint16_t index = 0;; index++) { - char subLabel[OT_DNS_MAX_LABEL_SIZE]; + const char *subTypeName = otSrpServerServiceGetSubTypeServiceNameAt(aSrpService, index); + char subLabel[OT_DNS_MAX_LABEL_SIZE]; - if (otSrpServerServiceGetServiceSubTypeLabel(subService, subLabel, sizeof(subLabel)) == OT_ERROR_NONE) - { - subTypeList.emplace_back(subLabel); - } - else - { - otbrLogWarning("Failed to retrieve subtype of SRP service: %s", otSrpServerServiceGetFullName(aSrpService)); - } + VerifyOrExit(subTypeName != nullptr); + SuccessOrExit(otSrpServerParseSubTypeServiceName(subTypeName, subLabel, sizeof(subLabel))); + subTypeList.emplace_back(subLabel); } +exit: return subTypeList; } diff --git a/src/sdp_proxy/advertising_proxy.hpp b/src/sdp_proxy/advertising_proxy.hpp index 1a845dc0..385dadd6 100644 --- a/src/sdp_proxy/advertising_proxy.hpp +++ b/src/sdp_proxy/advertising_proxy.hpp @@ -100,7 +100,7 @@ class AdvertisingProxy : private NonCopyable void *aContext); void AdvertisingHandler(otSrpServerServiceUpdateId aId, const otSrpServerHost *aHost, uint32_t aTimeout); - static Mdns::Publisher::TxtList MakeTxtList(const otSrpServerService *aSrpService); + static Mdns::Publisher::TxtData MakeTxtData(const otSrpServerService *aSrpService); static Mdns::Publisher::SubTypeList MakeSubTypeList(const otSrpServerService *aSrpService); void OnMdnsPublishResult(otSrpServerServiceUpdateId aUpdateId, otbrError aError); @@ -131,9 +131,6 @@ class AdvertisingProxy : private NonCopyable // A vector that tracks outstanding updates. std::vector mOutstandingUpdates; - - // Task runner for running tasks in the context of the main thread. - TaskRunner mTaskRunner; }; } // namespace otbr diff --git a/src/trel_dnssd/trel_dnssd.cpp b/src/trel_dnssd/trel_dnssd.cpp index 11794fcb..c285a834 100644 --- a/src/trel_dnssd/trel_dnssd.cpp +++ b/src/trel_dnssd/trel_dnssd.cpp @@ -249,7 +249,7 @@ void TrelDnssd::PublishTrelService(void) mRegisterInfo.mInstanceName = GetTrelInstanceName(); mPublisher.PublishService(/* aHostName */ "", mRegisterInfo.mInstanceName, kTrelServiceName, - Mdns::Publisher::SubTypeList{}, mRegisterInfo.mPort, mRegisterInfo.mTxtEntries, + Mdns::Publisher::SubTypeList{}, mRegisterInfo.mPort, mRegisterInfo.mTxtData, [](otbrError aError) { HandlePublishTrelServiceError(aError); }); } @@ -461,18 +461,11 @@ uint16_t TrelDnssd::CountDuplicatePeers(const TrelDnssd::Peer &aPeer) void TrelDnssd::RegisterInfo::Assign(uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength) { - otbrError error; - - OTBR_UNUSED_VARIABLE(error); - assert(!IsPublished()); assert(aPort > 0); mPort = aPort; - mTxtEntries.clear(); - - error = Mdns::Publisher::DecodeTxtData(mTxtEntries, aTxtData, aTxtLength); - assert(error == OTBR_ERROR_NONE); + mTxtData.assign(aTxtData, aTxtData + aTxtLength); } void TrelDnssd::RegisterInfo::Clear(void) @@ -480,7 +473,7 @@ void TrelDnssd::RegisterInfo::Clear(void) assert(!IsPublished()); mPort = 0; - mTxtEntries.clear(); + mTxtData.clear(); } const char TrelDnssd::Peer::kTxtRecordExtAddressKey[] = "xa"; @@ -495,7 +488,12 @@ void TrelDnssd::Peer::ReadExtAddrFromTxtData(void) for (const auto &txtEntry : txtEntries) { - if (StringUtils::EqualCaseInsensitive(txtEntry.mName, kTxtRecordExtAddressKey)) + if (txtEntry.mIsBooleanAttribute) + { + continue; + } + + if (StringUtils::EqualCaseInsensitive(txtEntry.mKey, kTxtRecordExtAddressKey)) { VerifyOrExit(txtEntry.mValue.size() == sizeof(mExtAddr)); diff --git a/src/trel_dnssd/trel_dnssd.hpp b/src/trel_dnssd/trel_dnssd.hpp index cd7daaa8..8f44104e 100644 --- a/src/trel_dnssd/trel_dnssd.hpp +++ b/src/trel_dnssd/trel_dnssd.hpp @@ -120,9 +120,9 @@ class TrelDnssd struct RegisterInfo { - uint16_t mPort = 0; - std::vector mTxtEntries; - std::string mInstanceName; + uint16_t mPort = 0; + Mdns::Publisher::TxtData mTxtData; + std::string mInstanceName; bool IsValid(void) const { return mPort > 0; } bool IsPublished(void) const { return !mInstanceName.empty(); } diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index 5a624844..4f9c4202 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -32,6 +32,7 @@ add_library(otbr-utils hex.cpp infra_link_selector.cpp pskc.cpp + sha256.cpp socket_utils.cpp steering_data.cpp string_utils.cpp @@ -39,7 +40,10 @@ add_library(otbr-utils thread_helper.cpp thread_helper.hpp ) -target_link_libraries(otbr-utils PRIVATE + +target_link_libraries(otbr-utils PUBLIC otbr-common + $<$:otbr-proto> + $<$:otbr-proto> mbedtls ) diff --git a/src/utils/pskc.cpp b/src/utils/pskc.cpp index bcd37a69..b15ca9e8 100644 --- a/src/utils/pskc.cpp +++ b/src/utils/pskc.cpp @@ -41,9 +41,16 @@ namespace Psk { void Pskc::SetSalt(const uint8_t *aExtPanId, const char *aNetworkName) { - const char *saltPrefix = "Thread"; - int cur = 0; - int ret = kPskcStatus_Ok; + const char *saltPrefix = "Thread"; + int cur = 0; + int ret = kPskcStatus_Ok; + int remainingSpace = 0; + int networkNameLen = 0; + + if (strlen(saltPrefix) + OT_EXTENDED_PAN_ID_LENGTH + strlen(aNetworkName) >= sizeof(mSalt)) + { + otbrLogWarning("Network name too long; will be truncated."); + } memset(mSalt, 0, sizeof(mSalt)); memcpy(mSalt, saltPrefix, strlen(saltPrefix)); @@ -53,8 +60,14 @@ void Pskc::SetSalt(const uint8_t *aExtPanId, const char *aNetworkName) cur += OT_EXTENDED_PAN_ID_LENGTH; VerifyOrExit(strlen(aNetworkName) > 0, ret = kPskcStatus_InvalidArgument); - memcpy(mSalt + cur, aNetworkName, strlen(aNetworkName)); - cur += strlen(aNetworkName); + + remainingSpace = sizeof(mSalt) - cur; + if (remainingSpace > 0) + { + networkNameLen = std::min(static_cast(strlen(aNetworkName)), remainingSpace); + memcpy(mSalt + cur, aNetworkName, networkNameLen); + cur += networkNameLen; + } mSaltLen = static_cast(cur); diff --git a/src/utils/sha256.cpp b/src/utils/sha256.cpp new file mode 100644 index 00000000..30be250e --- /dev/null +++ b/src/utils/sha256.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2023, 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 SHA-256. + */ + +#include "sha256.hpp" + +namespace otbr { + +Sha256::Sha256(void) +{ + otError error; + + mContext.mContext = &mContextStorage; + mContext.mContextSize = sizeof(mContextStorage); + + SuccessOrExit(error = otPlatCryptoSha256Init(&mContext)); + +exit: + if (error != OT_ERROR_NONE) + { + otbrLogErr("Error otPlatCryptoSha256Init: %s", otThreadErrorToString(error)); + } +} + +Sha256::~Sha256(void) +{ + otError error; + + SuccessOrExit(error = otPlatCryptoSha256Deinit(&mContext)); + +exit: + if (error != OT_ERROR_NONE) + { + otbrLogErr("Error otPlatCryptoSha256Deinit: %s", otThreadErrorToString(error)); + } +} + +void Sha256::Start(void) +{ + otError error; + + SuccessOrExit(error = otPlatCryptoSha256Start(&mContext)); + +exit: + if (error != OT_ERROR_NONE) + { + otbrLogErr("Error otPlatCryptoSha256Start: %s", otThreadErrorToString(error)); + } +} + +void Sha256::Update(const void *aBuf, uint16_t aBufLength) +{ + otError error; + + SuccessOrExit(error = otPlatCryptoSha256Update(&mContext, aBuf, aBufLength)); + +exit: + if (error != OT_ERROR_NONE) + { + otbrLogErr("Error otPlatCryptoSha256Update: %s", otThreadErrorToString(error)); + } +} + +void Sha256::Finish(Hash &aHash) +{ + otError error; + + SuccessOrExit(error = otPlatCryptoSha256Finish(&mContext, aHash.m8, Hash::kSize)); + +exit: + if (error != OT_ERROR_NONE) + { + otbrLogErr("Error otPlatCryptoSha256Finish: %s", otThreadErrorToString(error)); + } +} +} // namespace otbr diff --git a/src/utils/sha256.hpp b/src/utils/sha256.hpp new file mode 100644 index 00000000..df90a846 --- /dev/null +++ b/src/utils/sha256.hpp @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2023, 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 includes definitions for performing SHA-256 computations. + */ + +#ifndef SHA256_HPP_ +#define SHA256_HPP_ + +#include +#include +#include "common/code_utils.hpp" + +#include + +namespace otbr { +/** + * @addtogroup core-security + * + * @{ + * + */ + +/** + * This class implements SHA-256 computation. + * + */ +class Sha256 +{ +public: + /** + * This type represents a SHA-256 hash. + * + */ + class Hash : public otCryptoSha256Hash + { + public: + static const uint8_t kSize = OT_CRYPTO_SHA256_HASH_SIZE; ///< SHA-256 hash size (bytes) + + /** + * This method returns a pointer to a byte array containing the hash value. + * + * @returns A pointer to a byte array containing the hash. + * + */ + const uint8_t *GetBytes(void) const { return m8; } + }; + + /** + * Constructor for `Sha256` object. + * + */ + Sha256(void); + + /** + * Destructor for `Sha256` object. + * + */ + ~Sha256(void); + + /** + * This method starts the SHA-256 computation. + * + */ + void Start(void); + + /** + * This method inputs bytes into the SHA-256 computation. + * + * @param[in] aBuf A pointer to the input buffer. + * @param[in] aBufLength The length of @p aBuf in bytes. + * + */ + void Update(const void *aBuf, uint16_t aBufLength); + + /** + * This method finalizes the hash computation. + * + * @param[out] aHash A reference to a `Hash` to output the calculated hash. + * + */ + void Finish(Hash &aHash); + +private: + otCryptoContext mContext; + const static uint16_t kSha256ContextSize = sizeof(mbedtls_sha256_context); + OT_DEFINE_ALIGNED_VAR(mContextStorage, kSha256ContextSize, uint64_t); +}; +} // namespace otbr + +#endif // SHA256_HPP_ diff --git a/src/utils/thread_helper.cpp b/src/utils/thread_helper.cpp index 24cc2aed..9cd2dd8e 100644 --- a/src/utils/thread_helper.cpp +++ b/src/utils/thread_helper.cpp @@ -40,8 +40,19 @@ #include #include #include +#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY +#include +#endif #include #include +#if OTBR_ENABLE_NAT64 +#include +#include +#include "utils/sha256.hpp" +#endif +#if OTBR_ENABLE_SRP_ADVERTISING_PROXY +#include +#endif #include #include @@ -70,12 +81,135 @@ const Tlv *FindTlv(uint8_t aTlvType, const uint8_t *aTlvs, int aTlvsSize) exit: return result; } + +#if OTBR_ENABLE_TELEMETRY_DATA_API +static uint32_t TelemetryNodeTypeFromRoleAndLinkMode(const otDeviceRole &aRole, const otLinkModeConfig &aLinkModeCfg) +{ + uint32_t nodeType; + + switch (aRole) + { + case OT_DEVICE_ROLE_DISABLED: + nodeType = threadnetwork::TelemetryData::NODE_TYPE_DISABLED; + break; + case OT_DEVICE_ROLE_DETACHED: + nodeType = threadnetwork::TelemetryData::NODE_TYPE_DETACHED; + break; + case OT_DEVICE_ROLE_ROUTER: + nodeType = threadnetwork::TelemetryData::NODE_TYPE_ROUTER; + break; + case OT_DEVICE_ROLE_LEADER: + nodeType = threadnetwork::TelemetryData::NODE_TYPE_LEADER; + break; + case OT_DEVICE_ROLE_CHILD: + if (!aLinkModeCfg.mRxOnWhenIdle) + { + nodeType = threadnetwork::TelemetryData::NODE_TYPE_SLEEPY_END; + } + else if (!aLinkModeCfg.mDeviceType) + { + // If it's not an FTD, return as minimal end device. + nodeType = threadnetwork::TelemetryData::NODE_TYPE_MINIMAL_END; + } + else + { + nodeType = threadnetwork::TelemetryData::NODE_TYPE_END; + } + break; + default: + nodeType = threadnetwork::TelemetryData::NODE_TYPE_UNSPECIFIED; + } + + return nodeType; +} + +#if OTBR_ENABLE_SRP_ADVERTISING_PROXY +threadnetwork::TelemetryData_SrpServerState SrpServerStateFromOtSrpServerState(otSrpServerState srpServerState) +{ + switch (srpServerState) + { + case OT_SRP_SERVER_STATE_DISABLED: + return threadnetwork::TelemetryData::SRP_SERVER_STATE_DISABLED; + case OT_SRP_SERVER_STATE_RUNNING: + return threadnetwork::TelemetryData::SRP_SERVER_STATE_RUNNING; + case OT_SRP_SERVER_STATE_STOPPED: + return threadnetwork::TelemetryData::SRP_SERVER_STATE_STOPPED; + default: + return threadnetwork::TelemetryData::SRP_SERVER_STATE_UNSPECIFIED; + } +} + +threadnetwork::TelemetryData_SrpServerAddressMode SrpServerAddressModeFromOtSrpServerAddressMode( + otSrpServerAddressMode srpServerAddressMode) +{ + switch (srpServerAddressMode) + { + case OT_SRP_SERVER_ADDRESS_MODE_ANYCAST: + return threadnetwork::TelemetryData::SRP_SERVER_ADDRESS_MODE_STATE_ANYCAST; + case OT_SRP_SERVER_ADDRESS_MODE_UNICAST: + return threadnetwork::TelemetryData::SRP_SERVER_ADDRESS_MODE_UNICAST; + default: + return threadnetwork::TelemetryData::SRP_SERVER_ADDRESS_MODE_UNSPECIFIED; + } +} +#endif // OTBR_ENABLE_SRP_ADVERTISING_PROXY + +#if OTBR_ENABLE_NAT64 +threadnetwork::TelemetryData_Nat64State Nat64StateFromOtNat64State(otNat64State nat64State) +{ + switch (nat64State) + { + case OT_NAT64_STATE_DISABLED: + return threadnetwork::TelemetryData::NAT64_STATE_DISABLED; + case OT_NAT64_STATE_NOT_RUNNING: + return threadnetwork::TelemetryData::NAT64_STATE_NOT_RUNNING; + case OT_NAT64_STATE_IDLE: + return threadnetwork::TelemetryData::NAT64_STATE_IDLE; + case OT_NAT64_STATE_ACTIVE: + return threadnetwork::TelemetryData::NAT64_STATE_ACTIVE; + default: + return threadnetwork::TelemetryData::NAT64_STATE_UNSPECIFIED; + } +} + +void CopyNat64TrafficCounters(const otNat64Counters &from, threadnetwork::TelemetryData_Nat64TrafficCounters *to) +{ + to->set_ipv4_to_ipv6_packets(from.m4To6Packets); + to->set_ipv4_to_ipv6_bytes(from.m4To6Bytes); + to->set_ipv6_to_ipv4_packets(from.m6To4Packets); + to->set_ipv6_to_ipv4_bytes(from.m6To4Bytes); +} +#endif // OTBR_ENABLE_NAT64 + +void CopyMdnsResponseCounters(const MdnsResponseCounters &from, threadnetwork::TelemetryData_MdnsResponseCounters *to) +{ + to->set_success_count(from.mSuccess); + to->set_not_found_count(from.mNotFound); + to->set_invalid_args_count(from.mInvalidArgs); + to->set_duplicated_count(from.mDuplicated); + to->set_not_implemented_count(from.mNotImplemented); + to->set_unknown_error_count(from.mUnknownError); + to->set_aborted_count(from.mAborted); + to->set_invalid_state_count(from.mInvalidState); +} +#endif // OTBR_ENABLE_TELEMETRY_DATA_API } // namespace ThreadHelper::ThreadHelper(otInstance *aInstance, otbr::Ncp::ControllerOpenThread *aNcp) : mInstance(aInstance) , mNcp(aNcp) { +#if OTBR_ENABLE_TELEMETRY_DATA_API && OTBR_ENABLE_NAT64 + otError error; + + SuccessOrExit(error = otPlatCryptoRandomGet(mNat64Ipv6AddressSalt, sizeof(mNat64Ipv6AddressSalt))); + +exit: + if (error != OT_ERROR_NONE) + { + otbrLogWarning("Error otPlatCryptoRandomGet: %s", otThreadErrorToString(error)); + } +#endif } void ThreadHelper::StateChangedCallback(otChangedFlags aFlags) @@ -753,5 +887,505 @@ void ThreadHelper::DetachGracefullyCallback(void) } } +#if OTBR_ENABLE_TELEMETRY_DATA_API +otError ThreadHelper::RetrieveTelemetryData(Mdns::Publisher *aPublisher, threadnetwork::TelemetryData &telemetryData) +{ + otError error = OT_ERROR_NONE; + + // Begin of WpanStats section. + auto wpanStats = telemetryData.mutable_wpan_stats(); + + { + otDeviceRole role = otThreadGetDeviceRole(mInstance); + otLinkModeConfig otCfg = otThreadGetLinkMode(mInstance); + + wpanStats->set_node_type(TelemetryNodeTypeFromRoleAndLinkMode(role, otCfg)); + } + + wpanStats->set_channel(otLinkGetChannel(mInstance)); + + { + uint16_t ccaFailureRate = otLinkGetCcaFailureRate(mInstance); + + wpanStats->set_mac_cca_fail_rate(static_cast(ccaFailureRate) / 0xffff); + } + + { + int8_t radioTxPower; + + SuccessOrExit(error = otPlatRadioGetTransmitPower(mInstance, &radioTxPower)); + wpanStats->set_radio_tx_power(radioTxPower); + } + + { + const otMacCounters *linkCounters = otLinkGetCounters(mInstance); + + wpanStats->set_phy_rx(linkCounters->mRxTotal); + wpanStats->set_phy_tx(linkCounters->mTxTotal); + wpanStats->set_mac_unicast_rx(linkCounters->mRxUnicast); + wpanStats->set_mac_unicast_tx(linkCounters->mTxUnicast); + wpanStats->set_mac_broadcast_rx(linkCounters->mRxBroadcast); + wpanStats->set_mac_broadcast_tx(linkCounters->mTxBroadcast); + wpanStats->set_mac_tx_ack_req(linkCounters->mTxAckRequested); + wpanStats->set_mac_tx_no_ack_req(linkCounters->mTxNoAckRequested); + wpanStats->set_mac_tx_acked(linkCounters->mTxAcked); + wpanStats->set_mac_tx_data(linkCounters->mTxData); + wpanStats->set_mac_tx_data_poll(linkCounters->mTxDataPoll); + wpanStats->set_mac_tx_beacon(linkCounters->mTxBeacon); + wpanStats->set_mac_tx_beacon_req(linkCounters->mTxBeaconRequest); + wpanStats->set_mac_tx_other_pkt(linkCounters->mTxOther); + wpanStats->set_mac_tx_retry(linkCounters->mTxRetry); + wpanStats->set_mac_rx_data(linkCounters->mRxData); + wpanStats->set_mac_rx_data_poll(linkCounters->mRxDataPoll); + wpanStats->set_mac_rx_beacon(linkCounters->mRxBeacon); + wpanStats->set_mac_rx_beacon_req(linkCounters->mRxBeaconRequest); + wpanStats->set_mac_rx_other_pkt(linkCounters->mRxOther); + wpanStats->set_mac_rx_filter_whitelist(linkCounters->mRxAddressFiltered); + wpanStats->set_mac_rx_filter_dest_addr(linkCounters->mRxDestAddrFiltered); + wpanStats->set_mac_tx_fail_cca(linkCounters->mTxErrCca); + wpanStats->set_mac_rx_fail_decrypt(linkCounters->mRxErrSec); + wpanStats->set_mac_rx_fail_no_frame(linkCounters->mRxErrNoFrame); + wpanStats->set_mac_rx_fail_unknown_neighbor(linkCounters->mRxErrUnknownNeighbor); + wpanStats->set_mac_rx_fail_invalid_src_addr(linkCounters->mRxErrInvalidSrcAddr); + wpanStats->set_mac_rx_fail_fcs(linkCounters->mRxErrFcs); + wpanStats->set_mac_rx_fail_other(linkCounters->mRxErrOther); + } + + { + const otIpCounters *ipCounters = otThreadGetIp6Counters(mInstance); + + wpanStats->set_ip_tx_success(ipCounters->mTxSuccess); + wpanStats->set_ip_rx_success(ipCounters->mRxSuccess); + wpanStats->set_ip_tx_failure(ipCounters->mTxFailure); + wpanStats->set_ip_rx_failure(ipCounters->mRxFailure); + } + // End of WpanStats section. + + { + // Begin of WpanTopoFull section. + auto wpanTopoFull = telemetryData.mutable_wpan_topo_full(); + uint16_t rloc16 = otThreadGetRloc16(mInstance); + + wpanTopoFull->set_rloc16(rloc16); + + otRouterInfo info; + + VerifyOrExit(otThreadGetRouterInfo(mInstance, rloc16, &info) == OT_ERROR_NONE, error = OT_ERROR_INVALID_STATE); + wpanTopoFull->set_router_id(info.mRouterId); + + otNeighborInfoIterator iter = OT_NEIGHBOR_INFO_ITERATOR_INIT; + otNeighborInfo neighborInfo; + std::vector neighborTable; + + while (otThreadGetNextNeighborInfo(mInstance, &iter, &neighborInfo) == OT_ERROR_NONE) + { + neighborTable.push_back(neighborInfo); + } + wpanTopoFull->set_neighbor_table_size(neighborTable.size()); + + uint16_t childIndex = 0; + otChildInfo childInfo; + std::vector childTable; + + while (otThreadGetChildInfoByIndex(mInstance, childIndex, &childInfo) == OT_ERROR_NONE) + { + childTable.push_back(childInfo); + childIndex++; + } + wpanTopoFull->set_child_table_size(childTable.size()); + + struct otLeaderData leaderData; + + SuccessOrExit(error = otThreadGetLeaderData(mInstance, &leaderData)); + wpanTopoFull->set_leader_router_id(leaderData.mLeaderRouterId); + wpanTopoFull->set_leader_weight(leaderData.mWeighting); + wpanTopoFull->set_network_data_version(leaderData.mDataVersion); + wpanTopoFull->set_stable_network_data_version(leaderData.mStableDataVersion); + + uint8_t weight = otThreadGetLocalLeaderWeight(mInstance); + + wpanTopoFull->set_leader_local_weight(weight); + + uint32_t partitionId = otThreadGetPartitionId(mInstance); + + wpanTopoFull->set_partition_id(partitionId); + + static constexpr size_t kNetworkDataMaxSize = 255; + { + uint8_t data[kNetworkDataMaxSize]; + uint8_t len = sizeof(data); + std::vector networkData; + + SuccessOrExit(error = otNetDataGet(mInstance, /*stable=*/false, data, &len)); + networkData = std::vector(&data[0], &data[len]); + wpanTopoFull->set_network_data(std::string(networkData.begin(), networkData.end())); + } + + { + uint8_t data[kNetworkDataMaxSize]; + uint8_t len = sizeof(data); + std::vector networkData; + + SuccessOrExit(error = otNetDataGet(mInstance, /*stable=*/true, data, &len)); + networkData = std::vector(&data[0], &data[len]); + wpanTopoFull->set_stable_network_data(std::string(networkData.begin(), networkData.end())); + } + + int8_t rssi = otPlatRadioGetRssi(mInstance); + + wpanTopoFull->set_instant_rssi(rssi); + + const otExtendedPanId *extPanId = otThreadGetExtendedPanId(mInstance); + uint64_t extPanIdVal; + + extPanIdVal = ConvertOpenThreadUint64(extPanId->m8); + wpanTopoFull->set_extended_pan_id(extPanIdVal); + // End of WpanTopoFull section. + + // Begin of TopoEntry section. + std::map childMap; + + for (const otChildInfo &childInfo : childTable) + { + auto pair = childMap.insert({childInfo.mRloc16, &childInfo}); + if (!pair.second) + { + // This shouldn't happen, so log an error. It doesn't matter which + // duplicate is kept. + otbrLogErr("Children with duplicate RLOC16 found: 0x%04x", static_cast(childInfo.mRloc16)); + } + } + + for (const otNeighborInfo &neighborInfo : neighborTable) + { + auto topoEntry = telemetryData.add_topo_entries(); + topoEntry->set_rloc16(neighborInfo.mRloc16); + topoEntry->mutable_age()->set_seconds(neighborInfo.mAge); + topoEntry->set_link_quality_in(neighborInfo.mLinkQualityIn); + topoEntry->set_average_rssi(neighborInfo.mAverageRssi); + topoEntry->set_last_rssi(neighborInfo.mLastRssi); + topoEntry->set_link_frame_counter(neighborInfo.mLinkFrameCounter); + topoEntry->set_mle_frame_counter(neighborInfo.mMleFrameCounter); + topoEntry->set_rx_on_when_idle(neighborInfo.mRxOnWhenIdle); + topoEntry->set_secure_data_request(true); + topoEntry->set_full_function(neighborInfo.mFullThreadDevice); + topoEntry->set_full_network_data(neighborInfo.mFullNetworkData); + topoEntry->set_mac_frame_error_rate(static_cast(neighborInfo.mFrameErrorRate) / 0xffff); + topoEntry->set_ip_message_error_rate(static_cast(neighborInfo.mMessageErrorRate) / 0xffff); + topoEntry->set_version(neighborInfo.mVersion); + + if (!neighborInfo.mIsChild) + { + continue; + } + + auto it = childMap.find(neighborInfo.mRloc16); + if (it == childMap.end()) + { + otbrLogErr("Neighbor 0x%04x not found in child table", static_cast(neighborInfo.mRloc16)); + continue; + } + const otChildInfo *childInfo = it->second; + topoEntry->set_is_child(true); + topoEntry->mutable_timeout()->set_seconds(childInfo->mTimeout); + topoEntry->set_network_data_version(childInfo->mNetworkDataVersion); + } + // End of TopoEntry section. + } + + { + // Begin of WpanBorderRouter section. + auto wpanBorderRouter = telemetryData.mutable_wpan_border_router(); + // Begin of BorderRoutingCounters section. + auto borderRoutingCouters = wpanBorderRouter->mutable_border_routing_counters(); + const otBorderRoutingCounters *otBorderRoutingCounters = otIp6GetBorderRoutingCounters(mInstance); + + borderRoutingCouters->mutable_inbound_unicast()->set_packet_count( + otBorderRoutingCounters->mInboundUnicast.mPackets); + borderRoutingCouters->mutable_inbound_unicast()->set_byte_count( + otBorderRoutingCounters->mInboundUnicast.mBytes); + borderRoutingCouters->mutable_inbound_multicast()->set_packet_count( + otBorderRoutingCounters->mInboundMulticast.mPackets); + borderRoutingCouters->mutable_inbound_multicast()->set_byte_count( + otBorderRoutingCounters->mInboundMulticast.mBytes); + borderRoutingCouters->mutable_outbound_unicast()->set_packet_count( + otBorderRoutingCounters->mOutboundUnicast.mPackets); + borderRoutingCouters->mutable_outbound_unicast()->set_byte_count( + otBorderRoutingCounters->mOutboundUnicast.mBytes); + borderRoutingCouters->mutable_outbound_multicast()->set_packet_count( + otBorderRoutingCounters->mOutboundMulticast.mPackets); + borderRoutingCouters->mutable_outbound_multicast()->set_byte_count( + otBorderRoutingCounters->mOutboundMulticast.mBytes); + borderRoutingCouters->set_ra_rx(otBorderRoutingCounters->mRaRx); + borderRoutingCouters->set_ra_tx_success(otBorderRoutingCounters->mRaTxSuccess); + borderRoutingCouters->set_ra_tx_failure(otBorderRoutingCounters->mRaTxFailure); + borderRoutingCouters->set_rs_rx(otBorderRoutingCounters->mRsRx); + borderRoutingCouters->set_rs_tx_success(otBorderRoutingCounters->mRsTxSuccess); + borderRoutingCouters->set_rs_tx_failure(otBorderRoutingCounters->mRsTxFailure); + +#if OTBR_ENABLE_NAT64 + { + auto nat64IcmpCounters = borderRoutingCouters->mutable_nat64_protocol_counters()->mutable_icmp(); + auto nat64UdpCounters = borderRoutingCouters->mutable_nat64_protocol_counters()->mutable_udp(); + auto nat64TcpCounters = borderRoutingCouters->mutable_nat64_protocol_counters()->mutable_tcp(); + otNat64ProtocolCounters otCounters; + + otNat64GetCounters(mInstance, &otCounters); + nat64IcmpCounters->set_ipv4_to_ipv6_packets(otCounters.mIcmp.m4To6Packets); + nat64IcmpCounters->set_ipv4_to_ipv6_bytes(otCounters.mIcmp.m4To6Bytes); + nat64IcmpCounters->set_ipv6_to_ipv4_packets(otCounters.mIcmp.m6To4Packets); + nat64IcmpCounters->set_ipv6_to_ipv4_bytes(otCounters.mIcmp.m6To4Bytes); + nat64UdpCounters->set_ipv4_to_ipv6_packets(otCounters.mUdp.m4To6Packets); + nat64UdpCounters->set_ipv4_to_ipv6_bytes(otCounters.mUdp.m4To6Bytes); + nat64UdpCounters->set_ipv6_to_ipv4_packets(otCounters.mUdp.m6To4Packets); + nat64UdpCounters->set_ipv6_to_ipv4_bytes(otCounters.mUdp.m6To4Bytes); + nat64TcpCounters->set_ipv4_to_ipv6_packets(otCounters.mTcp.m4To6Packets); + nat64TcpCounters->set_ipv4_to_ipv6_bytes(otCounters.mTcp.m4To6Bytes); + nat64TcpCounters->set_ipv6_to_ipv4_packets(otCounters.mTcp.m6To4Packets); + nat64TcpCounters->set_ipv6_to_ipv4_bytes(otCounters.mTcp.m6To4Bytes); + } + + { + auto errorCounters = borderRoutingCouters->mutable_nat64_error_counters(); + otNat64ErrorCounters otCounters; + otNat64GetErrorCounters(mInstance, &otCounters); + + errorCounters->mutable_unknown()->set_ipv4_to_ipv6_packets( + otCounters.mCount4To6[OT_NAT64_DROP_REASON_UNKNOWN]); + errorCounters->mutable_unknown()->set_ipv6_to_ipv4_packets( + otCounters.mCount6To4[OT_NAT64_DROP_REASON_UNKNOWN]); + errorCounters->mutable_illegal_packet()->set_ipv4_to_ipv6_packets( + otCounters.mCount4To6[OT_NAT64_DROP_REASON_ILLEGAL_PACKET]); + errorCounters->mutable_illegal_packet()->set_ipv6_to_ipv4_packets( + otCounters.mCount6To4[OT_NAT64_DROP_REASON_ILLEGAL_PACKET]); + errorCounters->mutable_unsupported_protocol()->set_ipv4_to_ipv6_packets( + otCounters.mCount4To6[OT_NAT64_DROP_REASON_UNSUPPORTED_PROTO]); + errorCounters->mutable_unsupported_protocol()->set_ipv6_to_ipv4_packets( + otCounters.mCount6To4[OT_NAT64_DROP_REASON_UNSUPPORTED_PROTO]); + errorCounters->mutable_no_mapping()->set_ipv4_to_ipv6_packets( + otCounters.mCount4To6[OT_NAT64_DROP_REASON_NO_MAPPING]); + errorCounters->mutable_no_mapping()->set_ipv6_to_ipv4_packets( + otCounters.mCount6To4[OT_NAT64_DROP_REASON_NO_MAPPING]); + } +#endif // OTBR_ENABLE_NAT64 + // End of BorderRoutingCounters section. + +#if OTBR_ENABLE_SRP_ADVERTISING_PROXY + // Begin of SrpServerInfo section. + { + auto srpServer = wpanBorderRouter->mutable_srp_server(); + otSrpServerLeaseInfo leaseInfo; + const otSrpServerHost *host = nullptr; + const otSrpServerResponseCounters *responseCounters = otSrpServerGetResponseCounters(mInstance); + + srpServer->set_state(SrpServerStateFromOtSrpServerState(otSrpServerGetState(mInstance))); + srpServer->set_port(otSrpServerGetPort(mInstance)); + srpServer->set_address_mode( + SrpServerAddressModeFromOtSrpServerAddressMode(otSrpServerGetAddressMode(mInstance))); + + auto srpServerHosts = srpServer->mutable_hosts(); + auto srpServerServices = srpServer->mutable_services(); + auto srpServerResponseCounters = srpServer->mutable_response_counters(); + + while ((host = otSrpServerGetNextHost(mInstance, host))) + { + const otSrpServerService *service = nullptr; + + if (otSrpServerHostIsDeleted(host)) + { + srpServerHosts->set_deleted_count(srpServerHosts->deleted_count() + 1); + } + else + { + srpServerHosts->set_fresh_count(srpServerHosts->fresh_count() + 1); + otSrpServerHostGetLeaseInfo(host, &leaseInfo); + srpServerHosts->set_lease_time_total_ms(srpServerHosts->lease_time_total_ms() + leaseInfo.mLease); + srpServerHosts->set_key_lease_time_total_ms(srpServerHosts->key_lease_time_total_ms() + + leaseInfo.mKeyLease); + srpServerHosts->set_remaining_lease_time_total_ms(srpServerHosts->remaining_lease_time_total_ms() + + leaseInfo.mRemainingLease); + srpServerHosts->set_remaining_key_lease_time_total_ms( + srpServerHosts->remaining_key_lease_time_total_ms() + leaseInfo.mRemainingKeyLease); + } + + while ((service = otSrpServerHostGetNextService(host, service))) + { + if (otSrpServerServiceIsDeleted(service)) + { + srpServerServices->set_deleted_count(srpServerServices->deleted_count() + 1); + } + else + { + srpServerServices->set_fresh_count(srpServerServices->fresh_count() + 1); + otSrpServerServiceGetLeaseInfo(service, &leaseInfo); + srpServerServices->set_lease_time_total_ms(srpServerServices->lease_time_total_ms() + + leaseInfo.mLease); + srpServerServices->set_key_lease_time_total_ms(srpServerServices->key_lease_time_total_ms() + + leaseInfo.mKeyLease); + srpServerServices->set_remaining_lease_time_total_ms( + srpServerServices->remaining_lease_time_total_ms() + leaseInfo.mRemainingLease); + srpServerServices->set_remaining_key_lease_time_total_ms( + srpServerServices->remaining_key_lease_time_total_ms() + leaseInfo.mRemainingKeyLease); + } + } + } + + srpServerResponseCounters->set_success_count(responseCounters->mSuccess); + srpServerResponseCounters->set_server_failure_count(responseCounters->mServerFailure); + srpServerResponseCounters->set_format_error_count(responseCounters->mFormatError); + srpServerResponseCounters->set_name_exists_count(responseCounters->mNameExists); + srpServerResponseCounters->set_refused_count(responseCounters->mRefused); + srpServerResponseCounters->set_other_count(responseCounters->mOther); + } + // End of SrpServerInfo section. +#endif // OTBR_ENABLE_SRP_ADVERTISING_PROXY + +#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY + // Begin of DnsServerInfo section. + { + auto dnsServer = wpanBorderRouter->mutable_dns_server(); + auto dnsServerResponseCounters = dnsServer->mutable_response_counters(); + otDnssdCounters otDnssdCounters = *otDnssdGetCounters(mInstance); + + dnsServerResponseCounters->set_success_count(otDnssdCounters.mSuccessResponse); + dnsServerResponseCounters->set_server_failure_count(otDnssdCounters.mServerFailureResponse); + dnsServerResponseCounters->set_format_error_count(otDnssdCounters.mFormatErrorResponse); + dnsServerResponseCounters->set_name_error_count(otDnssdCounters.mNameErrorResponse); + dnsServerResponseCounters->set_not_implemented_count(otDnssdCounters.mNotImplementedResponse); + dnsServerResponseCounters->set_other_count(otDnssdCounters.mOtherResponse); + + dnsServer->set_resolved_by_local_srp_count(otDnssdCounters.mResolvedBySrp); + } + // End of DnsServerInfo section. +#endif // OTBR_ENABLE_DNSSD_DISCOVERY_PROXY + + // Start of MdnsInfo section. + if (aPublisher != nullptr) + { + auto mdns = wpanBorderRouter->mutable_mdns(); + const MdnsTelemetryInfo &mdnsInfo = aPublisher->GetMdnsTelemetryInfo(); + + CopyMdnsResponseCounters(mdnsInfo.mHostRegistrations, mdns->mutable_host_registration_responses()); + CopyMdnsResponseCounters(mdnsInfo.mServiceRegistrations, mdns->mutable_service_registration_responses()); + CopyMdnsResponseCounters(mdnsInfo.mHostResolutions, mdns->mutable_host_resolution_responses()); + CopyMdnsResponseCounters(mdnsInfo.mServiceResolutions, mdns->mutable_service_resolution_responses()); + + mdns->set_host_registration_ema_latency_ms(mdnsInfo.mHostRegistrationEmaLatency); + mdns->set_service_registration_ema_latency_ms(mdnsInfo.mServiceRegistrationEmaLatency); + mdns->set_host_resolution_ema_latency_ms(mdnsInfo.mHostResolutionEmaLatency); + mdns->set_service_resolution_ema_latency_ms(mdnsInfo.mServiceResolutionEmaLatency); + } + // End of MdnsInfo section. + +#if OTBR_ENABLE_NAT64 + // Start of BorderRoutingNat64State section. + { + auto nat64State = wpanBorderRouter->mutable_nat64_state(); + + nat64State->set_prefix_manager_state(Nat64StateFromOtNat64State(otNat64GetPrefixManagerState(mInstance))); + nat64State->set_translator_state(Nat64StateFromOtNat64State(otNat64GetTranslatorState(mInstance))); + } + // End of BorderRoutingNat64State section. + + // Start of Nat64Mapping section. + { + otNat64AddressMappingIterator iterator; + otNat64AddressMapping otMapping; + Sha256::Hash hash; + Sha256 sha256; + + otNat64InitAddressMappingIterator(mInstance, &iterator); + while (otNat64GetNextAddressMapping(mInstance, &iterator, &otMapping) == OT_ERROR_NONE) + { + auto nat64Mapping = wpanBorderRouter->add_nat64_mappings(); + auto nat64MappingCounters = nat64Mapping->mutable_counters(); + + nat64Mapping->set_mapping_id(otMapping.mId); + CopyNat64TrafficCounters(otMapping.mCounters.mTcp, nat64MappingCounters->mutable_tcp()); + CopyNat64TrafficCounters(otMapping.mCounters.mUdp, nat64MappingCounters->mutable_udp()); + CopyNat64TrafficCounters(otMapping.mCounters.mIcmp, nat64MappingCounters->mutable_icmp()); + + { + uint8_t ipAddrShaInput[OT_IP6_ADDRESS_SIZE + kNat64SourceAddressHashSaltLength]; + memcpy(ipAddrShaInput, otMapping.mIp6.mFields.m8, sizeof(otMapping.mIp6.mFields.m8)); + memcpy(&ipAddrShaInput[sizeof(otMapping.mIp6.mFields.m8)], mNat64Ipv6AddressSalt, + sizeof(mNat64Ipv6AddressSalt)); + + sha256.Start(); + sha256.Update(ipAddrShaInput, sizeof(ipAddrShaInput)); + sha256.Finish(hash); + + nat64Mapping->mutable_hashed_ipv6_address()->append(reinterpret_cast(hash.GetBytes()), + sizeof(hash.GetBytes())); + // Remaining time is not included in the telemetry + } + } + } + // End of Nat64Mapping section. +#endif // OTBR_ENABLE_NAT64 + + // End of WpanBorderRouter section. + + // Start of WpanRcp section. + { + auto wpanRcp = telemetryData.mutable_wpan_rcp(); + auto rcpStabilityStatistics = wpanRcp->mutable_rcp_stability_statistics(); + otRadioSpinelMetrics otRadioSpinelMetrics = *otSysGetRadioSpinelMetrics(); + + rcpStabilityStatistics->set_rcp_timeout_count(otRadioSpinelMetrics.mRcpTimeoutCount); + rcpStabilityStatistics->set_rcp_reset_count(otRadioSpinelMetrics.mRcpUnexpectedResetCount); + rcpStabilityStatistics->set_rcp_restoration_count(otRadioSpinelMetrics.mRcpRestorationCount); + rcpStabilityStatistics->set_spinel_parse_error_count(otRadioSpinelMetrics.mSpinelParseErrorCount); + + // TODO: provide rcp_firmware_update_count info. + rcpStabilityStatistics->set_thread_stack_uptime(otInstanceGetUptime(mInstance)); + + auto rcpInterfaceStatistics = wpanRcp->mutable_rcp_interface_statistics(); + otRcpInterfaceMetrics otRcpInterfaceMetrics = *otSysGetRcpInterfaceMetrics(); + + rcpInterfaceStatistics->set_rcp_interface_type(otRcpInterfaceMetrics.mRcpInterfaceType); + rcpInterfaceStatistics->set_transferred_frames_count(otRcpInterfaceMetrics.mTransferredFrameCount); + rcpInterfaceStatistics->set_transferred_valid_frames_count( + otRcpInterfaceMetrics.mTransferredValidFrameCount); + rcpInterfaceStatistics->set_transferred_garbage_frames_count( + otRcpInterfaceMetrics.mTransferredGarbageFrameCount); + rcpInterfaceStatistics->set_rx_frames_count(otRcpInterfaceMetrics.mRxFrameCount); + rcpInterfaceStatistics->set_rx_bytes_count(otRcpInterfaceMetrics.mRxFrameByteCount); + rcpInterfaceStatistics->set_tx_frames_count(otRcpInterfaceMetrics.mTxFrameCount); + rcpInterfaceStatistics->set_tx_bytes_count(otRcpInterfaceMetrics.mTxFrameByteCount); + } + // End of WpanRcp section. + + // Start of CoexMetrics section. + { + auto coexMetrics = telemetryData.mutable_coex_metrics(); + otRadioCoexMetrics otRadioCoexMetrics; + + SuccessOrExit(error = otPlatRadioGetCoexMetrics(mInstance, &otRadioCoexMetrics)); + coexMetrics->set_count_tx_request(otRadioCoexMetrics.mNumTxRequest); + coexMetrics->set_count_tx_grant_immediate(otRadioCoexMetrics.mNumTxGrantImmediate); + coexMetrics->set_count_tx_grant_wait(otRadioCoexMetrics.mNumTxGrantWait); + coexMetrics->set_count_tx_grant_wait_activated(otRadioCoexMetrics.mNumTxGrantWaitActivated); + coexMetrics->set_count_tx_grant_wait_timeout(otRadioCoexMetrics.mNumTxGrantWaitTimeout); + coexMetrics->set_count_tx_grant_deactivated_during_request( + otRadioCoexMetrics.mNumTxGrantDeactivatedDuringRequest); + coexMetrics->set_tx_average_request_to_grant_time_us(otRadioCoexMetrics.mAvgTxRequestToGrantTime); + coexMetrics->set_count_rx_request(otRadioCoexMetrics.mNumRxRequest); + coexMetrics->set_count_rx_grant_immediate(otRadioCoexMetrics.mNumRxGrantImmediate); + coexMetrics->set_count_rx_grant_wait(otRadioCoexMetrics.mNumRxGrantWait); + coexMetrics->set_count_rx_grant_wait_activated(otRadioCoexMetrics.mNumRxGrantWaitActivated); + coexMetrics->set_count_rx_grant_wait_timeout(otRadioCoexMetrics.mNumRxGrantWaitTimeout); + coexMetrics->set_count_rx_grant_deactivated_during_request( + otRadioCoexMetrics.mNumRxGrantDeactivatedDuringRequest); + coexMetrics->set_count_rx_grant_none(otRadioCoexMetrics.mNumRxGrantNone); + coexMetrics->set_rx_average_request_to_grant_time_us(otRadioCoexMetrics.mAvgRxRequestToGrantTime); + } + // End of CoexMetrics section. + } + +exit: + return error; +} +#endif // OTBR_ENABLE_TELEMETRY_DATA_API } // namespace agent } // namespace otbr diff --git a/src/utils/thread_helper.hpp b/src/utils/thread_helper.hpp index d9a37bdf..10d38770 100644 --- a/src/utils/thread_helper.hpp +++ b/src/utils/thread_helper.hpp @@ -49,6 +49,10 @@ #include #include #include +#include "mdns/mdns.hpp" +#if OTBR_ENABLE_TELEMETRY_DATA_API +#include "proto/thread_telemetry.pb.h" +#endif namespace otbr { namespace Ncp { @@ -252,6 +256,18 @@ class ThreadHelper void DetachGracefully(ResultHandler aHandler); +#if OTBR_ENABLE_TELEMETRY_DATA_API + /** + * This method populates the telemetry data and returns the error code if error happens. + * + * @param[in] aPublisher The Mdns::Publisher to provide MDNS telemetry if it is not `nullptr`. + * @param[in] telemetryData The telemetry data to be populated. + * + * @returns The error code if error happens during the population of the telemetry data. + */ + otError RetrieveTelemetryData(Mdns::Publisher *aPublisher, threadnetwork::TelemetryData &telemetryData); +#endif // OTBR_ENABLE_TELEMETRY_DATA_API + /** * This method logs OpenThread action result. * @@ -311,6 +327,11 @@ class ThreadHelper #if OTBR_ENABLE_DBUS_SERVER UpdateMeshCopTxtHandler mUpdateMeshCopTxtHandler; #endif + +#if OTBR_ENABLE_TELEMETRY_DATA_API & OTBR_ENABLE_NAT64 + static const uint8_t kNat64SourceAddressHashSaltLength = 16; + uint8_t mNat64Ipv6AddressSalt[kNat64SourceAddressHashSaltLength]; +#endif }; } // namespace agent diff --git a/src/web/main.cpp b/src/web/main.cpp index be6d34c0..4e25e058 100644 --- a/src/web/main.cpp +++ b/src/web/main.cpp @@ -46,7 +46,6 @@ #include "common/logging.hpp" #include "web/web-service/web_server.hpp" -static const char kSyslogIdent[] = "otbr-web"; static const char kDefaultInterfaceName[] = "wpan0"; static const char kDefaultListenAddr[] = "::"; @@ -112,7 +111,7 @@ int main(int argc, char **argv) } } - otbrLogInit(kSyslogIdent, logLevel, true); + otbrLogInit(argv[0], logLevel, true); otbrLogInfo("Running %s", OTBR_PACKAGE_VERSION); if (interfaceName == nullptr) diff --git a/tests/dbus/CMakeLists.txt b/tests/dbus/CMakeLists.txt index 00daaf93..5aa3f471 100644 --- a/tests/dbus/CMakeLists.txt +++ b/tests/dbus/CMakeLists.txt @@ -30,11 +30,6 @@ add_executable(otbr-test-dbus-client test_dbus_client.cpp ) -target_include_directories(otbr-test-dbus-client PRIVATE - ${PROJECT_BINARY_DIR}/src - ${PROJECT_SOURCE_DIR}/build/src -) - target_link_libraries(otbr-test-dbus-client PRIVATE otbr-dbus-client otbr-proto diff --git a/tests/dbus/test_dbus_client.cpp b/tests/dbus/test_dbus_client.cpp index 20ff341d..0e0e6134 100644 --- a/tests/dbus/test_dbus_client.cpp +++ b/tests/dbus/test_dbus_client.cpp @@ -267,6 +267,27 @@ void CheckTelemetryData(ThreadApiDBus *aApi) TEST_ASSERT(telemetryData.wpan_stats().phy_tx() > 0); TEST_ASSERT(telemetryData.wpan_stats().phy_rx() > 0); TEST_ASSERT(telemetryData.wpan_stats().ip_tx_success() > 0); + TEST_ASSERT(telemetryData.wpan_topo_full().rloc16() > 0); + TEST_ASSERT(telemetryData.wpan_topo_full().network_data().size() > 0); + TEST_ASSERT(telemetryData.wpan_topo_full().partition_id() > 0); + TEST_ASSERT(telemetryData.wpan_topo_full().extended_pan_id() > 0); + TEST_ASSERT(telemetryData.topo_entries_size() == 1); + TEST_ASSERT(telemetryData.topo_entries(0).rloc16() > 0); + TEST_ASSERT(telemetryData.wpan_border_router().border_routing_counters().rs_tx_failure() == 0); +#if OTBR_ENABLE_SRP_ADVERTISING_PROXY + TEST_ASSERT(telemetryData.wpan_border_router().srp_server().state() == + threadnetwork::TelemetryData::SRP_SERVER_STATE_RUNNING); +#endif +#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY + TEST_ASSERT(telemetryData.wpan_border_router().dns_server().response_counters().server_failure_count() == 0); +#endif + TEST_ASSERT(telemetryData.wpan_border_router().mdns().service_registration_responses().success_count() > 0); +#if OTBR_ENABLE_NAT64 + TEST_ASSERT(telemetryData.wpan_border_router().nat64_state().prefix_manager_state() == + threadnetwork::TelemetryData::NAT64_STATE_NOT_RUNNING); +#endif + TEST_ASSERT(telemetryData.wpan_rcp().rcp_interface_statistics().transferred_frames_count() > 0); + TEST_ASSERT(telemetryData.coex_metrics().count_tx_request() > 0); } #endif @@ -317,7 +338,6 @@ int main() TEST_ASSERT(region == "US"); TEST_ASSERT(api->GetPreferredChannelMask(preferredChannelMask) == ClientError::ERROR_NONE); - TEST_ASSERT(preferredChannelMask == 0x7fff800); api->EnergyScan(scanDuration, [&stepDone](const std::vector &aResult) { TEST_ASSERT(!aResult.empty()); diff --git a/tests/mdns/main.cpp b/tests/mdns/main.cpp index 758ed1b2..66f6366c 100644 --- a/tests/mdns/main.cpp +++ b/tests/mdns/main.cpp @@ -96,14 +96,17 @@ void PublishSingleServiceWithCustomHost(void *aContext, Mdns::Publisher::State a VerifyOrDie(aContext == &sContext, "unexpected context"); if (aState == Mdns::Publisher::State::kReady) { + Mdns::Publisher::TxtData txtData; Mdns::Publisher::TxtList txtList{ {"nn", "cool"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"xa", extAddr, sizeof(extAddr)}}; + Mdns::Publisher::EncodeTxtData(txtList, txtData); + sContext.mPublisher->PublishHost(hostName, {Ip6Address(hostAddr)}, [](otbrError aError) { SuccessOrDie(aError, "cannot publish the host"); }); sContext.mPublisher->PublishService( - hostName, "SingleService", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList, + hostName, "SingleService", "_meshcop._udp", Mdns::Publisher::SubTypeList{}, 12345, txtData, [](otbrError aError) { SuccessOrDie(aError, "cannot publish the service"); }); } } @@ -123,18 +126,21 @@ void PublishMultipleServicesWithCustomHost(void *aContext, Mdns::Publisher::Stat VerifyOrDie(aContext == &sContext, "unexpected context"); if (aState == Mdns::Publisher::State::kReady) { + Mdns::Publisher::TxtData txtData; Mdns::Publisher::TxtList txtList{ {"nn", "cool"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"xa", extAddr, sizeof(extAddr)}}; + Mdns::Publisher::EncodeTxtData(txtList, txtData); + sContext.mPublisher->PublishHost(hostName1, {Ip6Address(hostAddr)}, [](otbrError aError) { SuccessOrDie(aError, "cannot publish the host"); }); sContext.mPublisher->PublishService( - hostName1, "MultipleService11", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList, + hostName1, "MultipleService11", "_meshcop._udp", Mdns::Publisher::SubTypeList{}, 12345, txtData, [](otbrError aError) { SuccessOrDie(aError, "cannot publish the first service"); }); sContext.mPublisher->PublishService( - hostName1, "MultipleService12", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList, + hostName1, "MultipleService12", "_meshcop._udp", Mdns::Publisher::SubTypeList{}, 12345, txtData, [](otbrError aError) { SuccessOrDie(aError, "cannot publish the second service"); }); sContext.mPublisher->PublishHost(hostName2, {Ip6Address(hostAddr)}, [](otbrError aError) { @@ -142,11 +148,11 @@ void PublishMultipleServicesWithCustomHost(void *aContext, Mdns::Publisher::Stat }); sContext.mPublisher->PublishService( - hostName2, "MultipleService21", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList, + hostName2, "MultipleService21", "_meshcop._udp", Mdns::Publisher::SubTypeList{}, 12345, txtData, [](otbrError aError) { SuccessOrDie(aError, "cannot publish the first service"); }); sContext.mPublisher->PublishService( - hostName2, "MultipleService22", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList, + hostName2, "MultipleService22", "_meshcop._udp", Mdns::Publisher::SubTypeList{}, 12345, txtData, [](otbrError aError) { SuccessOrDie(aError, "cannot publish the second service"); }); } } @@ -157,15 +163,18 @@ void PublishSingleService(void *aContext, Mdns::Publisher::State aState) uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; + Mdns::Publisher::TxtData txtData; Mdns::Publisher::TxtList txtList{ {"nn", "cool"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"xa", extAddr, sizeof(extAddr)}}; + Mdns::Publisher::EncodeTxtData(txtList, txtData); + assert(aContext == &sContext); if (aState == Mdns::Publisher::State::kReady) { sContext.mPublisher->PublishService( - "", "SingleService", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList, - [](otbrError aError) { SuccessOrDie(aError, "SingleService._meshcop._udp."); }); + "", "SingleService", "_meshcop._udp", Mdns::Publisher::SubTypeList{}, 12345, txtData, + [](otbrError aError) { SuccessOrDie(aError, "SingleService._meshcop._udp"); }); } } @@ -175,14 +184,17 @@ void PublishSingleServiceWithEmptyName(void *aContext, Mdns::Publisher::State aS uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; uint8_t extAddr[kSizeExtAddr] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; + Mdns::Publisher::TxtData txtData; Mdns::Publisher::TxtList txtList{ {"nn", "cool"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"xa", extAddr, sizeof(extAddr)}}; + Mdns::Publisher::EncodeTxtData(txtList, txtData); + assert(aContext == &sContext); if (aState == Mdns::Publisher::State::kReady) { - sContext.mPublisher->PublishService("", "", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList, - [](otbrError aError) { SuccessOrDie(aError, "(empty)._meshcop._udp."); }); + sContext.mPublisher->PublishService("", "", "_meshcop._udp", Mdns::Publisher::SubTypeList{}, 12345, txtData, + [](otbrError aError) { SuccessOrDie(aError, "(empty)._meshcop._udp"); }); } } @@ -196,22 +208,28 @@ void PublishMultipleServices(void *aContext, Mdns::Publisher::State aState) assert(aContext == &sContext); if (aState == Mdns::Publisher::State::kReady) { + Mdns::Publisher::TxtData txtData; Mdns::Publisher::TxtList txtList{ {"nn", "cool1"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"xa", extAddr, sizeof(extAddr)}}; + Mdns::Publisher::EncodeTxtData(txtList, txtData); + sContext.mPublisher->PublishService( - "", "MultipleService1", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList, - [](otbrError aError) { SuccessOrDie(aError, "MultipleService1._meshcop._udp."); }); + "", "MultipleService1", "_meshcop._udp", Mdns::Publisher::SubTypeList{}, 12345, txtData, + [](otbrError aError) { SuccessOrDie(aError, "MultipleService1._meshcop._udp"); }); } if (aState == Mdns::Publisher::State::kReady) { + Mdns::Publisher::TxtData txtData; Mdns::Publisher::TxtList txtList{ {"nn", "cool2"}, {"xp", xpanid, sizeof(xpanid)}, {"tv", "1.1.1"}, {"xa", extAddr, sizeof(extAddr)}}; + Mdns::Publisher::EncodeTxtData(txtList, txtData); + sContext.mPublisher->PublishService( - "", "MultipleService2", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList, - [](otbrError aError) { SuccessOrDie(aError, "MultipleService2._meshcop._udp."); }); + "", "MultipleService2", "_meshcop._udp", Mdns::Publisher::SubTypeList{}, 12345, txtData, + [](otbrError aError) { SuccessOrDie(aError, "MultipleService2._meshcop._udp"); }); } } @@ -226,28 +244,38 @@ void PublishUpdateServices(void *aContext) assert(aContext == &sContext); if (!sContext.mUpdate) { + Mdns::Publisher::TxtData txtData; Mdns::Publisher::TxtList txtList{ {"nn", "cool"}, {"xp", xpanidOld, sizeof(xpanidOld)}, {"tv", "1.1.1"}, {"xa", extAddr, sizeof(extAddr)}}; + Mdns::Publisher::EncodeTxtData(txtList, txtData); + sContext.mPublisher->PublishService( - "", "UpdateService", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList, + "", "UpdateService", "_meshcop._udp", Mdns::Publisher::SubTypeList{}, 12345, txtData, [](otbrError aError) { otbrLogResult(aError, "UpdateService._meshcop._udp"); }); } else { + Mdns::Publisher::TxtData txtData; Mdns::Publisher::TxtList txtList{{"nn", "coolcool"}, {"xp", xpanidNew, sizeof(xpanidNew)}, {"tv", "1.1.1"}, {"xa", extAddr, sizeof(extAddr)}}; + Mdns::Publisher::EncodeTxtData(txtList, txtData); + sContext.mPublisher->PublishService( - "", "UpdateService", "_meshcop._udp.", Mdns::Publisher::SubTypeList{}, 12345, txtList, + "", "UpdateService", "_meshcop._udp", Mdns::Publisher::SubTypeList{}, 12345, txtData, [](otbrError aError) { SuccessOrDie(aError, "UpdateService._meshcop._udp"); }); } } void PublishServiceSubTypes(void *aContext) { + Mdns::Publisher::TxtData txtData; + + txtData.push_back(0); + OT_UNUSED_VARIABLE(aContext); assert(aContext == &sContext); @@ -257,8 +285,8 @@ void PublishServiceSubTypes(void *aContext) subTypeList.back() = "_SUBTYPE3"; sContext.mPublisher->PublishService( - "", "ServiceWithSubTypes", "_meshcop._udp.", subTypeList, 12345, Mdns::Publisher::TxtList{}, - [](otbrError aError) { SuccessOrDie(aError, "ServiceWithSubTypes._meshcop._udp."); }); + "", "ServiceWithSubTypes", "_meshcop._udp", subTypeList, 12345, txtData, + [](otbrError aError) { SuccessOrDie(aError, "ServiceWithSubTypes._meshcop._udp"); }); } otbrError TestSingleServiceWithCustomHost(void) @@ -410,10 +438,65 @@ otbrError TestStopService(void) return ret; } +otbrError CheckTxtDataEncoderDecoder(void) +{ + otbrError error = OTBR_ERROR_NONE; + Mdns::Publisher::TxtList txtList; + Mdns::Publisher::TxtList parsedTxtList; + std::vector txtData; + + // Encode empty `TxtList` + + SuccessOrExit(error = Mdns::Publisher::EncodeTxtData(txtList, txtData)); + VerifyOrExit(txtData.size() == 1, error = OTBR_ERROR_PARSE); + VerifyOrExit(txtData[0] == 0, error = OTBR_ERROR_PARSE); + + SuccessOrExit(error = Mdns::Publisher::DecodeTxtData(parsedTxtList, txtData.data(), txtData.size())); + VerifyOrExit(parsedTxtList.size() == 0, error = OTBR_ERROR_PARSE); + + // TxtList with one bool attribute + + txtList.clear(); + txtList.emplace_back("b1"); + + SuccessOrExit(error = Mdns::Publisher::EncodeTxtData(txtList, txtData)); + SuccessOrExit(error = Mdns::Publisher::DecodeTxtData(parsedTxtList, txtData.data(), txtData.size())); + VerifyOrExit(parsedTxtList == txtList, error = OTBR_ERROR_PARSE); + + // TxtList with one one key/value + + txtList.clear(); + txtList.emplace_back("k1", "v1"); + + SuccessOrExit(error = Mdns::Publisher::EncodeTxtData(txtList, txtData)); + SuccessOrExit(error = Mdns::Publisher::DecodeTxtData(parsedTxtList, txtData.data(), txtData.size())); + VerifyOrExit(parsedTxtList == txtList, error = OTBR_ERROR_PARSE); + + // TxtList with multiple entries + + txtList.clear(); + txtList.emplace_back("k1", "v1"); + txtList.emplace_back("b1"); + txtList.emplace_back("b2"); + txtList.emplace_back("k2", "valu2"); + + SuccessOrExit(error = Mdns::Publisher::EncodeTxtData(txtList, txtData)); + SuccessOrExit(error = Mdns::Publisher::DecodeTxtData(parsedTxtList, txtData.data(), txtData.size())); + VerifyOrExit(parsedTxtList == txtList, error = OTBR_ERROR_PARSE); + +exit: + return error; +} + int main(int argc, char *argv[]) { int ret = 0; + if (CheckTxtDataEncoderDecoder() != OTBR_ERROR_NONE) + { + return 1; + } + if (argc < 2) { return 1; diff --git a/tests/scripts/bootstrap.sh b/tests/scripts/bootstrap.sh index a89e9ccd..f3bdf513 100755 --- a/tests/scripts/bootstrap.sh +++ b/tests/scripts/bootstrap.sh @@ -32,6 +32,8 @@ set -euxo pipefail TOOLS_HOME="$HOME"/.cache/tools [[ -d $TOOLS_HOME ]] || mkdir -p "$TOOLS_HOME" +MDNSRESPONDER_PATCH_PATH=$(realpath "$(dirname "$0")"/../../third_party/mDNSResponder) + disable_install_recommends() { OTBR_APT_CONF_FILE=/etc/apt/apt.conf @@ -126,15 +128,18 @@ case "$(uname)" in fi if [ "${OTBR_MDNS-}" == 'mDNSResponder' ]; then - SOURCE_NAME=mDNSResponder-1310.80.1 + SOURCE_NAME=mDNSResponder-1790.80.10 wget https://github.com/apple-oss-distributions/mDNSResponder/archive/refs/tags/$SOURCE_NAME.tar.gz \ && mkdir -p $SOURCE_NAME \ && tar xvf $SOURCE_NAME.tar.gz -C $SOURCE_NAME --strip-components=1 \ - && cd $SOURCE_NAME/Clients \ - && sed -i '/#include /a #include ' dns-sd.c \ - && sed -i '/#include /a #include ' dns-sd.c \ - && cd ../mDNSPosix \ - && make os=linux && sudo make install os=linux + && cd "$SOURCE_NAME" \ + && ( + for patch in "$MDNSRESPONDER_PATCH_PATH"/*.patch; do + patch -p1 <"$patch" + done + ) \ + && cd mDNSPosix \ + && make os=linux tls=no && sudo make install os=linux tls=no fi # Enable IPv6 diff --git a/tests/scripts/check-docker b/tests/scripts/check-docker index 60ae0f31..3387a52a 100755 --- a/tests/scripts/check-docker +++ b/tests/scripts/check-docker @@ -29,9 +29,6 @@ set -euxo pipefail -OT_POSIX_CONFIG_RCP_BUS=${OT_POSIX_CONFIG_RCP_BUS:-UART} -readonly OT_POSIX_CONFIG_RCP_BUS - on_exit() { local status=$? @@ -56,15 +53,12 @@ main() { sudo modprobe ip6table_filter docker build -t otbr \ - --build-arg OTBR_OPTIONS=-DOT_POSIX_CONFIG_RCP_BUS="${OT_POSIX_CONFIG_RCP_BUS}" \ + --build-arg OTBR_OPTIONS=-DOT_POSIX_RCP_SPI_BUS=ON \ --build-arg BACKBONE_ROUTER=0 \ -f etc/docker/Dockerfile . # SPI simulation is not available yet, so just verify the binary runs - if [[ ${OT_POSIX_CONFIG_RCP_BUS} == SPI ]]; then - docker run --rm -t --entrypoint otbr-agent otbr -h | grep 'spi://' - return 0 - fi + docker run --rm -t --entrypoint otbr-agent otbr -h | grep 'spi://' local -r SOCAT_OUTPUT=/tmp/ot-socat socat -d -d pty,raw,echo=0 pty,raw,echo=0 2>&1 | tee $SOCAT_OUTPUT & diff --git a/third_party/mDNSResponder/0001-Fix-Linux-build.patch b/third_party/mDNSResponder/0001-Fix-Linux-build.patch new file mode 100644 index 00000000..1dc01f3f --- /dev/null +++ b/third_party/mDNSResponder/0001-Fix-Linux-build.patch @@ -0,0 +1,32 @@ +From e136dcdcdd93ef32ada981e89c195905eb809eea Mon Sep 17 00:00:00 2001 +Message-ID: +From: Nate Karstens +Date: Thu, 23 Mar 2023 00:15:52 -0500 +Subject: [PATCH] Fix Linux build + +The __block qualifier is not used in Linux builds. + +Signed-off-by: Nate Karstens +--- + mDNSShared/uds_daemon.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/mDNSShared/uds_daemon.c b/mDNSShared/uds_daemon.c +index 9ae5f78..5a00bb5 100644 +--- a/mDNSShared/uds_daemon.c ++++ b/mDNSShared/uds_daemon.c +@@ -2912,7 +2912,11 @@ exit: + mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d) + { + browser_t *b, *p; ++#if defined(TARGET_OS_MAC) && TARGET_OS_MAC + __block mStatus err; ++#else ++ mStatus err; ++#endif + + for (p = info->u.browser.browsers; p; p = p->next) + { +-- +2.41.0 + diff --git a/third_party/mDNSResponder/0002-Create-subroutine-for-cleaning-recent-interfaces.patch b/third_party/mDNSResponder/0002-Create-subroutine-for-cleaning-recent-interfaces.patch new file mode 100644 index 00000000..98da74c5 --- /dev/null +++ b/third_party/mDNSResponder/0002-Create-subroutine-for-cleaning-recent-interfaces.patch @@ -0,0 +1,64 @@ +From 4f7970ac1615aba7a39ae94c1ca14135265574e9 Mon Sep 17 00:00:00 2001 +Message-ID: <4f7970ac1615aba7a39ae94c1ca14135265574e9.1687508149.git.stefan@agner.ch> +In-Reply-To: +References: +From: Nate Karstens +Date: Wed, 28 Jun 2017 17:30:00 -0500 +Subject: [PATCH] Create subroutine for cleaning recent interfaces + +Moves functionality for cleaning the list of recent +interfaces into its own subroutine. + +Upstream-Status: Submitted [dts@apple.com] + +Signed-off-by: Nate Karstens +Signed-off-by: Alex Kiernan +--- + mDNSPosix/mDNSPosix.c | 24 ++++++++++++++---------- + 1 file changed, 14 insertions(+), 10 deletions(-) + +diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c +index 0a7c3df..fe7242d 100644 +--- a/mDNSPosix/mDNSPosix.c ++++ b/mDNSPosix/mDNSPosix.c +@@ -1322,6 +1322,19 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf + return err; + } + ++// Clean up any interfaces that have been hanging around on the RecentInterfaces list for more than a minute ++mDNSlocal void CleanRecentInterfaces(void) ++{ ++ PosixNetworkInterface **ri = &gRecentInterfaces; ++ const mDNSs32 utc = mDNSPlatformUTC(); ++ while (*ri) ++ { ++ PosixNetworkInterface *pi = *ri; ++ if (utc - pi->LastSeen < 60) ri = (PosixNetworkInterface **)&pi->coreIntf.next; ++ else { *ri = (PosixNetworkInterface *)pi->coreIntf.next; mdns_free(pi); } ++ } ++} ++ + // Creates a PosixNetworkInterface for the interface whose IP address is + // intfAddr and whose name is intfName and registers it with mDNS core. + mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct sockaddr *intfMask, +@@ -1559,16 +1572,7 @@ mDNSlocal int SetupInterfaceList(mDNS *const m) + + // Clean up. + if (intfList != NULL) freeifaddrs(intfList); +- +- // Clean up any interfaces that have been hanging around on the RecentInterfaces list for more than a minute +- PosixNetworkInterface **ri = &gRecentInterfaces; +- const mDNSs32 utc = mDNSPlatformUTC(); +- while (*ri) +- { +- PosixNetworkInterface *pi = *ri; +- if (utc - pi->LastSeen < 60) ri = (PosixNetworkInterface **)&pi->coreIntf.next; +- else { *ri = (PosixNetworkInterface *)pi->coreIntf.next; mdns_free(pi); } +- } ++ CleanRecentInterfaces(); + + return err; + } +-- +2.41.0 + diff --git a/third_party/mDNSResponder/0003-Create-subroutine-for-tearing-down-an-interface.patch b/third_party/mDNSResponder/0003-Create-subroutine-for-tearing-down-an-interface.patch new file mode 100644 index 00000000..812bd20c --- /dev/null +++ b/third_party/mDNSResponder/0003-Create-subroutine-for-tearing-down-an-interface.patch @@ -0,0 +1,62 @@ +From f7ab91f739b936305ca56743adfb4673e3f2f4ba Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: +References: +From: Nate Karstens +Date: Wed, 28 Jun 2017 17:30:00 -0500 +Subject: [PATCH] Create subroutine for tearing down an interface + +Creates a subroutine for tearing down an interface. + +Upstream-Status: Submitted [dts@apple.com] + +Signed-off-by: Nate Karstens +Signed-off-by: Alex Kiernan +--- + mDNSPosix/mDNSPosix.c | 22 ++++++++++++++++------ + 1 file changed, 16 insertions(+), 6 deletions(-) + +diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c +index fe7242d..a32a880 100644 +--- a/mDNSPosix/mDNSPosix.c ++++ b/mDNSPosix/mDNSPosix.c +@@ -1043,6 +1043,19 @@ mDNSlocal void FreePosixNetworkInterface(PosixNetworkInterface *intf) + gRecentInterfaces = intf; + } + ++mDNSlocal void TearDownInterface(mDNS *const m, PosixNetworkInterface *intf) ++{ ++ mDNS_DeregisterInterface(m, &intf->coreIntf, NormalActivation); ++ if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName); ++ FreePosixNetworkInterface(intf); ++ ++ num_registered_interfaces--; ++ if (num_registered_interfaces == 0) { ++ num_pkts_accepted = 0; ++ num_pkts_rejected = 0; ++ } ++} ++ + // Grab the first interface, deregister it, free it, and repeat until done. + mDNSlocal void ClearInterfaceList(mDNS *const m) + { +@@ -1051,13 +1064,10 @@ mDNSlocal void ClearInterfaceList(mDNS *const m) + while (m->HostInterfaces) + { + PosixNetworkInterface *intf = (PosixNetworkInterface*)(m->HostInterfaces); +- mDNS_DeregisterInterface(m, &intf->coreIntf, NormalActivation); +- if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName); +- FreePosixNetworkInterface(intf); ++ TearDownInterface(m, intf); + } +- num_registered_interfaces = 0; +- num_pkts_accepted = 0; +- num_pkts_rejected = 0; ++ ++ assert(num_registered_interfaces == 0); + } + + mDNSlocal int SetupIPv6Socket(int fd) +-- +2.41.0 + diff --git a/third_party/mDNSResponder/0004-Track-interface-socket-family.patch b/third_party/mDNSResponder/0004-Track-interface-socket-family.patch new file mode 100644 index 00000000..48fbc741 --- /dev/null +++ b/third_party/mDNSResponder/0004-Track-interface-socket-family.patch @@ -0,0 +1,54 @@ +From 542c1b2ce1dcc069cf848d11978c8b6ae5982b6e Mon Sep 17 00:00:00 2001 +Message-ID: <542c1b2ce1dcc069cf848d11978c8b6ae5982b6e.1687508149.git.stefan@agner.ch> +In-Reply-To: +References: +From: Nate Karstens +Date: Wed, 28 Jun 2017 17:30:00 -0500 +Subject: [PATCH] Track interface socket family + +Tracks the socket family associated with the interface. + +Upstream-Status: Submitted [dts@apple.com] + +Signed-off-by: Nate Karstens +Signed-off-by: Alex Kiernan +--- + mDNSPosix/mDNSPosix.c | 1 + + mDNSPosix/mDNSPosix.h | 2 ++ + 2 files changed, 3 insertions(+) + +diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c +index a32a880..9a5b4d7 100644 +--- a/mDNSPosix/mDNSPosix.c ++++ b/mDNSPosix/mDNSPosix.c +@@ -1415,6 +1415,7 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct + // Set up the extra fields in PosixNetworkInterface. + assert(intf->intfName != NULL); // intf->intfName already set up above + intf->index = intfIndex; ++ intf->sa_family = intfAddr->sa_family; + intf->multicastSocket4 = -1; + #if HAVE_IPV6 + intf->multicastSocket6 = -1; +diff --git a/mDNSPosix/mDNSPosix.h b/mDNSPosix/mDNSPosix.h +index 9675591..dd7864c 100644 +--- a/mDNSPosix/mDNSPosix.h ++++ b/mDNSPosix/mDNSPosix.h +@@ -19,6 +19,7 @@ + #define __mDNSPlatformPosix_h + + #include ++#include + #include + + #ifdef __cplusplus +@@ -40,6 +41,7 @@ struct PosixNetworkInterface + char * intfName; + PosixNetworkInterface * aliasIntf; + int index; ++ sa_family_t sa_family; + int multicastSocket4; + #if HAVE_IPV6 + int multicastSocket6; +-- +2.41.0 + diff --git a/third_party/mDNSResponder/0005-Indicate-loopback-interface-to-mDNS-core.patch b/third_party/mDNSResponder/0005-Indicate-loopback-interface-to-mDNS-core.patch new file mode 100644 index 00000000..f7aa4617 --- /dev/null +++ b/third_party/mDNSResponder/0005-Indicate-loopback-interface-to-mDNS-core.patch @@ -0,0 +1,61 @@ +From 44385771ef63f081ed7e80eae6f24591046b4c7c Mon Sep 17 00:00:00 2001 +Message-ID: <44385771ef63f081ed7e80eae6f24591046b4c7c.1687508149.git.stefan@agner.ch> +In-Reply-To: +References: +From: Nate Karstens +Date: Tue, 1 Aug 2017 17:06:01 -0500 +Subject: [PATCH] Indicate loopback interface to mDNS core + +Tells the mDNS core if an interface is a loopback interface, +similar to AddInterfaceToList() in the MacOS implementation. + +Upstream-Status: Submitted [dts@apple.com] + +Signed-off-by: Nate Karstens +Signed-off-by: Alex Kiernan +--- + mDNSPosix/mDNSPosix.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c +index 9a5b4d7..02a19b4 100644 +--- a/mDNSPosix/mDNSPosix.c ++++ b/mDNSPosix/mDNSPosix.c +@@ -1348,7 +1348,7 @@ mDNSlocal void CleanRecentInterfaces(void) + // Creates a PosixNetworkInterface for the interface whose IP address is + // intfAddr and whose name is intfName and registers it with mDNS core. + mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct sockaddr *intfMask, +- const mDNSu8 *intfHaddr, mDNSu16 intfHlen, const char *intfName, int intfIndex) ++ const mDNSu8 *intfHaddr, mDNSu16 intfHlen, const char *intfName, int intfIndex, int intfFlags) + { + int err = 0; + PosixNetworkInterface *intf; +@@ -1411,6 +1411,7 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct + + intf->coreIntf.Advertise = m->AdvertiseLocalAddresses; + intf->coreIntf.McastTxRx = mDNStrue; ++ intf->coreIntf.Loopback = ((intfFlags & IFF_LOOPBACK) != 0) ? mDNStrue : mDNSfalse; + + // Set up the extra fields in PosixNetworkInterface. + assert(intf->intfName != NULL); // intf->intfName already set up above +@@ -1561,7 +1562,7 @@ mDNSlocal int SetupInterfaceList(mDNS *const m) + } + #endif + if (SetupOneInterface(m, i->ifa_addr, i->ifa_netmask, +- hwaddr, hwaddr_len, i->ifa_name, ifIndex) == 0) ++ hwaddr, hwaddr_len, i->ifa_name, ifIndex, i->ifa_flags) == 0) + { + if (i->ifa_addr->sa_family == AF_INET) + foundav4 = mDNStrue; +@@ -1578,7 +1579,7 @@ mDNSlocal int SetupInterfaceList(mDNS *const m) + // if ((m->HostInterfaces == NULL) && (firstLoopback != NULL)) + if (!foundav4 && firstLoopback) + (void) SetupOneInterface(m, firstLoopback->ifa_addr, firstLoopback->ifa_netmask, +- NULL, 0, firstLoopback->ifa_name, firstLoopbackIndex); ++ NULL, 0, firstLoopback->ifa_name, firstLoopbackIndex, firstLoopback->ifa_flags); + } + + // Clean up. +-- +2.41.0 + diff --git a/third_party/mDNSResponder/0006-Use-list-for-changed-interfaces.patch b/third_party/mDNSResponder/0006-Use-list-for-changed-interfaces.patch new file mode 100644 index 00000000..87ac1907 --- /dev/null +++ b/third_party/mDNSResponder/0006-Use-list-for-changed-interfaces.patch @@ -0,0 +1,178 @@ +From 2a0f873184068f21e1d0d2a3e0d8c26bc705bf88 Mon Sep 17 00:00:00 2001 +Message-ID: <2a0f873184068f21e1d0d2a3e0d8c26bc705bf88.1687508149.git.stefan@agner.ch> +In-Reply-To: +References: +From: Nate Karstens +Date: Thu, 13 Jul 2017 09:00:00 -0500 +Subject: [PATCH] Use list for changed interfaces + +Uses a linked list to store the index of changed network interfaces +instead of a bitfield. This allows for network interfaces with an +index greater than 31 (an index of 36 was seen on Android). + +Upstream-Status: Submitted [dts@apple.com] + +Signed-off-by: Nate Karstens +Signed-off-by: Alex Kiernan +Change-Id: Ibeab0ec68ca0d21da8384d4362e59afd2951f138 +--- + mDNSPosix/mDNSPosix.c | 60 +++++++++++++++++++++++++++++++------------ + 1 file changed, 44 insertions(+), 16 deletions(-) + +diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c +index 02a19b4..9867881 100644 +--- a/mDNSPosix/mDNSPosix.c ++++ b/mDNSPosix/mDNSPosix.c +@@ -74,6 +74,14 @@ struct IfChangeRec + }; + typedef struct IfChangeRec IfChangeRec; + ++// Used to build a list of network interface indices ++struct NetworkInterfaceIndex ++{ ++ int if_index; ++ struct NetworkInterfaceIndex *Next; ++}; ++typedef struct NetworkInterfaceIndex NetworkInterfaceIndex; ++ + // Note that static data is initialized to zero in (modern) C. + static PosixEventSource *gEventSources; // linked list of PosixEventSource's + static sigset_t gEventSignalSet; // Signals which event loop listens for +@@ -1621,6 +1629,23 @@ mDNSlocal mStatus OpenIfNotifySocket(int *pFD) + return err; + } + ++mDNSlocal void AddInterfaceIndexToList(GenLinkedList *list, int if_index) ++{ ++ NetworkInterfaceIndex *item; ++ ++ for (item = (NetworkInterfaceIndex*)list->Head; item != NULL; item = item->Next) ++ { ++ if (if_index == item->if_index) return; ++ } ++ ++ item = mdns_malloc(sizeof *item); ++ if (item == NULL) return; ++ ++ item->if_index = if_index; ++ item->Next = NULL; ++ AddToTail(list, item); ++} ++ + #if MDNS_DEBUGMSGS + mDNSlocal void PrintNetLinkMsg(const struct nlmsghdr *pNLMsg) + { +@@ -1648,14 +1673,13 @@ mDNSlocal void PrintNetLinkMsg(const struct nlmsghdr *pNLMsg) + } + #endif + +-mDNSlocal mDNSu32 ProcessRoutingNotification(int sd) ++mDNSlocal void ProcessRoutingNotification(int sd, GenLinkedList *changedInterfaces) + // Read through the messages on sd and if any indicate that any interface records should + // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0. + { + ssize_t readCount; + char buff[4096]; + struct nlmsghdr *pNLMsg = (struct nlmsghdr*) buff; +- mDNSu32 result = 0; + + // The structure here is more complex than it really ought to be because, + // unfortunately, there's no good way to size a buffer in advance large +@@ -1691,9 +1715,9 @@ mDNSlocal mDNSu32 ProcessRoutingNotification(int sd) + + // Process the NetLink message + if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK) +- result |= 1 << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index; ++ AddInterfaceIndexToList(changedInterfaces, ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index); + else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR) +- result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index; ++ AddInterfaceIndexToList(changedInterfaces, ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index); + + // Advance pNLMsg to the next message in the buffer + if ((pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE) +@@ -1704,8 +1728,6 @@ mDNSlocal mDNSu32 ProcessRoutingNotification(int sd) + else + break; // all done! + } +- +- return result; + } + + #else // USES_NETLINK +@@ -1737,18 +1759,17 @@ mDNSlocal void PrintRoutingSocketMsg(const struct ifa_msghdr *pRSMsg) + } + #endif + +-mDNSlocal mDNSu32 ProcessRoutingNotification(int sd) ++mDNSlocal void ProcessRoutingNotification(int sd, GenLinkedList *changedInterfaces) + // Read through the messages on sd and if any indicate that any interface records should + // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0. + { + ssize_t readCount; + char buff[4096]; + struct ifa_msghdr *pRSMsg = (struct ifa_msghdr*) buff; +- mDNSu32 result = 0; + + readCount = read(sd, buff, sizeof buff); + if (readCount < (ssize_t) sizeof(struct ifa_msghdr)) +- return mStatus_UnsupportedErr; // cannot decipher message ++ return; // cannot decipher message + + #if MDNS_DEBUGMSGS + PrintRoutingSocketMsg(pRSMsg); +@@ -1759,12 +1780,10 @@ mDNSlocal mDNSu32 ProcessRoutingNotification(int sd) + pRSMsg->ifam_type == RTM_IFINFO) + { + if (pRSMsg->ifam_type == RTM_IFINFO) +- result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index; ++ AddInterfaceIndexToList(changedInterfaces, ((struct if_msghdr*) pRSMsg)->ifm_index); + else +- result |= 1 << pRSMsg->ifam_index; ++ AddInterfaceIndexToList(changedInterfaces, pRSMsg->ifam_index); + } +- +- return result; + } + + #endif // USES_NETLINK +@@ -1774,7 +1793,8 @@ mDNSlocal void InterfaceChangeCallback(int fd, void *context) + { + IfChangeRec *pChgRec = (IfChangeRec*) context; + fd_set readFDs; +- mDNSu32 changedInterfaces = 0; ++ GenLinkedList changedInterfaces; ++ NetworkInterfaceIndex *changedInterface; + struct timeval zeroTimeout = { 0, 0 }; + + (void)fd; // Unused +@@ -1782,17 +1802,25 @@ mDNSlocal void InterfaceChangeCallback(int fd, void *context) + FD_ZERO(&readFDs); + FD_SET(pChgRec->NotifySD, &readFDs); + ++ InitLinkedList(&changedInterfaces, offsetof(NetworkInterfaceIndex, Next)); ++ + do + { +- changedInterfaces |= ProcessRoutingNotification(pChgRec->NotifySD); ++ ProcessRoutingNotification(pChgRec->NotifySD, &changedInterfaces); + } + while (0 < select(pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout)); + + // Currently we rebuild the entire interface list whenever any interface change is + // detected. If this ever proves to be a performance issue in a multi-homed + // configuration, more care should be paid to changedInterfaces. +- if (changedInterfaces) ++ if (changedInterfaces.Head != NULL) + mDNSPlatformPosixRefreshInterfaceList(pChgRec->mDNS); ++ ++ while ((changedInterface = (NetworkInterfaceIndex*)changedInterfaces.Head) != NULL) ++ { ++ RemoveFromList(&changedInterfaces, changedInterface); ++ mdns_free(changedInterface); ++ } + } + + // Register with either a Routing Socket or RtNetLink to listen for interface changes. +-- +2.41.0 + diff --git a/third_party/mDNSResponder/0007-Handle-noisy-netlink-sockets.patch b/third_party/mDNSResponder/0007-Handle-noisy-netlink-sockets.patch new file mode 100644 index 00000000..08cce016 --- /dev/null +++ b/third_party/mDNSResponder/0007-Handle-noisy-netlink-sockets.patch @@ -0,0 +1,255 @@ +From 00289e89cccb9567d6ea6bd2a394fd14b61e5ad1 Mon Sep 17 00:00:00 2001 +Message-ID: <00289e89cccb9567d6ea6bd2a394fd14b61e5ad1.1687508149.git.stefan@agner.ch> +In-Reply-To: +References: +From: Nate Karstens +Date: Mon, 24 Jul 2017 09:38:55 -0500 +Subject: [PATCH] Handle noisy netlink sockets + +The POSIX implementation currently clears all network interfaces +when netlink indicates that there has been a change. This causes +the following problems: + + 1) Applications are informed that all of the services they are + tracking have been removed. + 2) Increases network load because the client must re-query for + all records it is interested in. + +This changes netlink notification handling by: + + 1) Always comparing with the latest interface list returned + by the OS. + 2) Confirming that the interface has been changed in a way + that we care about. + +Upstream-Status: Submitted [dts@apple.com] + +Signed-off-by: Nate Karstens +Signed-off-by: Alex Kiernan +--- + mDNSPosix/mDNSPosix.c | 182 +++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 172 insertions(+), 10 deletions(-) + +diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c +index 9867881..ad7000d 100644 +--- a/mDNSPosix/mDNSPosix.c ++++ b/mDNSPosix/mDNSPosix.c +@@ -1788,14 +1788,43 @@ mDNSlocal void ProcessRoutingNotification(int sd, GenLinkedList *change + + #endif // USES_NETLINK + ++// Test whether the given PosixNetworkInterface matches the given struct ifaddrs ++mDNSlocal mDNSBool InterfacesMatch(PosixNetworkInterface *intf, struct ifaddrs *ifi) ++{ ++ mDNSBool match = mDNSfalse; ++ mDNSAddr ip, mask; ++ int if_index; ++ ++ if_index = if_nametoindex(ifi->ifa_name); ++ if (if_index == 0) ++ return mDNSfalse; ++ ++ if((intf->index == if_index) && ++ (intf->sa_family == ifi->ifa_addr->sa_family) && ++ (strcmp(intf->coreIntf.ifname, ifi->ifa_name) == 0)) ++ { ++ SockAddrTomDNSAddr(ifi->ifa_addr, &ip, NULL); ++ SockAddrTomDNSAddr(ifi->ifa_netmask, &mask, NULL); ++ ++ match = mDNSSameAddress(&intf->coreIntf.ip, &ip) && ++ mDNSSameAddress(&intf->coreIntf.mask, &mask); ++ } ++ ++ return match; ++} ++ + // Called when data appears on interface change notification socket + mDNSlocal void InterfaceChangeCallback(int fd, void *context) + { + IfChangeRec *pChgRec = (IfChangeRec*) context; ++ mDNS *m = pChgRec->mDNS; + fd_set readFDs; + GenLinkedList changedInterfaces; + NetworkInterfaceIndex *changedInterface; + struct timeval zeroTimeout = { 0, 0 }; ++ struct ifaddrs *ifa_list, **ifi, *ifa_loop4 = NULL; ++ PosixNetworkInterface *intf, *intfNext; ++ mDNSBool found, foundav4; + + (void)fd; // Unused + +@@ -1810,12 +1839,149 @@ mDNSlocal void InterfaceChangeCallback(int fd, void *context) + } + while (0 < select(pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout)); + +- // Currently we rebuild the entire interface list whenever any interface change is +- // detected. If this ever proves to be a performance issue in a multi-homed +- // configuration, more care should be paid to changedInterfaces. +- if (changedInterfaces.Head != NULL) +- mDNSPlatformPosixRefreshInterfaceList(pChgRec->mDNS); ++ CleanRecentInterfaces(); ++ ++ if (changedInterfaces.Head == NULL) goto cleanup; ++ ++ if (getifaddrs(&ifa_list) < 0) goto cleanup; ++ ++ for (intf = (PosixNetworkInterface*)(m->HostInterfaces); intf != NULL; intf = intfNext) ++ { ++ intfNext = (PosixNetworkInterface*)(intf->coreIntf.next); ++ ++ // Loopback interface(s) are handled later ++ if (intf->coreIntf.Loopback) continue; ++ ++ found = mDNSfalse; ++ for (ifi = &ifa_list; *ifi != NULL; ifi = &(*ifi)->ifa_next) ++ { ++ if (InterfacesMatch(intf, *ifi)) ++ { ++ found = mDNStrue; ++ break; ++ } ++ } ++ ++ // Removes changed and old interfaces from m->HostInterfaces ++ if (!found) TearDownInterface(m, intf); ++ } ++ ++ // Add new and changed interfaces in ifa_list ++ // Save off loopback interface in case it is needed later ++ for (ifi = &ifa_list; *ifi != NULL; ifi = &(*ifi)->ifa_next) ++ { ++ found = mDNSfalse; ++ for (intf = (PosixNetworkInterface*)(m->HostInterfaces); intf != NULL; intf = intfNext) ++ { ++ intfNext = (PosixNetworkInterface*)(intf->coreIntf.next); ++ ++ // Loopback interface(s) are handled later ++ if (intf->coreIntf.Loopback) continue; ++ ++ if (InterfacesMatch(intf, *ifi)) ++ { ++ found = mDNStrue; ++ break; ++ } ++ ++ // Removes changed and old interfaces from m->HostInterfaces ++ } ++ if (found) ++ continue; ++ ++ if ((ifa_loop4 == NULL) && ++ ((*ifi)->ifa_addr->sa_family == AF_INET) && ++ ((*ifi)->ifa_flags & IFF_UP) && ++ ((*ifi)->ifa_flags & IFF_LOOPBACK)) ++ { ++ ifa_loop4 = *ifi; ++ continue; ++ } ++ ++ if ( (((*ifi)->ifa_addr->sa_family == AF_INET) ++#if HAVE_IPV6 ++ || ((*ifi)->ifa_addr->sa_family == AF_INET6) ++#endif ++ ) && ((*ifi)->ifa_flags & IFF_UP) ++ && !((*ifi)->ifa_flags & IFF_POINTOPOINT) ++ && !((*ifi)->ifa_flags & IFF_LOOPBACK)) ++ { ++ struct ifaddrs *i = *ifi; ++ ++#define ethernet_addr_len 6 ++ uint8_t hwaddr[ethernet_addr_len]; ++ int hwaddr_len = 0; ++ ++#if defined(TARGET_OS_LINUX) && TARGET_OS_LINUX ++ struct ifreq ifr; ++ int sockfd = socket(AF_INET6, SOCK_DGRAM, 0); ++ if (sockfd >= 0) ++ { ++ /* Add hardware address */ ++ memcpy(ifr.ifr_name, i->ifa_name, IFNAMSIZ); ++ if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) != -1) ++ { ++ if (ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER) ++ { ++ memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ethernet_addr_len); ++ hwaddr_len = ethernet_addr_len; ++ } ++ } ++ close(sockfd); ++ } ++ else ++ { ++ memset(hwaddr, 0, sizeof(hwaddr)); ++ } ++#endif // TARGET_OS_LINUX ++ SetupOneInterface(m, i->ifa_addr, i->ifa_netmask, ++ hwaddr, hwaddr_len, i->ifa_name, if_nametoindex(i->ifa_name), i->ifa_flags); ++ } ++ } ++ ++ // Determine if there is at least one non-loopback IPv4 interface. This is to work around issues ++ // with multicast loopback on IPv6 interfaces -- see corresponding logic in SetupInterfaceList(). ++ foundav4 = mDNSfalse; ++ for (intf = (PosixNetworkInterface*)(m->HostInterfaces); intf != NULL; intf = (PosixNetworkInterface*)(intf->coreIntf.next)) ++ { ++ if (intf->sa_family == AF_INET && !intf->coreIntf.Loopback) ++ { ++ foundav4 = mDNStrue; ++ break; ++ } ++ } ++ ++ if (foundav4) ++ { ++ for (intf = (PosixNetworkInterface*)(m->HostInterfaces); intf != NULL; intf = intfNext) ++ { ++ intfNext = (PosixNetworkInterface*)(intf->coreIntf.next); ++ if (intf->coreIntf.Loopback) TearDownInterface(m, intf); ++ } ++ } ++ else ++ { ++ found = mDNSfalse; ++ ++ for (intf = (PosixNetworkInterface*)(m->HostInterfaces); intf != NULL; intf = (PosixNetworkInterface*)(intf->coreIntf.next)) ++ { ++ if (intf->coreIntf.Loopback) ++ { ++ found = mDNStrue; ++ break; ++ } ++ } ++ ++ if (!found && (ifa_loop4 != NULL)) ++ { ++ SetupOneInterface(m, ifa_loop4->ifa_addr, ifa_loop4->ifa_netmask, ++ NULL, 0, ifa_loop4->ifa_name, if_nametoindex(ifa_loop4->ifa_name), ifa_loop4->ifa_flags); ++ } ++ } ++ ++ if (ifa_list != NULL) freeifaddrs(ifa_list); + ++cleanup: + while ((changedInterface = (NetworkInterfaceIndex*)changedInterfaces.Head) != NULL) + { + RemoveFromList(&changedInterfaces, changedInterface); +@@ -1947,15 +2113,11 @@ mDNSexport void mDNSPlatformClose(mDNS *const m) + #endif + } + +-// This is used internally by InterfaceChangeCallback. +-// It's also exported so that the Standalone Responder (mDNSResponderPosix) ++// This is exported so that the Standalone Responder (mDNSResponderPosix) + // can call it in response to a SIGHUP (mainly for debugging purposes). + mDNSexport mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m) + { + int err; +- // This is a pretty heavyweight way to process interface changes -- +- // destroying the entire interface list and then making fresh one from scratch. +- // We should make it like the OS X version, which leaves unchanged interfaces alone. + ClearInterfaceList(m); + err = SetupInterfaceList(m); + return PosixErrorToStatus(err); +-- +2.41.0 + diff --git a/third_party/mDNSResponder/0008-Mark-deleted-interfaces-as-being-changed.patch b/third_party/mDNSResponder/0008-Mark-deleted-interfaces-as-being-changed.patch new file mode 100644 index 00000000..216fde7f --- /dev/null +++ b/third_party/mDNSResponder/0008-Mark-deleted-interfaces-as-being-changed.patch @@ -0,0 +1,43 @@ +From 8ebfeaf55ab364a1e51a3438dfa9a742a01b8d36 Mon Sep 17 00:00:00 2001 +Message-ID: <8ebfeaf55ab364a1e51a3438dfa9a742a01b8d36.1687508149.git.stefan@agner.ch> +In-Reply-To: +References: +From: Nate Karstens +Date: Wed, 9 Aug 2017 09:16:58 -0500 +Subject: [PATCH] Mark deleted interfaces as being changed + +Netlink notification handling ignores messages for deleted links, +RTM_DELLINK. It does handle RTM_GETLINK. According to libnl docu- +mentation (http://www.infradead.org/~tgr/libnl/doc/route.html) +RTM_DELLINK can be sent by the kernel, but RTM_GETLINK cannot. +There was likely a mixup in the original implementation, so this +change replaces handling for RTM_GETLINK with RTM_DELLINK. + +Testing and Verification Instructions: + 1. Use ip-link to add and remove a VLAN interface and verify + that mDNSResponder handles the deleted link. + +Upstream-Status: Submitted [dts@apple.com] + +Signed-off-by: Nate Karstens +Signed-off-by: Alex Kiernan +--- + mDNSPosix/mDNSPosix.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c +index ad7000d..010f266 100644 +--- a/mDNSPosix/mDNSPosix.c ++++ b/mDNSPosix/mDNSPosix.c +@@ -1714,7 +1714,7 @@ mDNSlocal void ProcessRoutingNotification(int sd, GenLinkedList *change + #endif + + // Process the NetLink message +- if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK) ++ if (pNLMsg->nlmsg_type == RTM_DELLINK || pNLMsg->nlmsg_type == RTM_NEWLINK) + AddInterfaceIndexToList(changedInterfaces, ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index); + else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR) + AddInterfaceIndexToList(changedInterfaces, ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index); +-- +2.41.0 + diff --git a/third_party/mDNSResponder/0009-Handle-errors-from-socket-calls.patch b/third_party/mDNSResponder/0009-Handle-errors-from-socket-calls.patch new file mode 100644 index 00000000..2057e2cb --- /dev/null +++ b/third_party/mDNSResponder/0009-Handle-errors-from-socket-calls.patch @@ -0,0 +1,66 @@ +From dae89c4e97faf408394961c0f4b1577a7d5976cc Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: +References: +From: Nate Karstens +Date: Thu, 10 Aug 2017 08:27:32 -0500 +Subject: [PATCH] Handle errors from socket calls + +Adds handling for socket() or read() returning a +negative value (indicating an error has occurred). + +Upstream-Status: Submitted [dts@apple.com] + +Signed-off-by: Nate Karstens +Signed-off-by: Alex Kiernan +--- + mDNSPosix/mDNSPosix.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c +index 010f266..89e108f 100644 +--- a/mDNSPosix/mDNSPosix.c ++++ b/mDNSPosix/mDNSPosix.c +@@ -1677,7 +1677,7 @@ mDNSlocal void ProcessRoutingNotification(int sd, GenLinkedList *change + // Read through the messages on sd and if any indicate that any interface records should + // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0. + { +- ssize_t readCount; ++ ssize_t readVal, readCount; + char buff[4096]; + struct nlmsghdr *pNLMsg = (struct nlmsghdr*) buff; + +@@ -1686,7 +1686,10 @@ mDNSlocal void ProcessRoutingNotification(int sd, GenLinkedList *change + // enough to hold all pending data and so avoid message fragmentation. + // (Note that FIONREAD is not supported on AF_NETLINK.) + +- readCount = read(sd, buff, sizeof buff); ++ readVal = read(sd, buff, sizeof buff); ++ if (readVal < 0) return; ++ readCount = readVal; ++ + while (1) + { + // Make sure we've got an entire nlmsghdr in the buffer, and payload, too. +@@ -1702,7 +1705,9 @@ mDNSlocal void ProcessRoutingNotification(int sd, GenLinkedList *change + pNLMsg = (struct nlmsghdr*) buff; + + // read more data +- readCount += read(sd, buff + readCount, sizeof buff - readCount); ++ readVal = read(sd, buff + readCount, sizeof buff - readCount); ++ if (readVal < 0) return; ++ readCount += readVal; + continue; // spin around and revalidate with new readCount + } + else +@@ -2017,6 +2022,7 @@ mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void) + int err; + int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + struct sockaddr_in s5353; ++ if (s < 0) return mDNSfalse; + s5353.sin_family = AF_INET; + s5353.sin_port = MulticastDNSPort.NotAnInteger; + s5353.sin_addr.s_addr = 0; +-- +2.41.0 + diff --git a/third_party/mDNSResponder/0010-Handle-interface-without-ifa_addr.patch b/third_party/mDNSResponder/0010-Handle-interface-without-ifa_addr.patch new file mode 100644 index 00000000..602b205e --- /dev/null +++ b/third_party/mDNSResponder/0010-Handle-interface-without-ifa_addr.patch @@ -0,0 +1,41 @@ +From e501d58e9ec6cb6e19a682d425fa638069585fbc Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: +References: +From: Stefan Agner +Date: Fri, 23 Jun 2023 10:10:00 +0200 +Subject: [PATCH] Handle interface without `ifa_addr` + +It seems that certain interface types may have `ifa_addr` set to null. +Handle this case gracefully. + +Signed-off-by: Stefan Agner +--- + mDNSPosix/mDNSPosix.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c +index 89e108f..2056871 100644 +--- a/mDNSPosix/mDNSPosix.c ++++ b/mDNSPosix/mDNSPosix.c +@@ -1895,6 +1895,7 @@ mDNSlocal void InterfaceChangeCallback(int fd, void *context) + continue; + + if ((ifa_loop4 == NULL) && ++ ((*ifi)->ifa_addr != NULL) && + ((*ifi)->ifa_addr->sa_family == AF_INET) && + ((*ifi)->ifa_flags & IFF_UP) && + ((*ifi)->ifa_flags & IFF_LOOPBACK)) +@@ -1903,7 +1904,8 @@ mDNSlocal void InterfaceChangeCallback(int fd, void *context) + continue; + } + +- if ( (((*ifi)->ifa_addr->sa_family == AF_INET) ++ if ( ((*ifi)->ifa_addr != NULL) && ++ (((*ifi)->ifa_addr->sa_family == AF_INET) + #if HAVE_IPV6 + || ((*ifi)->ifa_addr->sa_family == AF_INET6) + #endif +-- +2.41.0 + diff --git a/third_party/openthread/repo/.clang-tidy b/third_party/openthread/repo/.clang-tidy new file mode 100644 index 00000000..61af657f --- /dev/null +++ b/third_party/openthread/repo/.clang-tidy @@ -0,0 +1,23 @@ +--- +Checks: > + -*, + bugprone-argument-comment, + bugprone-too-small-loop-variable, + google-explicit-constructor, + google-readability-casting, + misc-unused-using-decls, + modernize-loop-convert, + modernize-use-bool-literals, + modernize-use-equals-default, + modernize-use-equals-delete, + modernize-use-nullptr, + readability-avoid-const-params-in-decls, + readability-else-after-return, + readability-inconsistent-declaration-parameter-name, + readability-make-member-function-const, + readability-redundant-control-flow, + readability-redundant-member-init, + readability-simplify-boolean-expr, + readability-static-accessed-through-instance +WarningsAsErrors: '*' +HeaderFilterRegex: '(examples|include|src).*(?> $GITHUB_OUTPUT - name: Set up Docker Buildx - uses: docker/setup-buildx-action@4b4e9c3e2d4531116a6f8ba8e71fc6e2cb6e6c8c # v2.5.0 + uses: docker/setup-buildx-action@4c0219f9ac95b02789c1075625400b2acbff50b1 # v2.9.1 - name: Docker Buildx (build) run: | @@ -91,7 +91,7 @@ jobs: - name: Login to DockerHub if: success() && github.repository == 'openthread/openthread' && github.event_name != 'pull_request' - uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # v2.1.0 + uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2.2.0 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} diff --git a/third_party/openthread/repo/.github/workflows/fuzz.yml b/third_party/openthread/repo/.github/workflows/fuzz.yml index e1b37fe6..802ab26e 100644 --- a/third_party/openthread/repo/.github/workflows/fuzz.yml +++ b/third_party/openthread/repo/.github/workflows/fuzz.yml @@ -45,7 +45,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/third_party/openthread/repo/.github/workflows/makefile-check.yml b/third_party/openthread/repo/.github/workflows/makefile-check.yml index 8474a8c4..6daf99dc 100644 --- a/third_party/openthread/repo/.github/workflows/makefile-check.yml +++ b/third_party/openthread/repo/.github/workflows/makefile-check.yml @@ -48,11 +48,11 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Check diff --git a/third_party/openthread/repo/.github/workflows/otbr.yml b/third_party/openthread/repo/.github/workflows/otbr.yml index 1a808f3b..2b3e588b 100644 --- a/third_party/openthread/repo/.github/workflows/otbr.yml +++ b/third_party/openthread/repo/.github/workflows/otbr.yml @@ -62,7 +62,7 @@ jobs: # of OMR prefix and Domain prefix is not deterministic. BORDER_ROUTING: 0 steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Build OTBR Docker @@ -156,6 +156,13 @@ jobs: packet_verification: 2 nat64: 0 description: "" + - otbr_mdns: "avahi" + otbr_trel: 0 + cert_scripts: ./tests/scripts/thread-cert/border_router/*.py + packet_verification: 1 + nat64: 0 + use_core_firewall: 1 + description: "core firewall" name: BR ${{ matrix.description }} (${{ matrix.otbr_mdns }}, TREL=${{matrix.otbr_trel}}) env: REFERENCE_DEVICE: 1 @@ -172,7 +179,11 @@ jobs: NAT64: ${{ matrix.nat64 }} MAX_JOBS: 3 steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Set firewall environment variables + if: ${{ matrix.use_core_firewall }} + run: | + echo "FIREWALL=0" >> $GITHUB_ENV - name: Build OTBR Docker env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" @@ -223,7 +234,7 @@ jobs: - thread-border-router runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap diff --git a/third_party/openthread/repo/.github/workflows/otci.yml b/third_party/openthread/repo/.github/workflows/otci.yml index 77642b1f..72d8b4f9 100644 --- a/third_party/openthread/repo/.github/workflows/otci.yml +++ b/third_party/openthread/repo/.github/workflows/otci.yml @@ -57,11 +57,11 @@ jobs: REAL_DEVICE: 0 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Bootstrap run: | sudo rm /etc/apt/sources.list.d/* && sudo apt-get update diff --git a/third_party/openthread/repo/.github/workflows/otns.yml b/third_party/openthread/repo/.github/workflows/otns.yml index 252f601e..63079f4b 100644 --- a/third_party/openthread/repo/.github/workflows/otns.yml +++ b/third_party/openthread/repo/.github/workflows/otns.yml @@ -58,16 +58,16 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: go-version: "1.20" - name: Set up Python - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: "3.9" - name: Bootstrap @@ -101,12 +101,12 @@ jobs: name: Examples runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: go-version: "1.20" - name: Set up Python - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: "3.9" - name: Bootstrap @@ -159,16 +159,16 @@ jobs: STRESS_LEVEL: ${{ matrix.stress_level }} steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: go-version: "1.20" - name: Set up Python - uses: actions/setup-python@bd6b4b6205c4dbad673328db7b31b7fab9e241c0 # v4.6.1 + uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 # v4.7.0 with: python-version: "3.9" - name: Bootstrap @@ -206,11 +206,11 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Bootstrap run: | sudo apt-get --no-install-recommends install -y lcov diff --git a/third_party/openthread/repo/.github/workflows/posix.yml b/third_party/openthread/repo/.github/workflows/posix.yml index f260f039..d72c293d 100644 --- a/third_party/openthread/repo/.github/workflows/posix.yml +++ b/third_party/openthread/repo/.github/workflows/posix.yml @@ -52,11 +52,11 @@ jobs: CXXFLAGS: -DCLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER=1 -DOPENTHREAD_CONFIG_MLE_MAX_CHILDREN=15 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Bootstrap run: | sudo apt-get --no-install-recommends install -y expect ninja-build lcov socat @@ -135,11 +135,11 @@ jobs: VIRTUAL_TIME: 1 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -179,11 +179,11 @@ jobs: OT_READLINE: 'readline' steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Bootstrap run: | sudo rm /etc/apt/sources.list.d/* && sudo apt-get update @@ -228,11 +228,11 @@ jobs: OT_READLINE: 'off' steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Bootstrap run: | rm -f /usr/local/bin/2to3 @@ -258,11 +258,11 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Bootstrap env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" @@ -291,11 +291,11 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -318,7 +318,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/third_party/openthread/repo/.github/workflows/scorecards.yml b/third_party/openthread/repo/.github/workflows/scorecards.yml index 80d49886..8239e9dd 100644 --- a/third_party/openthread/repo/.github/workflows/scorecards.yml +++ b/third_party/openthread/repo/.github/workflows/scorecards.yml @@ -60,7 +60,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false @@ -95,6 +95,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@46ed16ded91731b2df79a2893d3aea8e9f03b5c4 # v2.1.27 + uses: github/codeql-action/upload-sarif@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.1.27 with: sarif_file: results.sarif diff --git a/third_party/openthread/repo/.github/workflows/simulation-1.1.yml b/third_party/openthread/repo/.github/workflows/simulation-1.1.yml index 9adebe4e..765df64b 100644 --- a/third_party/openthread/repo/.github/workflows/simulation-1.1.yml +++ b/third_party/openthread/repo/.github/workflows/simulation-1.1.yml @@ -55,11 +55,11 @@ jobs: MULTIPLY: 3 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -103,11 +103,11 @@ jobs: VIRTUAL_TIME: 1 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -153,11 +153,11 @@ jobs: MESSAGE_USE_HEAP: ${{ matrix.message_use_heap }} steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -196,11 +196,11 @@ jobs: VIRTUAL_TIME: 1 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -235,11 +235,11 @@ jobs: THREAD_VERSION: 1.1 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Bootstrap run: | sudo apt-get --no-install-recommends install -y expect ninja-build lcov socat @@ -274,11 +274,11 @@ jobs: THREAD_VERSION: 1.1 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -325,11 +325,11 @@ jobs: CXXFLAGS: "-DOPENTHREAD_CONFIG_LOG_PREPEND_UPTIME=0" steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -367,11 +367,11 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -394,7 +394,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/third_party/openthread/repo/.github/workflows/simulation-1.2.yml b/third_party/openthread/repo/.github/workflows/simulation-1.2.yml index 25d28c8c..45b8bd83 100644 --- a/third_party/openthread/repo/.github/workflows/simulation-1.2.yml +++ b/third_party/openthread/repo/.github/workflows/simulation-1.2.yml @@ -66,11 +66,11 @@ jobs: arch: ["m32", "m64"] steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -127,11 +127,11 @@ jobs: INTER_OP_BBR: 0 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -191,11 +191,11 @@ jobs: MULTIPLY: 3 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -235,11 +235,11 @@ jobs: VIRTUAL_TIME: 0 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -283,11 +283,11 @@ jobs: INTER_OP: 1 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -343,11 +343,11 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -370,7 +370,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/third_party/openthread/repo/.github/workflows/size.yml b/third_party/openthread/repo/.github/workflows/size.yml index de97e010..6eeb3ab2 100644 --- a/third_party/openthread/repo/.github/workflows/size.yml +++ b/third_party/openthread/repo/.github/workflows/size.yml @@ -49,16 +49,11 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - - name: Bootstrap - if: "github.event_name == 'push'" - run: | - python3 -m pip install --upgrade setuptools wheel - python3 -m pip install git+https://github.com/axiros/terminal_markdown_viewer.git + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Run env: OT_BASE_BRANCH: "${{ github.base_ref }}" @@ -72,3 +67,4 @@ jobs: export OT_SIZE_REPORTER=./size-report fi ./script/check-size + cat /tmp/ot-size-report/report_pr >> $GITHUB_STEP_SUMMARY diff --git a/third_party/openthread/repo/.github/workflows/toranj.yml b/third_party/openthread/repo/.github/workflows/toranj.yml index efa9aff4..960d52ac 100644 --- a/third_party/openthread/repo/.github/workflows/toranj.yml +++ b/third_party/openthread/repo/.github/workflows/toranj.yml @@ -59,11 +59,11 @@ jobs: TORANJ_EVENT_NAME: ${{ github.event_name }} steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -90,11 +90,11 @@ jobs: TORANJ_CLI: 1 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -122,11 +122,11 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -156,11 +156,11 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -183,7 +183,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/third_party/openthread/repo/.github/workflows/unit.yml b/third_party/openthread/repo/.github/workflows/unit.yml index 37d83959..d993e074 100644 --- a/third_party/openthread/repo/.github/workflows/unit.yml +++ b/third_party/openthread/repo/.github/workflows/unit.yml @@ -49,11 +49,11 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Build @@ -67,11 +67,11 @@ jobs: COVERAGE: 1 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -104,11 +104,11 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Bootstrap @@ -131,7 +131,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/third_party/openthread/repo/.github/workflows/version.yml b/third_party/openthread/repo/.github/workflows/version.yml index 10a30dfe..e7024abb 100644 --- a/third_party/openthread/repo/.github/workflows/version.yml +++ b/third_party/openthread/repo/.github/workflows/version.yml @@ -45,11 +45,11 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Harden Runner - uses: step-security/harden-runner@6b3083af2869dc3314a0257a42f4af696cc79ba3 # v2.3.1 + uses: step-security/harden-runner@1b05615854632b887b69ae1be8cbefe72d3ae423 # v2.6.0 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true - name: Check diff --git a/third_party/openthread/repo/CMakeLists.txt b/third_party/openthread/repo/CMakeLists.txt index c966aa75..e8959834 100644 --- a/third_party/openthread/repo/CMakeLists.txt +++ b/third_party/openthread/repo/CMakeLists.txt @@ -106,72 +106,11 @@ if(OT_PACKAGE_VERSION STREQUAL "") endif() message(STATUS "Package Version: ${OT_PACKAGE_VERSION}") -set(OT_THREAD_VERSION "1.3" CACHE STRING "Thread version chosen by the user at configure time") -set_property(CACHE OT_THREAD_VERSION PROPERTY STRINGS "1.1" "1.2" "1.3" "1.3.1") -if(${OT_THREAD_VERSION} STREQUAL "1.1") - target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_THREAD_VERSION=OT_THREAD_VERSION_1_1") - message(STATUS "Thread Version: 1.1 (OPENTHREAD_CONFIG_THREAD_VERSION=OT_THREAD_VERSION_1_1)") -elseif(${OT_THREAD_VERSION} STREQUAL "1.2") - target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_THREAD_VERSION=OT_THREAD_VERSION_1_2") - message(STATUS "Thread Version: 1.2 (OPENTHREAD_CONFIG_THREAD_VERSION=OT_THREAD_VERSION_1_2)") -elseif(${OT_THREAD_VERSION} STREQUAL "1.3") - target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_THREAD_VERSION=OT_THREAD_VERSION_1_3") - message(STATUS "Thread Version: 1.3 (OPENTHREAD_CONFIG_THREAD_VERSION=OT_THREAD_VERSION_1_3)") -elseif(${OT_THREAD_VERSION} STREQUAL "1.3.1") - target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_THREAD_VERSION=OT_THREAD_VERSION_1_3_1") - message(STATUS "Thread Version: 1.3.1 (OPENTHREAD_CONFIG_THREAD_VERSION=OT_THREAD_VERSION_1_3_1)") -else() - message(FATAL_ERROR "Thread version unknown: ${OT_THREAD_VERSION}") -endif() - -set(OT_PLATFORM "NO" CACHE STRING "Target platform chosen by the user at configure time") -ot_get_platforms(OT_PLATFORMS) -set_property(CACHE OT_PLATFORM PROPERTY STRINGS ${OT_PLATFORMS}) -if(NOT OT_PLATFORM IN_LIST OT_PLATFORMS) - message(FATAL_ERROR "Platform unknown: ${OT_PLATFORM}") -endif() - -set(OT_LOG_LEVEL "" CACHE STRING "set OpenThread log level") -set(OT_LOG_LEVEL_VALUES - "NONE" - "CRIT" - "WARN" - "NOTE" - "INFO" - "DEBG" -) -set_property(CACHE OT_LOG_LEVEL PROPERTY STRINGS ${OT_LOG_LEVEL_VALUES}) -if(OT_LOG_LEVEL) - target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_LOG_LEVEL=OT_LOG_LEVEL_${OT_LOG_LEVEL}") -endif() - -set(OT_LOG_OUTPUT_VALUES - "APP" - "DEBUG_UART" - "NONE" - "PLATFORM_DEFINED" -) -if(OT_REFERENCE_DEVICE AND NOT OT_PLATFORM STREQUAL "posix") - set(OT_LOG_OUTPUT "APP" CACHE STRING "Set log output to application for reference device") -else() - set(OT_LOG_OUTPUT "" CACHE STRING "Where log output goes to") -endif() -set_property(CACHE OT_LOG_OUTPUT PROPERTY STRINGS ${OT_LOG_OUTPUT_VALUES}) -if(OT_LOG_OUTPUT) - if(NOT OT_LOG_OUTPUT IN_LIST OT_LOG_OUTPUT_VALUES) - message(FATAL_ERROR "Log output unknown: ${OT_LOG_OUTPUT}") - endif() - target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_LOG_OUTPUT=OPENTHREAD_CONFIG_LOG_OUTPUT_${OT_LOG_OUTPUT}") - message(STATUS "Log output: ${OT_LOG_OUTPUT}") -endif() - -# OT_CONFIG allows users to specify the path to a customized OpenThread -# config header file. The default value of this parameter is empty string. -# When not specified by user (value is ""), a platform cmake file may -# choose to change this variable to provide its own OpenThread config header -# file instead. +# Deprecated +set(OT_CONFIG "" CACHE STRING "OpenThread config header file (deprecated, use `OT_PROJECT_CONFIG` or `OT_PLATFORM_CONFIG` instead") -set(OT_CONFIG "" CACHE STRING "OpenThread project-specific config header file chosen by user at configure time") +set(OT_PROJECT_CONFIG "" CACHE STRING "OpenThread project-specific config header file") +set(OT_PLATFORM_CONFIG "" CACHE STRING "OpenThread platform-specific config header file") list(APPEND OT_PUBLIC_INCLUDES ${PROJECT_BINARY_DIR}/etc/cmake) list(APPEND OT_PUBLIC_INCLUDES ${PROJECT_SOURCE_DIR}/etc/cmake) @@ -190,7 +129,18 @@ endif() if(OT_CONFIG) target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_FILE=\"${OT_CONFIG}\"") - message(STATUS "OpenThread Config File: \"${OT_CONFIG}\"") + message(WARNING "OT_CONFIG is deprecated - use `OT_PROJECT_CONFIG` and `OT_PLATFORM_CONFIG` instead") + message(STATUS "OT_CONFIG=\"${OT_CONFIG}\"") +endif() + +if (OT_PROJECT_CONFIG) + target_compile_definitions(ot-config INTERFACE "OPENTHREAD_PROJECT_CORE_CONFIG_FILE=\"${OT_PROJECT_CONFIG}\"") + message(STATUS "OT_PROJECT_CONFIG=\"${OT_PROJECT_CONFIG}\"") +endif() + +if (OT_PLATFORM_CONFIG) + target_compile_definitions(ot-config INTERFACE "OPENTHREAD_PLATFORM_CORE_CONFIG_FILE=\"${OT_PLATFORM_CONFIG}\"") + message(STATUS "OT_PLATFORM_CONFIG=\"${OT_PLATFORM_CONFIG}\"") endif() target_compile_definitions(ot-config INTERFACE ${OT_PLATFORM_DEFINES}) diff --git a/third_party/openthread/repo/etc/cmake/functions.cmake b/third_party/openthread/repo/etc/cmake/functions.cmake index 464b106a..f616bee0 100755 --- a/third_party/openthread/repo/etc/cmake/functions.cmake +++ b/third_party/openthread/repo/etc/cmake/functions.cmake @@ -26,22 +26,6 @@ # POSSIBILITY OF SUCH DAMAGE. # -# Get a list of the available platforms and output as a list to the 'arg_platforms' argument -function(ot_get_platforms arg_platforms) - list(APPEND result "NO" "posix" "external") - set(platforms_dir "${PROJECT_SOURCE_DIR}/examples/platforms") - file(GLOB platforms RELATIVE "${platforms_dir}" "${platforms_dir}/*") - foreach(platform IN LISTS platforms) - if(IS_DIRECTORY "${platforms_dir}/${platform}") - list(APPEND result "${platform}") - endif() - endforeach() - - list(REMOVE_ITEM result utils) - list(SORT result) - set(${arg_platforms} "${result}" PARENT_SCOPE) -endfunction() - function(ot_git_version git_version) execute_process( COMMAND git describe --dirty --always diff --git a/third_party/openthread/repo/etc/cmake/options.cmake b/third_party/openthread/repo/etc/cmake/options.cmake index fe659f06..7cc713c1 100644 --- a/third_party/openthread/repo/etc/cmake/options.cmake +++ b/third_party/openthread/repo/etc/cmake/options.cmake @@ -42,7 +42,6 @@ message(STATUS OT_APP_RCP=${OT_APP_RCP}) message(STATUS OT_FTD=${OT_FTD}) message(STATUS OT_MTD=${OT_MTD}) message(STATUS OT_RCP=${OT_RCP}) -message(STATUS OT_THREAD_VERSION=${OT_THREAD_VERSION}) set(OT_CONFIG_VALUES "" @@ -51,13 +50,15 @@ set(OT_CONFIG_VALUES ) macro(ot_option name ot_config description) - # Declare an OT cmake config with `name` mapping to OPENTHREAD_CONFIG - # `ot_config`. Parameter `description` provides the help string for this - # OT cmake config. There is an optional last parameter which if provided - # determines the default value for the cmake config. If not provided - # empty string is used which will be treated as "not specified". In this - # case, the variable `name` would still be false but the related - # OPENTHREAD_CONFIG is not added in `ot-config`. + # Declare an (ON/OFF/unspecified) OT cmake config with `name` + # mapping to OPENTHREAD_CONFIG `ot_config`. Parameter + # `description` provides the help string for this OT cmake + # config. There is an optional last parameter which if provided + # determines the default value for the cmake config. If not + # provided empty string is used which will be treated as "not + # specified". In this case, the variable `name` would still be + # false but the related OPENTHREAD_CONFIG is not added in + # `ot-config`. if (${ARGC} GREATER 3) set(${name} ${ARGN} CACHE STRING "enable ${description}") @@ -79,6 +80,91 @@ macro(ot_option name ot_config description) endif() endmacro() +macro(ot_string_option name ot_config description) + # Declare a string OT cmake config with `name` mapping to + # OPENTHREAD_CONFIG `ot_config`. Parameter `description` provides + # the help string for this OT cmake config. There is an optional + # last parameter which if provided determines the default value + # for the cmake config. If not provided empty string is used + # which will be treated as "not specified". + + if (${ARGC} GREATER 3) + set(${name} ${ARGN} CACHE STRING "${description}") + else() + set(${name} "" CACHE STRING "${description}") + endif() + + set_property(CACHE ${name} PROPERTY STRINGS "") + + string(COMPARE EQUAL "${${name}}" "" is_empty) + if (is_empty) + message(STATUS "${name}=\"\"") + else() + message(STATUS "${name}=\"${${name}}\" --> ${ot_config}=\"${${name}}\"") + target_compile_definitions(ot-config INTERFACE "${ot_config}=\"${${name}}\"") + endif() +endmacro() + +macro(ot_int_option name ot_config description) + # Declares a integer-value OT cmake config with `name` mapping to + # OPENTHREAD_CONFIG `ot_config`. There is an optional last + # parameter which if provided determines the default value for + # the cmake config. If not provided empty string is used which + # will be treated as "not specified". + + if (${ARGC} GREATER 3) + set(${name} ${ARGN} CACHE STRING "${description}") + else() + set(${name} "" CACHE STRING "${description}") + endif() + + set_property(CACHE ${name} PROPERTY STRINGS "") + + string(COMPARE EQUAL "${${name}}" "" is_empty) + if (is_empty) + message(STATUS "${name}=\"\"") + elseif("${${name}}" MATCHES "^[0-9]+$") + message(STATUS "${name}=\"${${name}}\" --> ${ot_config}=${${name}}") + target_compile_definitions(ot-config INTERFACE "${ot_config}=${${name}}") + else() + message(FATAL_ERROR "${name}=\"${${name}}\" - invalid value, must be integer") + endif() +endmacro() + +macro(ot_multi_option name values ot_config ot_value_prefix description) + # Declares a multi-value OT cmake config with `name` with valid + # values from `values` list mapping to OPENTHREAD_CONFIG + # `ot_config`. The `ot_value_prefix` is the prefix string to + # construct the OPENTHREAD_CONFIG value. There is an optional + # last parameter which if provided determines the default value + # for the cmake config. If not provided empty string is used + # which will be treated as "not specified". + + if (${ARGC} GREATER 5) + set(${name} ${ARGN} CACHE STRING "${description}") + else() + set(${name} "" CACHE STRING "${description}") + endif() + + set_property(CACHE ${name} PROPERTY STRINGS "${${values}}") + + string(COMPARE EQUAL "${${name}}" "" is_empty) + if (is_empty) + message(STATUS "${name}=\"\"") + else() + list(FIND ${values} "${${name}}" ot_index) + if(ot_index EQUAL -1) + message(FATAL_ERROR "${name}=\"${${name}}\" - unknown value, valid values " "${${values}}") + else() + message(STATUS "${name}=\"${${name}}\" --> ${ot_config}=${ot_value_prefix}${${name}}") + target_compile_definitions(ot-config INTERFACE "${ot_config}=${ot_value_prefix}${${name}}") + endif() + endif() +endmacro() + +message(STATUS "- - - - - - - - - - - - - - - - ") +message(STATUS "OpenThread ON/OFF/Unspecified Configs") + ot_option(OT_15_4 OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE "802.15.4 radio link") ot_option(OT_ANDROID_NDK OPENTHREAD_CONFIG_ANDROID_NDK_ENABLE "enable android NDK") ot_option(OT_ANYCAST_LOCATOR OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE "anycast locator") @@ -103,6 +189,7 @@ ot_option(OT_CSL_AUTO_SYNC OPENTHREAD_CONFIG_MAC_CSL_AUTO_SYNC_ENABLE "data poll ot_option(OT_CSL_DEBUG OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE "csl debug") ot_option(OT_CSL_RECEIVER OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE "csl receiver") ot_option(OT_DATASET_UPDATER OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE "dataset updater") +ot_option(OT_DEVICE_PROP_LEADER_WEIGHT OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE "device prop for leader weight") ot_option(OT_DHCP6_CLIENT OPENTHREAD_CONFIG_DHCP6_CLIENT_ENABLE "DHCP6 client") ot_option(OT_DHCP6_SERVER OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE "DHCP6 server") ot_option(OT_DIAGNOSTIC OPENTHREAD_CONFIG_DIAG_ENABLE "diagnostic") @@ -120,6 +207,7 @@ ot_option(OT_IP6_FRAGM OPENTHREAD_CONFIG_IP6_FRAGMENTATION_ENABLE "ipv6 fragment ot_option(OT_JAM_DETECTION OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE "jam detection") ot_option(OT_JOINER OPENTHREAD_CONFIG_JOINER_ENABLE "joiner") ot_option(OT_LINK_METRICS_INITIATOR OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE "link metrics initiator") +ot_option(OT_LINK_METRICS_MANAGER OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE "link metrics manager") ot_option(OT_LINK_METRICS_SUBJECT OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE "link metrics subject") ot_option(OT_LINK_RAW OPENTHREAD_CONFIG_LINK_RAW_ENABLE "link raw service") ot_option(OT_LOG_LEVEL_DYNAMIC OPENTHREAD_CONFIG_LOG_LEVEL_DYNAMIC_ENABLE "dynamic log level control") @@ -138,6 +226,7 @@ ot_option(OT_NETDIAG_CLIENT OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE "Network ot_option(OT_OPERATIONAL_DATASET_AUTO_INIT OPENTHREAD_CONFIG_OPERATIONAL_DATASET_AUTO_INIT "operational dataset auto init") ot_option(OT_OTNS OPENTHREAD_CONFIG_OTNS_ENABLE "OTNS") ot_option(OT_PING_SENDER OPENTHREAD_CONFIG_PING_SENDER_ENABLE "ping sender" ${OT_APP_CLI}) +ot_option(OT_PLATFORM_BOOTLOADER_MODE OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE "platform bootloader mode") ot_option(OT_PLATFORM_NETIF OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE "platform netif") ot_option(OT_PLATFORM_UDP OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE "platform UDP") ot_option(OT_REFERENCE_DEVICE OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE "test harness reference device") @@ -155,7 +244,52 @@ ot_option(OT_TX_QUEUE_STATS OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE "tx que ot_option(OT_UDP_FORWARD OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE "UDP forward") ot_option(OT_UPTIME OPENTHREAD_CONFIG_UPTIME_ENABLE "uptime") -option(OT_DOC "Build OpenThread documentation") +option(OT_DOC "build OpenThread documentation") + +message(STATUS "- - - - - - - - - - - - - - - - ") + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Get a list of the available platforms and output as a list to the 'arg_platforms' argument +function(ot_get_platforms arg_platforms) + list(APPEND result "NO" "posix" "external") + set(platforms_dir "${PROJECT_SOURCE_DIR}/examples/platforms") + file(GLOB platforms RELATIVE "${platforms_dir}" "${platforms_dir}/*") + foreach(platform IN LISTS platforms) + if(IS_DIRECTORY "${platforms_dir}/${platform}") + list(APPEND result "${platform}") + endif() + endforeach() + list(REMOVE_ITEM result utils) + list(SORT result) + set(${arg_platforms} "${result}" PARENT_SCOPE) +endfunction() + +ot_get_platforms(OT_PLATFORM_VALUES) +set(OT_PLATFORM "NO" CACHE STRING "Target platform chosen by the user at configure time") +set_property(CACHE OT_PLATFORM PROPERTY STRINGS "${OT_PLATFORM_VALUES}") +message(STATUS "OT_PLATFORM=\"${OT_PLATFORM}\"") +list(FIND OT_PLATFORM_VALUES "${OT_PLATFORM}" ot_index) +if(ot_index EQUAL -1) + message(FATAL_ERROR "Invalid value for OT_PLATFORM - valid values are:" "${OT_PLATFORM_VALUES}") +endif() + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +set(OT_THREAD_VERSION_VALUES "1.1" "1.2" "1.3" "1.3.1") +set(OT_THREAD_VERSION "1.3" CACHE STRING "set Thread version") +set_property(CACHE OT_THREAD_VERSION PROPERTY STRINGS "${OT_THREAD_VERSION_VALUES}") +list(FIND OT_THREAD_VERSION_VALUES "${OT_THREAD_VERSION}" ot_index) +if(ot_index EQUAL -1) + message(STATUS "OT_THREAD_VERSION=\"${OT_THREAD_VERSION}\"") + message(FATAL_ERROR "Invalid value for OT_THREAD_VERSION - valid values are: " "${OT_THREAD_VERSION_VALUES}") +endif() +set(OT_VERSION_SUFFIX_LIST "1_1" "1_2" "1_3" "1_3_1") +list(GET OT_VERSION_SUFFIX_LIST ${ot_index} OT_VERSION_SUFFIX) +target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_THREAD_VERSION=OT_THREAD_VERSION_${OT_VERSION_SUFFIX}") +message(STATUS "OT_THREAD_VERSION=\"${OT_THREAD_VERSION}\" -> OPENTHREAD_CONFIG_THREAD_VERSION=OT_THREAD_VERSION_${OT_VERSION_SUFFIX}") + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +set(OT_LOG_LEVEL_VALUES "NONE" "CRIT" "WARN" "NOTE" "INFO" "DEBG") +ot_multi_option(OT_LOG_LEVEL OT_LOG_LEVEL_VALUES OPENTHREAD_CONFIG_LOG_LEVEL OT_LOG_LEVEL_ "set OpenThread log level") option(OT_FULL_LOGS "enable full logs") if(OT_FULL_LOGS) @@ -166,68 +300,28 @@ if(OT_FULL_LOGS) target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_LOG_PREPEND_LEVEL=1") endif() -set(OT_VENDOR_NAME "" CACHE STRING "set the vendor name config") -set_property(CACHE OT_VENDOR_NAME PROPERTY STRINGS ${OT_VENDOR_NAME_VALUES}) -string(COMPARE EQUAL "${OT_VENDOR_NAME}" "" is_empty) -if (is_empty) - message(STATUS "OT_VENDOR_NAME=\"\"") +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +if(OT_REFERENCE_DEVICE AND NOT OT_PLATFORM STREQUAL "posix") + set(OT_DEFAULT_LOG_OUTPUT "APP") else() - message(STATUS "OT_VENDOR_NAME=\"${OT_VENDOR_NAME}\" --> OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME=\"${OT_VENDOR_NAME}\"") - target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME=\"${OT_VENDOR_NAME}\"") + set(OT_DEFAULT_LOG_OUTPUT "") endif() +set(OT_LOG_OUTPUT_VALUES "APP" "DEBUG_UART" "NONE" "PLATFORM_DEFINED") +ot_multi_option(OT_LOG_OUTPUT OT_LOG_OUTPUT_VALUES OPENTHREAD_CONFIG_LOG_OUTPUT OPENTHREAD_CONFIG_LOG_OUTPUT_ "Set the log output" "${OT_DEFAULT_LOG_OUTPUT}") -set(OT_VENDOR_MODEL "" CACHE STRING "set the vendor model config") -set_property(CACHE OT_VENDOR_MODEL PROPERTY STRINGS ${OT_VENDOR_MODEL_VALUES}) -string(COMPARE EQUAL "${OT_VENDOR_MODEL}" "" is_empty) -if (is_empty) - message(STATUS "OT_VENDOR_MODEL=\"\"") -else() - message(STATUS "OT_VENDOR_MODEL=\"${OT_VENDOR_MODEL}\" --> OPENTHREAD_CONFIG_NET_DIAG_VENDOR_MODEL=\"${OT_VENDOR_MODEL}\"") - target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_NET_DIAG_VENDOR_MODEL=\"${OT_VENDOR_MODEL}\"") -endif() +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -set(OT_VENDOR_SW_VERSION "" CACHE STRING "set the vendor sw version config") -set_property(CACHE OT_VENDOR_SW_VERSION PROPERTY STRINGS ${OT_VENDOR_SW_VERSION_VALUES}) -string(COMPARE EQUAL "${OT_VENDOR_SW_VERSION}" "" is_empty) -if (is_empty) - message(STATUS "OT_VENDOR_SW_VERSION=\"\"") -else() - message(STATUS "OT_VENDOR_SW_VERSION=\"${OT_VENDOR_SW_VERSION}\" --> OPENTHREAD_CONFIG_NET_DIAG_VENDOR_SW_VERSION=\"${OT_VENDOR_SW_VERSION}\"") - target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_NET_DIAG_VENDOR_SW_VERSION=\"${OT_VENDOR_SW_VERSION}\"") -endif() +ot_string_option(OT_VENDOR_NAME OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME "set the vendor name config") +ot_string_option(OT_VENDOR_MODEL OPENTHREAD_CONFIG_NET_DIAG_VENDOR_MODEL "set the vendor model config") +ot_string_option(OT_VENDOR_SW_VERSION OPENTHREAD_CONFIG_NET_DIAG_VENDOR_SW_VERSION "set the vendor sw version config") -set(OT_POWER_SUPPLY "" CACHE STRING "set the device power supply config") -set(OT_POWER_SUPPLY_VALUES - "" - "BATTERY" - "EXTERNAL" - "EXTERNAL_STABLE" - "EXTERNAL_UNSTABLE" -) -set_property(CACHE OT_POWER_SUPPLY PROPERTY STRINGS ${OT_POWER_SUPPLY_VALUES}) -string(COMPARE EQUAL "${OT_POWER_SUPPLY}" "" is_empty) -if (is_empty) - message(STATUS "OT_POWER_SUPPLY=\"\"") -else() - message(STATUS "OT_POWER_SUPPLY=${OT_POWER_SUPPLY} --> OPENTHREAD_CONFIG_DEVICE_POWER_SUPPLY=OT_POWER_SUPPLY_${OT_POWER_SUPPLY}") - target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_DEVICE_POWER_SUPPLY=OT_POWER_SUPPLY_${OT_POWER_SUPPLY}") -endif() +set(OT_POWER_SUPPLY_VALUES "BATTERY" "EXTERNAL" "EXTERNAL_STABLE" "EXTERNAL_UNSTABLE") +ot_multi_option(OT_POWER_SUPPLY OT_POWER_SUPPLY_VALUES OPENTHREAD_CONFIG_DEVICE_POWER_SUPPLY OT_POWER_SUPPLY_ "set the device power supply config") -set(OT_MLE_MAX_CHILDREN "" CACHE STRING "set maximum number of children") -if(OT_MLE_MAX_CHILDREN MATCHES "^[0-9]+$") - message(STATUS "OT_MLE_MAX_CHILDREN=${OT_MLE_MAX_CHILDREN}") - target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_MLE_MAX_CHILDREN=${OT_MLE_MAX_CHILDREN}") -elseif(NOT OT_MLE_MAX_CHILDREN STREQUAL "") - message(FATAL_ERROR "Invalid maximum number of children: ${OT_MLE_MAX_CHILDREN}") -endif() +ot_int_option(OT_MLE_MAX_CHILDREN OPENTHREAD_CONFIG_MLE_MAX_CHILDREN "set maximum number of children") +ot_int_option(OT_RCP_RESTORATION_MAX_COUNT OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT "set max RCP restoration count") -set(OT_RCP_RESTORATION_MAX_COUNT "0" CACHE STRING "set max RCP restoration count") -if(OT_RCP_RESTORATION_MAX_COUNT MATCHES "^[0-9]+$") - message(STATUS "OT_RCP_RESTORATION_MAX_COUNT=${OT_RCP_RESTORATION_MAX_COUNT}") - target_compile_definitions(ot-config INTERFACE "OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT=${OT_RCP_RESTORATION_MAX_COUNT}") -else() - message(FATAL_ERROR "Invalid max RCP restoration count: ${OT_RCP_RESTORATION_MAX_COUNT}") -endif() +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - set(OT_RCP_TX_WAIT_TIME_SECS "5" CACHE STRING "set RCP TX wait TIME in seconds") if(OT_RCP_TX_WAIT_TIME_SECS MATCHES "^[0-9]+$") @@ -269,3 +363,4 @@ endmacro() ot_removed_option(OT_MTD_NETDIAG "- Use OT_NETDIAG_CLIENT instead - note that server function is always supported") ot_removed_option(OT_EXCLUDE_TCPLP_LIB "- Use OT_TCP instead, OT_EXCLUDE_TCPLP_LIB is deprecated") +ot_removed_option(OT_POSIX_CONFIG_RCP_BUS "- Use OT_POSIX_RCP_HDLC_BUS, OT_POSIX_RCP_SPI_BUS or OT_POSIX_RCP_VENDOR_BUS instead, OT_POSIX_CONFIG_RCP_BUS is deprecated") diff --git a/third_party/openthread/repo/examples/config/ot-core-config-check-size-br.h b/third_party/openthread/repo/examples/config/ot-core-config-check-size-br.h new file mode 100644 index 00000000..8310019f --- /dev/null +++ b/third_party/openthread/repo/examples/config/ot-core-config-check-size-br.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023, 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. + */ + +/** + * This header file defines the OpenThread core configuration example for an Border Router. This is intended for use + * in `script/check-size`. + * + */ + +#ifndef OT_CORE_CONFIG_CHECK_SIZE_BR_H_ +#define OT_CORE_CONFIG_CHECK_SIZE_BR_H_ + +#define OPENTHREAD_CONFIG_THREAD_VERSION OT_THREAD_VERSION_1_3 + +#define OPENTHREAD_CONFIG_ASSERT_ENABLE 1 +#define OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE 1 +#define OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE 1 +#define OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE 1 +#define OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 1 +#define OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE 1 +#define OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE 1 +#define OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE 1 +#define OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE 1 +#define OPENTHREAD_CONFIG_COAP_API_ENABLE 1 +#define OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE 0 +#define OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE 0 +#define OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE 1 +#define OPENTHREAD_CONFIG_COMMISSIONER_ENABLE 1 +#define OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE 1 +#define OPENTHREAD_CONFIG_DHCP6_CLIENT_ENABLE 1 +#define OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE 1 +#define OPENTHREAD_CONFIG_DIAG_ENABLE 1 +#define OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE 1 +#define OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE 1 +#define OPENTHREAD_CONFIG_DNS_DSO_ENABLE 1 +#define OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE 1 +#define OPENTHREAD_CONFIG_DUA_ENABLE 1 +#define OPENTHREAD_CONFIG_ECDSA_ENABLE 1 +#define OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE 1 +#define OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE 1 +#define OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE 1 +#define OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE 1 +#define OPENTHREAD_CONFIG_JOINER_ENABLE 1 +#define OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE 1 +#define OPENTHREAD_CONFIG_LINK_RAW_ENABLE 1 +#define OPENTHREAD_CONFIG_LOG_LEVEL OT_LOG_LEVEL_INFO +#define OPENTHREAD_CONFIG_LOG_LEVEL_DYNAMIC_ENABLE 1 +#define OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE 1 +#define OPENTHREAD_CONFIG_MAC_FILTER_ENABLE 1 +#define OPENTHREAD_CONFIG_MESH_DIAG_ENABLE 1 +#define OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE 1 +#define OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE 1 +#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE 1 +#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 1 +#define OPENTHREAD_CONFIG_MLR_ENABLE 1 +#define OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE 0 +#define OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE 1 +#define OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE 1 +#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE 1 +#define OPENTHREAD_CONFIG_PING_SENDER_ENABLE 1 +#define OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE 1 +#define OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE 1 +#define OPENTHREAD_CONFIG_SRP_SERVER_ENABLE 1 +#define OPENTHREAD_CONFIG_TIME_SYNC_ENABLE 0 +#define OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE 1 +#define OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE 1 +#define OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE 1 +#define OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE 1 +#define OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE 1 +#define OPENTHREAD_CONFIG_UPTIME_ENABLE 1 + +// Enable mock platform APIs +#define OPENTHREAD_CONFIG_DNS_DSO_MOCK_PLAT_APIS_ENABLE 1 +#define OPENTHREAD_CONFIG_BORDER_ROUTING_MOCK_PLAT_APIS_ENABLE 1 +#define OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_MOCK_PLAT_APIS_ENABLE 1 + +#endif // OT_CORE_CONFIG_CHECK_SIZE_BR_H_ diff --git a/third_party/openthread/repo/examples/config/ot-core-config-check-size-ftd.h b/third_party/openthread/repo/examples/config/ot-core-config-check-size-ftd.h new file mode 100644 index 00000000..63e7ad48 --- /dev/null +++ b/third_party/openthread/repo/examples/config/ot-core-config-check-size-ftd.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023, 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. + */ + +/** + * This header file defines the OpenThread core configuration example for an FTD device (not acting as BR). This is + * intended for use in `script/check-size`. + * + */ + +#ifndef OT_CORE_CONFIG_CHECK_SIZE_FTD_H_ +#define OT_CORE_CONFIG_CHECK_SIZE_FTD_H_ + +#define OPENTHREAD_CONFIG_THREAD_VERSION OT_THREAD_VERSION_1_3 + +#define OPENTHREAD_CONFIG_ASSERT_ENABLE 1 +#define OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE 0 +#define OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE 1 +#define OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE 1 +#define OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 0 +#define OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE 0 +#define OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE 0 +#define OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE 1 +#define OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE 1 +#define OPENTHREAD_CONFIG_COAP_API_ENABLE 1 +#define OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE 0 +#define OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE 0 +#define OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE 1 +#define OPENTHREAD_CONFIG_COMMISSIONER_ENABLE 1 +#define OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE 1 +#define OPENTHREAD_CONFIG_DHCP6_CLIENT_ENABLE 1 +#define OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE 1 +#define OPENTHREAD_CONFIG_DIAG_ENABLE 1 +#define OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE 0 +#define OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE 1 +#define OPENTHREAD_CONFIG_DNS_DSO_ENABLE 0 +#define OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE 0 +#define OPENTHREAD_CONFIG_DUA_ENABLE 1 +#define OPENTHREAD_CONFIG_ECDSA_ENABLE 1 +#define OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE 0 +#define OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE 0 +#define OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE 1 +#define OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE 1 +#define OPENTHREAD_CONFIG_JOINER_ENABLE 1 +#define OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE 1 +#define OPENTHREAD_CONFIG_LINK_RAW_ENABLE 1 +#define OPENTHREAD_CONFIG_LOG_LEVEL OT_LOG_LEVEL_INFO +#define OPENTHREAD_CONFIG_LOG_LEVEL_DYNAMIC_ENABLE 0 +#define OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE 1 +#define OPENTHREAD_CONFIG_MAC_FILTER_ENABLE 1 +#define OPENTHREAD_CONFIG_MESH_DIAG_ENABLE 1 +#define OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE 1 +#define OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE 1 +#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE 1 +#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 1 +#define OPENTHREAD_CONFIG_MLR_ENABLE 1 +#define OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE 0 +#define OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE 0 +#define OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE 0 +#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE 0 +#define OPENTHREAD_CONFIG_PING_SENDER_ENABLE 1 +#define OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE 1 +#define OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE 1 +#define OPENTHREAD_CONFIG_SRP_SERVER_ENABLE 0 +#define OPENTHREAD_CONFIG_TIME_SYNC_ENABLE 0 +#define OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE 1 +#define OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE 1 +#define OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE 1 +#define OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE 0 +#define OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE 1 +#define OPENTHREAD_CONFIG_UPTIME_ENABLE 1 + +#endif // OT_CORE_CONFIG_CHECK_SIZE_FTD_H_ diff --git a/third_party/openthread/repo/examples/config/ot-core-config-check-size-mtd.h b/third_party/openthread/repo/examples/config/ot-core-config-check-size-mtd.h new file mode 100644 index 00000000..88b2c119 --- /dev/null +++ b/third_party/openthread/repo/examples/config/ot-core-config-check-size-mtd.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023, 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. + */ + +/** + * This header file defines the OpenThread core configuration example for an MTD/SED device. This is intended for use + * in `script/check-size`. + * + */ + +#ifndef OT_CORE_CONFIG_CHECK_SIZE_MTD_H_ +#define OT_CORE_CONFIG_CHECK_SIZE_MTD_H_ + +#define OPENTHREAD_CONFIG_THREAD_VERSION OT_THREAD_VERSION_1_3 + +#define OPENTHREAD_CONFIG_ASSERT_ENABLE 1 +#define OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE 0 +#define OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE 0 +#define OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE 0 +#define OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 0 +#define OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE 0 +#define OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE 0 +#define OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE 0 +#define OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE 0 +#define OPENTHREAD_CONFIG_COAP_API_ENABLE 1 +#define OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE 0 +#define OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE 0 +#define OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE 1 +#define OPENTHREAD_CONFIG_COMMISSIONER_ENABLE 0 +#define OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE 0 +#define OPENTHREAD_CONFIG_DHCP6_CLIENT_ENABLE 1 +#define OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE 0 +#define OPENTHREAD_CONFIG_DIAG_ENABLE 1 +#define OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE 0 +#define OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE 1 +#define OPENTHREAD_CONFIG_DNS_DSO_ENABLE 0 +#define OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE 0 +#define OPENTHREAD_CONFIG_DUA_ENABLE 1 +#define OPENTHREAD_CONFIG_ECDSA_ENABLE 1 +#define OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE 0 +#define OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE 0 +#define OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE 1 +#define OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE 0 +#define OPENTHREAD_CONFIG_JOINER_ENABLE 1 +#define OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE 0 +#define OPENTHREAD_CONFIG_LINK_RAW_ENABLE 1 +#define OPENTHREAD_CONFIG_LOG_LEVEL OT_LOG_LEVEL_INFO +#define OPENTHREAD_CONFIG_LOG_LEVEL_DYNAMIC_ENABLE 0 +#define OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE 1 +#define OPENTHREAD_CONFIG_MAC_FILTER_ENABLE 1 +#define OPENTHREAD_CONFIG_MESH_DIAG_ENABLE 0 +#define OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE 1 +#define OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE 0 +#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE 0 +#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 1 +#define OPENTHREAD_CONFIG_MLR_ENABLE 1 +#define OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE 0 +#define OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE 0 +#define OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE 0 +#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE 0 +#define OPENTHREAD_CONFIG_PING_SENDER_ENABLE 1 +#define OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE 1 +#define OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE 1 +#define OPENTHREAD_CONFIG_SRP_SERVER_ENABLE 0 +#define OPENTHREAD_CONFIG_TIME_SYNC_ENABLE 0 +#define OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE 1 +#define OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE 0 +#define OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE 0 +#define OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE 0 +#define OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE 1 +#define OPENTHREAD_CONFIG_UPTIME_ENABLE 1 + +#endif // OT_CORE_CONFIG_CHECK_SIZE_MTD_H_ diff --git a/third_party/openthread/repo/examples/platforms/simulation/CMakeLists.txt b/third_party/openthread/repo/examples/platforms/simulation/CMakeLists.txt index 883ee641..c99597d4 100644 --- a/third_party/openthread/repo/examples/platforms/simulation/CMakeLists.txt +++ b/third_party/openthread/repo/examples/platforms/simulation/CMakeLists.txt @@ -45,8 +45,8 @@ if(OT_SIMULATION_MAX_NETWORK_SIZE) target_compile_definitions(ot-simulation-config INTERFACE "OPENTHREAD_SIMULATION_MAX_NETWORK_SIZE=${OT_SIMULATION_MAX_NETWORK_SIZE}") endif() -if(NOT OT_CONFIG) - set(OT_CONFIG "openthread-core-simulation-config.h" PARENT_SCOPE) +if(NOT OT_PLATFORM_CONFIG) + set(OT_PLATFORM_CONFIG "openthread-core-simulation-config.h" PARENT_SCOPE) endif() list(APPEND OT_PLATFORM_DEFINES @@ -61,6 +61,7 @@ add_library(openthread-simulation alarm.c crypto.c diag.c + dns.c dso_transport.c entropy.c flash.c diff --git a/third_party/openthread/repo/examples/platforms/simulation/dns.c b/third_party/openthread/repo/examples/platforms/simulation/dns.c new file mode 100644 index 00000000..0542af06 --- /dev/null +++ b/third_party/openthread/repo/examples/platforms/simulation/dns.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023, 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. + */ + +#include "platform-simulation.h" + +#include + +#if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE + +void otPlatDnsStartUpstreamQuery(otInstance *aInstance, otPlatDnsUpstreamQuery *aTxn, const otMessage *aQuery) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aTxn); + OT_UNUSED_VARIABLE(aQuery); +} + +void otPlatDnsCancelUpstreamQuery(otInstance *aInstance, otPlatDnsUpstreamQuery *aTxn) +{ + otPlatDnsUpstreamQueryDone(aInstance, aTxn, NULL); +} + +#endif diff --git a/third_party/openthread/repo/examples/platforms/simulation/flash.c b/third_party/openthread/repo/examples/platforms/simulation/flash.c index ce07f3a7..59461e0e 100644 --- a/third_party/openthread/repo/examples/platforms/simulation/flash.c +++ b/third_party/openthread/repo/examples/platforms/simulation/flash.c @@ -84,7 +84,7 @@ void otPlatFlashInit(otInstance *aInstance) if (create) { - for (uint8_t index = 0; index < SWAP_NUM; index++) + for (uint8_t index = 0; index < (uint8_t)SWAP_NUM; index++) { otPlatFlashErase(aInstance, index); } diff --git a/third_party/openthread/repo/examples/platforms/simulation/misc.c b/third_party/openthread/repo/examples/platforms/simulation/misc.c index aefbca5d..07739a2f 100644 --- a/third_party/openthread/repo/examples/platforms/simulation/misc.c +++ b/third_party/openthread/repo/examples/platforms/simulation/misc.c @@ -60,6 +60,15 @@ void otPlatReset(otInstance *aInstance) #endif // OPENTHREAD_PLATFORM_USE_PSEUDO_RESET } +#if OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE +otError otPlatResetToBootloader(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + + return OT_ERROR_NOT_CAPABLE; +} +#endif + otPlatResetReason otPlatGetResetReason(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); diff --git a/third_party/openthread/repo/examples/platforms/simulation/openthread-core-simulation-config.h b/third_party/openthread/repo/examples/platforms/simulation/openthread-core-simulation-config.h index 252a41a1..517b5b5b 100644 --- a/third_party/openthread/repo/examples/platforms/simulation/openthread-core-simulation-config.h +++ b/third_party/openthread/repo/examples/platforms/simulation/openthread-core-simulation-config.h @@ -39,128 +39,58 @@ #define OPENTHREAD_RADIO 0 #endif -/** - * @def OPENTHREAD_CONFIG_PLATFORM_INFO - * - * The platform-specific string to insert into the OpenThread version string. - * - */ +#ifndef OPENTHREAD_CONFIG_PLATFORM_INFO #define OPENTHREAD_CONFIG_PLATFORM_INFO "SIMULATION" +#endif -/** - * @def OPENTHREAD_CONFIG_LOG_OUTPUT - * - * Specify where the log output should go. - * - */ -#ifndef OPENTHREAD_CONFIG_LOG_OUTPUT /* allow command line override */ +#ifndef OPENTHREAD_CONFIG_LOG_OUTPUT #define OPENTHREAD_CONFIG_LOG_OUTPUT OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED #endif -/** - * @def OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE - * - * Define as 1 to enable support for adding of auto-configured SLAAC addresses by OpenThread. - * - */ -#ifndef OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE /* allows command line override */ +#ifndef OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE #define OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE 1 #endif #if OPENTHREAD_RADIO -/** - * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_ACK_TIMEOUT_ENABLE - * - * Define to 1 if you want to enable software ACK timeout logic. - * - */ + #ifndef OPENTHREAD_CONFIG_MAC_SOFTWARE_ACK_TIMEOUT_ENABLE #define OPENTHREAD_CONFIG_MAC_SOFTWARE_ACK_TIMEOUT_ENABLE 1 #endif -/** - * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_ENERGY_SCAN_ENABLE - * - * Define to 1 if you want to enable software energy scanning logic. - * - */ #ifndef OPENTHREAD_CONFIG_MAC_SOFTWARE_ENERGY_SCAN_ENABLE #define OPENTHREAD_CONFIG_MAC_SOFTWARE_ENERGY_SCAN_ENABLE 1 #endif -/** - * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_RETRANSMIT_ENABLE - * - * Define to 1 if you want to enable software retransmission logic. - * - */ #ifndef OPENTHREAD_CONFIG_MAC_SOFTWARE_RETRANSMIT_ENABLE #define OPENTHREAD_CONFIG_MAC_SOFTWARE_RETRANSMIT_ENABLE 1 #endif -/** - * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_CSMA_BACKOFF_ENABLE - * - * Define to 1 if you want to enable software CSMA-CA backoff logic. - * - */ #ifndef OPENTHREAD_CONFIG_MAC_SOFTWARE_CSMA_BACKOFF_ENABLE #define OPENTHREAD_CONFIG_MAC_SOFTWARE_CSMA_BACKOFF_ENABLE 1 #endif -/** - * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE - * - * Define to 1 if you want to enable software transmission security logic. - * - */ #ifndef OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE #define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE 1 #endif -/** - * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE - * - * Define to 1 to enable software transmission target time logic. - * - */ #ifndef OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE #define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE 1 #endif + #endif // OPENTHREAD_RADIO -/** - * @def OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE - * - * Define to 1 if you want to support microsecond timer in platform. - * - */ +#ifndef OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE #define OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE 1 +#endif -/** - * @def OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE - * - * Define to 1 to enable otPlatFlash* APIs to support non-volatile storage. - * - * When defined to 1, the platform MUST implement the otPlatFlash* APIs instead of the otPlatSettings* APIs. - * - */ +#ifndef OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE #define OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE 1 +#endif -/** - * @def CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER - * - * Define to 1 to use DefaultHandler for unhandled requests - * - */ +#ifndef CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER #define CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER 1 +#endif -/** - * @def OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE - * - * Define to 1 if you want to enable radio coexistence implemented in platform. - * - */ #ifndef OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE #define OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE 1 #endif @@ -169,129 +99,50 @@ #define OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE 1 #endif -/** - * @def OPENTHREAD_CONFIG_LOG_PLATFORM - * - * Define to enable platform region logging. - * - */ #ifndef OPENTHREAD_CONFIG_LOG_PLATFORM #define OPENTHREAD_CONFIG_LOG_PLATFORM 1 #endif -/** - * @def OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH - * - * The maximum size of the CLI line in bytes. - * - */ #ifndef OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH #define OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH 640 #endif -/** - * @def OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE - * - * The size of CLI UART RX buffer in bytes. - * - */ #ifndef OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE #define OPENTHREAD_CONFIG_CLI_UART_RX_BUFFER_SIZE 640 #endif -/** - * @def OPENTHREAD_CONFIG_MLE_MAX_CHILDREN - * - * The maximum number of children. - * - */ #ifndef OPENTHREAD_CONFIG_MLE_MAX_CHILDREN #define OPENTHREAD_CONFIG_MLE_MAX_CHILDREN 128 #endif -/** - * @def OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH - * - * Define as 1 for a child to inform its previous parent when it attaches to a new parent. - * - * If this feature is enabled, when a device attaches to a new parent, it will send an IP message (with empty payload - * and mesh-local IP address as the source address) to its previous parent. - * - */ #ifndef OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH #define OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH 1 #endif -/** - * @def OPENTHREAD_CONFIG_UPTIME_ENABLE - * - * Define to 1 to enable tracking the uptime of OpenThread instance. - * - */ #ifndef OPENTHREAD_CONFIG_UPTIME_ENABLE #define OPENTHREAD_CONFIG_UPTIME_ENABLE 1 #endif -/** - * @def OPENTHREAD_CONFIG_LOG_PREPEND_UPTIME - * - * Define as 1 to prepend the current uptime to all log messages. - * - */ #ifndef OPENTHREAD_CONFIG_LOG_PREPEND_UPTIME #define OPENTHREAD_CONFIG_LOG_PREPEND_UPTIME 1 #endif -/** - * @def OPENTHREAD_CONFIG_SRP_CLIENT_BUFFERS_MAX_SERVICES - * - * Specifies number of service entries in the SRP client service pool. - * - * This config is applicable only when `OPENTHREAD_CONFIG_SRP_CLIENT_BUFFERS_ENABLE` is enabled. - * - */ #ifndef OPENTHREAD_CONFIG_SRP_CLIENT_BUFFERS_MAX_SERVICES #define OPENTHREAD_CONFIG_SRP_CLIENT_BUFFERS_MAX_SERVICES 20 #endif -/** - * @def OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE - * - * Define to 1 to generate ECDSA signatures deterministically - * according to RFC 6979 instead of randomly. - * - */ #ifndef OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE #define OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE 1 #endif -/** - * @def OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE - * - * Define as 1 to enable power calibration support. - * - */ #ifndef OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE #define OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE 1 #endif -/** - * @def OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE - * - * Define as 1 to enable platform power calibration support. - * - */ #ifndef OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE #define OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE 1 #endif -/** - * @def OPENTHREAD_CONFIG_RADIO_STATS_ENABLE - * - * Set to 1 to enable support for Radio Statistics. Note that this option only works for OPENTHREAD_FTD and - * OPENTHREAD_MTD. - * - */ #ifndef OPENTHREAD_CONFIG_RADIO_STATS_ENABLE #define OPENTHREAD_CONFIG_RADIO_STATS_ENABLE 1 #endif diff --git a/third_party/openthread/repo/examples/platforms/simulation/radio.c b/third_party/openthread/repo/examples/platforms/simulation/radio.c index 9fe37b66..6ba2a5dc 100644 --- a/third_party/openthread/repo/examples/platforms/simulation/radio.c +++ b/third_party/openthread/repo/examples/platforms/simulation/radio.c @@ -236,7 +236,7 @@ otError ProcessNodeIdFilter(void *aContext, uint8_t aArgsLength, char *aArgs[]) break; } - for (uint16_t nodeId = 0; nodeId <= MAX_NETWORK_SIZE; nodeId++) + for (uint16_t nodeId = 0; nodeId <= (uint16_t)MAX_NETWORK_SIZE; nodeId++) { if (FilterContainsId(nodeId)) { diff --git a/third_party/openthread/repo/examples/platforms/utils/CMakeLists.txt b/third_party/openthread/repo/examples/platforms/utils/CMakeLists.txt index 3dcc67e4..3e4a680d 100644 --- a/third_party/openthread/repo/examples/platforms/utils/CMakeLists.txt +++ b/third_party/openthread/repo/examples/platforms/utils/CMakeLists.txt @@ -34,12 +34,19 @@ add_library(openthread-platform-utils OBJECT otns_utils.cpp settings_ram.c soft_source_match_table.c + uart_rtt.c ) target_compile_definitions(openthread-platform-utils PRIVATE $ ) +if(OT_RTT_UART) + target_compile_definitions(openthread-platform-utils PRIVATE + OPENTHREAD_UART_RTT_ENABLE=1 + ) +endif() + target_include_directories(openthread-platform-utils PRIVATE ${OT_PUBLIC_INCLUDES} $ diff --git a/third_party/openthread/repo/examples/platforms/utils/uart_rtt.c b/third_party/openthread/repo/examples/platforms/utils/uart_rtt.c new file mode 100644 index 00000000..b5a42e09 --- /dev/null +++ b/third_party/openthread/repo/examples/platforms/utils/uart_rtt.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2023, 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 the RTT implementation of the uart API. + * + */ + +#include + +#include +#include + +#include +#include + +#if OPENTHREAD_UART_RTT_ENABLE + +#include "SEGGER_RTT.h" +#include "uart.h" +#include "uart_rtt.h" + +static bool sUartInitialized = false; +static bool sUartPendingUp = false; + +#if UART_RTT_BUFFER_INDEX != 0 +static uint8_t sUartUpBuffer[UART_RTT_UP_BUFFER_SIZE]; +static uint8_t sUartDownBuffer[UART_RTT_DOWN_BUFFER_SIZE]; +#endif + +otError otPlatUartEnable(void) +{ + otError error = OT_ERROR_FAILED; + +#if UART_RTT_BUFFER_INDEX != 0 + int resUp = SEGGER_RTT_ConfigUpBuffer(UART_RTT_BUFFER_INDEX, UART_RTT_BUFFER_NAME, sUartUpBuffer, + UART_RTT_UP_BUFFER_SIZE, SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL); + int resDown = SEGGER_RTT_ConfigDownBuffer(UART_RTT_BUFFER_INDEX, UART_RTT_BUFFER_NAME, sUartDownBuffer, + UART_RTT_DOWN_BUFFER_SIZE, SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL); +#else + int resUp = SEGGER_RTT_SetFlagsUpBuffer(UART_RTT_BUFFER_INDEX, SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL); + int resDown = SEGGER_RTT_SetFlagsDownBuffer(UART_RTT_BUFFER_INDEX, SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL); +#endif + + otEXPECT(resUp >= 0 && resDown >= 0); + + sUartInitialized = true; + sUartPendingUp = false; + error = OT_ERROR_NONE; + +exit: + return error; +} + +otError otPlatUartDisable(void) +{ + sUartInitialized = false; + + return OT_ERROR_NONE; +} + +otError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength) +{ + otError error = OT_ERROR_NONE; + + otEXPECT_ACTION(SEGGER_RTT_Write(UART_RTT_BUFFER_INDEX, aBuf, aBufLength) != 0, error = OT_ERROR_FAILED); + sUartPendingUp = true; + +exit: + return error; +} + +otError otPlatUartFlush(void) +{ + otError error = OT_ERROR_NONE; + + otEXPECT_ACTION(sUartPendingUp, error = OT_ERROR_INVALID_STATE); + + while (SEGGER_RTT_HasDataUp(UART_RTT_BUFFER_INDEX) != 0) + { + } + +exit: + return error; +} + +void utilsUartRttProcess(void) +{ + uint8_t buf[UART_RTT_READ_BUFFER_SIZE]; + unsigned count; + + otEXPECT(sUartInitialized); + + if (sUartPendingUp && SEGGER_RTT_HasDataUp(UART_RTT_BUFFER_INDEX) == 0) + { + sUartPendingUp = false; + otPlatUartSendDone(); + } + + count = SEGGER_RTT_Read(UART_RTT_BUFFER_INDEX, &buf, sizeof(buf)); + if (count > 0) + { + otPlatUartReceived((const uint8_t *)&buf, count); + } + +exit: + return; +} + +#endif // OPENTHREAD_UART_RTT_ENABLE diff --git a/third_party/openthread/repo/examples/platforms/utils/uart_rtt.h b/third_party/openthread/repo/examples/platforms/utils/uart_rtt.h new file mode 100644 index 00000000..b1529f59 --- /dev/null +++ b/third_party/openthread/repo/examples/platforms/utils/uart_rtt.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2023, 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 defines the RTT implementation of the uart API and default constants used by uart_rtt.c. + * + */ + +#ifndef UTILS_UART_RTT_H +#define UTILS_UART_RTT_H + +#include "openthread-core-config.h" +#include + +#include "logging_rtt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @def UART_RTT_BUFFER_INDEX + * + * RTT buffer index used for the uart. + * + */ +#ifndef UART_RTT_BUFFER_INDEX +#define UART_RTT_BUFFER_INDEX 1 +#endif + +#if OPENTHREAD_UART_RTT_ENABLE && (OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED) && \ + (LOG_RTT_BUFFER_INDEX == UART_RTT_BUFFER_INDEX) +#error "Log buffer index matches uart buffer index" +#endif + +/** + * @def UART_RTT_BUFFER_NAME + * + * RTT name used for the uart. Only used if UART_RTT_BUFFER_INDEX is not 0. + * Otherwise, the buffer name is fixed to "Terminal". + * + */ +#ifndef UART_RTT_BUFFER_NAME +#define UART_RTT_BUFFER_NAME "Terminal" +#endif + +/** + * @def UART_RTT_UP_BUFFER_SIZE + * + * RTT up buffer size used for the uart. Only used if UART_RTT_BUFFER_INDEX + * is not 0. To configure buffer #0 size, check the BUFFER_SIZE_UP definition + * in SEGGER_RTT_Conf.h + * + */ +#ifndef UART_RTT_UP_BUFFER_SIZE +#define UART_RTT_UP_BUFFER_SIZE 256 +#endif + +/** + * @def UART_RTT_DOWN_BUFFER_SIZE + * + * RTT down buffer size used for the uart. Only used if UART_RTT_BUFFER_INDEX + * is not 0. To configure buffer #0 size, check the BUFFER_SIZE_DOWN definition + * in SEGGER_RTT_Conf.h + * + */ +#ifndef UART_RTT_DOWN_BUFFER_SIZE +#define UART_RTT_DOWN_BUFFER_SIZE 16 +#endif + +/** + * @def UART_RTT_READ_BUFFER_SIZE + * + * Size of the temporary buffer used when reading from the RTT channel. It will be + * locally allocated on the stack. + * + */ +#ifndef UART_RTT_READ_BUFFER_SIZE +#define UART_RTT_READ_BUFFER_SIZE 16 +#endif + +/** + * Updates the rtt uart. Must be called frequently to process receive and send done. + * + */ +void utilsUartRttProcess(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // UTILS_UART_RTT_H diff --git a/third_party/openthread/repo/include/openthread/border_agent.h b/third_party/openthread/repo/include/openthread/border_agent.h index 4ffbc9c6..1c7a5353 100644 --- a/third_party/openthread/repo/include/openthread/border_agent.h +++ b/third_party/openthread/repo/include/openthread/border_agent.h @@ -69,6 +69,12 @@ struct otBorderAgentId uint8_t mId[OT_BORDER_AGENT_ID_LENGTH]; } OT_TOOL_PACKED_END; +/** + * Represents a Border Agent ID. + * + */ +typedef struct otBorderAgentId otBorderAgentId; + /** * Defines the Border Agent state. * diff --git a/third_party/openthread/repo/include/openthread/border_routing.h b/third_party/openthread/repo/include/openthread/border_routing.h index 8c679ac0..36e83a6d 100644 --- a/third_party/openthread/repo/include/openthread/border_routing.h +++ b/third_party/openthread/repo/include/openthread/border_routing.h @@ -133,6 +133,8 @@ typedef enum * Initializes the Border Routing Manager on given infrastructure interface. * * @note This method MUST be called before any other otBorderRouting* APIs. + * @note This method can be re-called to change the infrastructure interface, but the Border Routing Manager should be + * disabled first, and re-enabled after. * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aInfraIfIndex The infrastructure interface index. @@ -140,11 +142,12 @@ typedef enum * interface is running. * * @retval OT_ERROR_NONE Successfully started the Border Routing Manager on given infrastructure. - * @retval OT_ERROR_INVALID_STATE The Border Routing Manager has already been initialized. + * @retval OT_ERROR_INVALID_STATE The Border Routing Manager is in a state other than disabled or uninitialized. * @retval OT_ERROR_INVALID_ARGS The index of the infrastructure interface is not valid. * @retval OT_ERROR_FAILED Internal failure. Usually due to failure in generating random prefixes. * * @sa otPlatInfraIfStateChanged. + * @sa otBorderRoutingSetEnabled. * */ otError otBorderRoutingInit(otInstance *aInstance, uint32_t aInfraIfIndex, bool aInfraIfIsRunning); diff --git a/third_party/openthread/repo/include/openthread/coap.h b/third_party/openthread/repo/include/openthread/coap.h index e494c3c6..4b7149ad 100644 --- a/third_party/openthread/repo/include/openthread/coap.h +++ b/third_party/openthread/repo/include/openthread/coap.h @@ -878,9 +878,9 @@ otMessage *otCoapNewMessage(otInstance *aInstance, const otMessageSettings *aSet * 2. mAckRandomFactorNumerator / mAckRandomFactorDenominator must not be below 1.0. * 3. The calculated exchange life time must not overflow uint32_t. * - * @retval OT_ERROR_INVALID_ARGS @p aTxParameters is invalid. * @retval OT_ERROR_NONE Successfully sent CoAP message. * @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data. + * @retval OT_ERROR_INVALID_ARGS Invalid arguments are given. * */ otError otCoapSendRequestWithParameters(otInstance *aInstance, @@ -909,8 +909,9 @@ otError otCoapSendRequestWithParameters(otInstance *aInstance, * @param[in] aTransmitHook A pointer to a hook function for outgoing block-wise transfer. * @param[in] aReceiveHook A pointer to a hook function for incoming block-wise transfer. * - * @retval OT_ERROR_NONE Successfully sent CoAP message. - * @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data. + * @retval OT_ERROR_NONE Successfully sent CoAP message. + * @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data. + * @retval OT_ERROR_INVALID_ARGS Invalid arguments are given. * */ otError otCoapSendRequestBlockWiseWithParameters(otInstance *aInstance, @@ -1059,8 +1060,9 @@ void otCoapSetDefaultHandler(otInstance *aInstance, otCoapRequestHandler aHandle * @param[in] aMessageInfo A pointer to the message info associated with @p aMessage. * @param[in] aTxParameters A pointer to transmission parameters for this response. Use NULL for defaults. * - * @retval OT_ERROR_NONE Successfully enqueued the CoAP response message. - * @retval OT_ERROR_NO_BUFS Insufficient buffers available to send the CoAP response. + * @retval OT_ERROR_NONE Successfully enqueued the CoAP response message. + * @retval OT_ERROR_NO_BUFS Insufficient buffers available to send the CoAP response. + * @retval OT_ERROR_INVALID_ARGS Invalid arguments are given. * */ otError otCoapSendResponseWithParameters(otInstance *aInstance, @@ -1081,8 +1083,9 @@ otError otCoapSendResponseWithParameters(otInstance *aInstance, * @param[in] aContext A pointer to arbitrary context information. May be NULL if not used. * @param[in] aTransmitHook A pointer to a hook function for outgoing block-wise transfer. * - * @retval OT_ERROR_NONE Successfully enqueued the CoAP response message. - * @retval OT_ERROR_NO_BUFS Insufficient buffers available to send the CoAP response. + * @retval OT_ERROR_NONE Successfully enqueued the CoAP response message. + * @retval OT_ERROR_NO_BUFS Insufficient buffers available to send the CoAP response. + * @retval OT_ERROR_INVALID_ARGS Invalid arguments are given. * */ otError otCoapSendResponseBlockWiseWithParameters(otInstance *aInstance, diff --git a/third_party/openthread/repo/include/openthread/commissioner.h b/third_party/openthread/repo/include/openthread/commissioner.h index 9f714b38..410bd0f7 100644 --- a/third_party/openthread/repo/include/openthread/commissioner.h +++ b/third_party/openthread/repo/include/openthread/commissioner.h @@ -111,6 +111,7 @@ typedef struct otCommissioningDataset bool mIsSessionIdSet : 1; ///< TRUE if Commissioner Session Id is set, FALSE otherwise. bool mIsSteeringDataSet : 1; ///< TRUE if Steering Data is set, FALSE otherwise. bool mIsJoinerUdpPortSet : 1; ///< TRUE if Joiner UDP Port is set, FALSE otherwise. + bool mHasExtraTlv : 1; ///< TRUE if the Dataset contains any extra unknown sub-TLV, FALSE otherwise. } otCommissioningDataset; #define OT_JOINER_MAX_PSKD_LENGTH 32 ///< Maximum string length of a Joiner PSKd (does not include null char). diff --git a/third_party/openthread/repo/include/openthread/crypto.h b/third_party/openthread/repo/include/openthread/crypto.h index 112d3bd3..414b4bae 100644 --- a/third_party/openthread/repo/include/openthread/crypto.h +++ b/third_party/openthread/repo/include/openthread/crypto.h @@ -56,8 +56,6 @@ extern "C" { */ /** - * @struct otCryptoSha256Hash - * * Represents a SHA-256 hash. * */ diff --git a/third_party/openthread/repo/include/openthread/dataset.h b/third_party/openthread/repo/include/openthread/dataset.h index 8be3be98..1cfc4cf7 100644 --- a/third_party/openthread/repo/include/openthread/dataset.h +++ b/third_party/openthread/repo/include/openthread/dataset.h @@ -201,18 +201,18 @@ typedef uint32_t otChannelMask; */ typedef struct otOperationalDatasetComponents { - bool mIsActiveTimestampPresent : 1; ///< TRUE if Active Timestamp is present, FALSE otherwise. - bool mIsPendingTimestampPresent : 1; ///< TRUE if Pending Timestamp is present, FALSE otherwise. - bool mIsNetworkKeyPresent : 1; ///< TRUE if Network Key is present, FALSE otherwise. - bool mIsNetworkNamePresent : 1; ///< TRUE if Network Name is present, FALSE otherwise. - bool mIsExtendedPanIdPresent : 1; ///< TRUE if Extended PAN ID is present, FALSE otherwise. - bool mIsMeshLocalPrefixPresent : 1; ///< TRUE if Mesh Local Prefix is present, FALSE otherwise. - bool mIsDelayPresent : 1; ///< TRUE if Delay Timer is present, FALSE otherwise. - bool mIsPanIdPresent : 1; ///< TRUE if PAN ID is present, FALSE otherwise. - bool mIsChannelPresent : 1; ///< TRUE if Channel is present, FALSE otherwise. - bool mIsPskcPresent : 1; ///< TRUE if PSKc is present, FALSE otherwise. - bool mIsSecurityPolicyPresent : 1; ///< TRUE if Security Policy is present, FALSE otherwise. - bool mIsChannelMaskPresent : 1; ///< TRUE if Channel Mask is present, FALSE otherwise. + bool mIsActiveTimestampPresent; ///< TRUE if Active Timestamp is present, FALSE otherwise. + bool mIsPendingTimestampPresent; ///< TRUE if Pending Timestamp is present, FALSE otherwise. + bool mIsNetworkKeyPresent; ///< TRUE if Network Key is present, FALSE otherwise. + bool mIsNetworkNamePresent; ///< TRUE if Network Name is present, FALSE otherwise. + bool mIsExtendedPanIdPresent; ///< TRUE if Extended PAN ID is present, FALSE otherwise. + bool mIsMeshLocalPrefixPresent; ///< TRUE if Mesh Local Prefix is present, FALSE otherwise. + bool mIsDelayPresent; ///< TRUE if Delay Timer is present, FALSE otherwise. + bool mIsPanIdPresent; ///< TRUE if PAN ID is present, FALSE otherwise. + bool mIsChannelPresent; ///< TRUE if Channel is present, FALSE otherwise. + bool mIsPskcPresent; ///< TRUE if PSKc is present, FALSE otherwise. + bool mIsSecurityPolicyPresent; ///< TRUE if Security Policy is present, FALSE otherwise. + bool mIsChannelMaskPresent; ///< TRUE if Channel Mask is present, FALSE otherwise. } otOperationalDatasetComponents; /** diff --git a/third_party/openthread/repo/include/openthread/instance.h b/third_party/openthread/repo/include/openthread/instance.h index a92a6b53..03f5c623 100644 --- a/third_party/openthread/repo/include/openthread/instance.h +++ b/third_party/openthread/repo/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (342) +#define OPENTHREAD_API_VERSION (370) /** * @addtogroup api-instance @@ -255,6 +255,20 @@ void otRemoveStateChangeCallback(otInstance *aInstance, otStateChangedCallback a */ void otInstanceReset(otInstance *aInstance); +/** + * Triggers a platform reset to bootloader mode, if supported. + * + * Requires `OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE`. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @retval OT_ERROR_NONE Reset to bootloader successfully. + * @retval OT_ERROR_BUSY Failed due to another operation is ongoing. + * @retval OT_ERROR_NOT_CAPABLE Not capable of resetting to bootloader. + * + */ +otError otInstanceResetToBootloader(otInstance *aInstance); + /** * Deletes all the settings stored on non-volatile memory, and then triggers a platform reset. * diff --git a/third_party/openthread/repo/include/openthread/ip6.h b/third_party/openthread/repo/include/openthread/ip6.h index e34205f4..850c64c6 100644 --- a/third_party/openthread/repo/include/openthread/ip6.h +++ b/third_party/openthread/repo/include/openthread/ip6.h @@ -144,6 +144,8 @@ struct otIp6Address typedef struct otIp6Address otIp6Address; /** + * @struct otIp6Prefix + * * Represents an IPv6 prefix. * */ @@ -178,15 +180,16 @@ enum */ typedef struct otNetifAddress { - otIp6Address mAddress; ///< The IPv6 unicast address. - uint8_t mPrefixLength; ///< The Prefix length (in bits). - uint8_t mAddressOrigin; ///< The IPv6 address origin. - bool mPreferred : 1; ///< TRUE if the address is preferred, FALSE otherwise. - bool mValid : 1; ///< TRUE if the address is valid, FALSE otherwise. - bool mScopeOverrideValid : 1; ///< TRUE if the mScopeOverride value is valid, FALSE otherwise. - unsigned int mScopeOverride : 4; ///< The IPv6 scope of this address. - bool mRloc : 1; ///< TRUE if the address is an RLOC, FALSE otherwise. - struct otNetifAddress *mNext; ///< A pointer to the next network interface address. + otIp6Address mAddress; ///< The IPv6 unicast address. + uint8_t mPrefixLength; ///< The Prefix length (in bits). + uint8_t mAddressOrigin; ///< The IPv6 address origin. + bool mPreferred : 1; ///< TRUE if the address is preferred, FALSE otherwise. + bool mValid : 1; ///< TRUE if the address is valid, FALSE otherwise. + bool mScopeOverrideValid : 1; ///< TRUE if the mScopeOverride value is valid, FALSE otherwise. + unsigned int mScopeOverride : 4; ///< The IPv6 scope of this address. + bool mRloc : 1; ///< TRUE if the address is an RLOC, FALSE otherwise. + bool mMeshLocal : 1; ///< TRUE if the address is mesh-local, FALSE otherwise. + const struct otNetifAddress *mNext; ///< A pointer to the next network interface address. } otNetifAddress; /** @@ -296,6 +299,7 @@ bool otIp6IsEnabled(otInstance *aInstance); * @retval OT_ERROR_NONE Successfully added (or updated) the Network Interface Address. * @retval OT_ERROR_INVALID_ARGS The IP Address indicated by @p aAddress is an internal address. * @retval OT_ERROR_NO_BUFS The Network Interface is already storing the maximum allowed external addresses. + * */ otError otIp6AddUnicastAddress(otInstance *aInstance, const otNetifAddress *aAddress); @@ -308,6 +312,7 @@ otError otIp6AddUnicastAddress(otInstance *aInstance, const otNetifAddress *aAdd * @retval OT_ERROR_NONE Successfully removed the Network Interface Address. * @retval OT_ERROR_INVALID_ARGS The IP Address indicated by @p aAddress is an internal address. * @retval OT_ERROR_NOT_FOUND The IP Address indicated by @p aAddress was not found. + * */ otError otIp6RemoveUnicastAddress(otInstance *aInstance, const otIp6Address *aAddress); @@ -317,9 +322,22 @@ otError otIp6RemoveUnicastAddress(otInstance *aInstance, const otIp6Address *aAd * @param[in] aInstance A pointer to an OpenThread instance. * * @returns A pointer to the first Network Interface Address. + * */ const otNetifAddress *otIp6GetUnicastAddresses(otInstance *aInstance); +/** + * Indicates whether or not a unicast IPv6 address is assigned to the Thread interface. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aAddress A pointer to the unicast address. + * + * @retval TRUE If @p aAddress is assigned to the Thread interface. + * @retval FALSE If @p aAddress is not assigned to the Thread interface. + * + */ +bool otIp6HasUnicastAddress(otInstance *aInstance, const otIp6Address *aAddress); + /** * Subscribes the Thread interface to a Network Interface Multicast Address. * @@ -450,8 +468,6 @@ typedef void (*otIp6ReceiveCallback)(otMessage *aMessage, void *aContext); void otIp6SetReceiveCallback(otInstance *aInstance, otIp6ReceiveCallback aCallback, void *aCallbackContext); /** - * @struct otIp6AddressInfo - * * Represents IPv6 address information. * */ @@ -527,6 +543,8 @@ void otIp6SetReceiveFilterEnabled(otInstance *aInstance, bool aEnabled); * @retval OT_ERROR_NO_ROUTE No route to host. * @retval OT_ERROR_INVALID_SOURCE_ADDRESS Source address is invalid, e.g. an anycast address or a multicast address. * @retval OT_ERROR_PARSE Encountered a malformed header when processing the message. + * @retval OT_ERROR_INVALID_ARGS The message's metadata is invalid, e.g. the message uses + * `OT_MESSAGE_ORIGIN_THREAD_NETIF` as the origin. * */ otError otIp6Send(otInstance *aInstance, otMessage *aMessage); @@ -847,7 +865,7 @@ otError otIp6RegisterMulticastListeners(otInstance * /** * Sets the Mesh Local IID (for test purpose). * - * `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` must be enabled. + * Requires `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE`. * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aIid A pointer to the Mesh Local IID to set. diff --git a/third_party/openthread/repo/include/openthread/joiner.h b/third_party/openthread/repo/include/openthread/joiner.h index dc4b09c8..7b896845 100644 --- a/third_party/openthread/repo/include/openthread/joiner.h +++ b/third_party/openthread/repo/include/openthread/joiner.h @@ -135,12 +135,7 @@ void otJoinerStop(otInstance *aInstance); * * @param[in] aInstance A pointer to an OpenThread instance. * - * @retval OT_JOINER_STATE_IDLE - * @retval OT_JOINER_STATE_DISCOVER - * @retval OT_JOINER_STATE_CONNECT - * @retval OT_JOINER_STATE_CONNECTED - * @retval OT_JOINER_STATE_ENTRUST - * @retval OT_JOINER_STATE_JOINED + * @returns The joiner state. * */ otJoinerState otJoinerGetState(otInstance *aInstance); diff --git a/third_party/openthread/repo/include/openthread/link.h b/third_party/openthread/repo/include/openthread/link.h index 933098c7..f4d203e7 100644 --- a/third_party/openthread/repo/include/openthread/link.h +++ b/third_party/openthread/repo/include/openthread/link.h @@ -714,7 +714,7 @@ void otLinkSetMaxFrameRetriesIndirect(otInstance *aInstance, uint8_t aMaxFrameRe /** * Gets the address mode of MAC filter. * - * Is available when OPENTHREAD_CONFIG_MAC_FILTER_ENABLE configuration is enabled. + * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * * @param[in] aInstance A pointer to an OpenThread instance. * @@ -726,7 +726,7 @@ otMacFilterAddressMode otLinkFilterGetAddressMode(otInstance *aInstance); /** * Sets the address mode of MAC filter. * - * Is available when OPENTHREAD_CONFIG_MAC_FILTER_ENABLE configuration is enabled. + * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aMode The address mode to set. @@ -737,7 +737,7 @@ void otLinkFilterSetAddressMode(otInstance *aInstance, otMacFilterAddressMode aM /** * Adds an Extended Address to MAC filter. * - * Is available when OPENTHREAD_CONFIG_MAC_FILTER_ENABLE configuration is enabled. + * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aExtAddress A pointer to the Extended Address (MUST NOT be NULL). @@ -751,7 +751,7 @@ otError otLinkFilterAddAddress(otInstance *aInstance, const otExtAddress *aExtAd /** * Removes an Extended Address from MAC filter. * - * Is available when OPENTHREAD_CONFIG_MAC_FILTER_ENABLE configuration is enabled. + * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * * No action is performed if there is no existing entry in Filter matching the given Extended Address. * @@ -764,7 +764,7 @@ void otLinkFilterRemoveAddress(otInstance *aInstance, const otExtAddress *aExtAd /** * Clears all the Extended Addresses from MAC filter. * - * Is available when OPENTHREAD_CONFIG_MAC_FILTER_ENABLE configuration is enabled. + * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * * @param[in] aInstance A pointer to an OpenThread instance. * @@ -774,7 +774,7 @@ void otLinkFilterClearAddresses(otInstance *aInstance); /** * Gets an in-use address filter entry. * - * Is available when OPENTHREAD_CONFIG_MAC_FILTER_ENABLE configuration is enabled. + * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in,out] aIterator A pointer to the MAC filter iterator context. To get the first in-use address filter @@ -788,10 +788,14 @@ void otLinkFilterClearAddresses(otInstance *aInstance); otError otLinkFilterGetNextAddress(otInstance *aInstance, otMacFilterIterator *aIterator, otMacFilterEntry *aEntry); /** - * Adds a fixed received signal strength (in dBm) entry for the messages from a given Extended Address in - * MAC Filter. + * Adds the specified Extended Address to the `RssIn` list (or modifies an existing + * address in the `RssIn` list) and sets the received signal strength (in dBm) entry + * for messages from that address. The Extended Address does not necessarily have + * to be in the `address allowlist/denylist` filter to set the `rss`. + * @note The `RssIn` list contains Extended Addresses whose `rss` or link quality indicator (`lqi`) + * values have been set to be different from the defaults. * - * Is available when OPENTHREAD_CONFIG_MAC_FILTER_ENABLE configuration is enabled. + * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aExtAddress A pointer to the IEEE 802.15.4 Extended Address. MUST NOT be NULL. @@ -804,11 +808,14 @@ otError otLinkFilterGetNextAddress(otInstance *aInstance, otMacFilterIterator *a otError otLinkFilterAddRssIn(otInstance *aInstance, const otExtAddress *aExtAddress, int8_t aRss); /** - * Removes a MAC Filter entry for fixed received signal strength setting for a given Extended Address. + * Removes the specified Extended Address from the `RssIn` list. Once removed + * from the `RssIn` list, this MAC address will instead use the default `rss` + * and `lqi` settings, assuming defaults have been set. + * (If no defaults have been set, the over-air signal is used.) * - * Is available when OPENTHREAD_CONFIG_MAC_FILTER_ENABLE configuration is enabled. + * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * - * No action is performed if there is no existing entry in Filter matching the given Extended Address. + * No action is performed if there is no existing entry in the `RssIn` list matching the specified Extended Address. * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aExtAddress A pointer to the IEEE 802.15.4 Extended Address. MUST NOT be NULL. @@ -819,7 +826,7 @@ void otLinkFilterRemoveRssIn(otInstance *aInstance, const otExtAddress *aExtAddr /** * Sets the default received signal strength (in dBm) on MAC Filter. * - * Is available when OPENTHREAD_CONFIG_MAC_FILTER_ENABLE configuration is enabled. + * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * * The default RSS value is used for all received frames from addresses for which there is no explicit RSS-IN entry * in the Filter list (added using `otLinkFilterAddRssIn()`). @@ -833,7 +840,7 @@ void otLinkFilterSetDefaultRssIn(otInstance *aInstance, int8_t aRss); /** * Clears any previously set default received signal strength (in dBm) on MAC Filter. * - * Is available when OPENTHREAD_CONFIG_MAC_FILTER_ENABLE configuration is enabled. + * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * * @param[in] aInstance A pointer to an OpenThread instance. * @@ -841,9 +848,11 @@ void otLinkFilterSetDefaultRssIn(otInstance *aInstance, int8_t aRss); void otLinkFilterClearDefaultRssIn(otInstance *aInstance); /** - * Clears all the received signal strength entries (including default RSS-in) on MAC Filter. + * Clears all the received signal strength (`rss`) and link quality + * indicator (`lqi`) entries (including defaults) from the `RssIn` list. + * Performing this action means that all Extended Addresses will use the on-air signal. * - * Is available when OPENTHREAD_CONFIG_MAC_FILTER_ENABLE configuration is enabled. + * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * * @param[in] aInstance A pointer to an OpenThread instance. * @@ -853,7 +862,7 @@ void otLinkFilterClearAllRssIn(otInstance *aInstance); /** * Gets an in-use RssIn filter entry. * - * Is available when OPENTHREAD_CONFIG_MAC_FILTER_ENABLE configuration is enabled. + * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in,out] aIterator A pointer to the MAC filter iterator context. MUST NOT be NULL. @@ -871,7 +880,7 @@ otError otLinkFilterGetNextRssIn(otInstance *aInstance, otMacFilterIterator *aIt /** * Enables/disables IEEE 802.15.4 radio filter mode. * - * Is available when OPENTHREAD_CONFIG_MAC_FILTER_ENABLE configuration is enabled. + * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * * The radio filter is mainly intended for testing. It can be used to temporarily block all tx/rx on the 802.15.4 radio. * When radio filter is enabled, radio is put to sleep instead of receive (to ensure device does not receive any frame @@ -887,7 +896,7 @@ void otLinkSetRadioFilterEnabled(otInstance *aInstance, bool aFilterEnabled); /** * Indicates whether the IEEE 802.15.4 radio filter is enabled or not. * - * Is available when OPENTHREAD_CONFIG_MAC_FILTER_ENABLE configuration is enabled. + * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * * @retval TRUE If the radio filter is enabled. * @retval FALSE If the radio filter is disabled. @@ -1031,7 +1040,7 @@ otError otLinkSetPromiscuous(otInstance *aInstance, bool aPromiscuous); * @returns The CSL channel. * */ -uint8_t otLinkCslGetChannel(otInstance *aInstance); +uint8_t otLinkGetCslChannel(otInstance *aInstance); /** * Sets the CSL channel. @@ -1044,29 +1053,40 @@ uint8_t otLinkCslGetChannel(otInstance *aInstance); * @retval OT_ERROR_INVALID_ARGS Invalid @p aChannel. * */ -otError otLinkCslSetChannel(otInstance *aInstance, uint8_t aChannel); +otError otLinkSetCslChannel(otInstance *aInstance, uint8_t aChannel); + +/** + * Represents CSL period ten symbols unit in microseconds. + * + * The CSL period (in micro seconds) MUST be a multiple of this value. + * + */ +#define OT_LINK_CSL_PERIOD_TEN_SYMBOLS_UNIT_IN_USEC (160) /** - * Gets the CSL period. + * Gets the CSL period in microseconds * * @param[in] aInstance A pointer to an OpenThread instance. * - * @returns The CSL period in units of 10 symbols. + * @returns The CSL period in microseconds. * */ -uint16_t otLinkCslGetPeriod(otInstance *aInstance); +uint32_t otLinkGetCslPeriod(otInstance *aInstance); /** - * Sets the CSL period in units of 10 symbols. Disable CSL by setting this parameter to `0`. + * Sets the CSL period in microseconds. Disable CSL by setting this parameter to `0`. + * + * The CSL period MUST be a multiple of `OT_LINK_CSL_PERIOD_TEN_SYMBOLS_UNIT_IN_USEC`, otherwise `OT_ERROR_INVALID_ARGS` + * is returned. * * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aPeriod The CSL period in units of 10 symbols. + * @param[in] aPeriod The CSL period in microseconds. * * @retval OT_ERROR_NONE Successfully set the CSL period. - * @retval OT_ERROR_INVALID_ARGS Invalid CSL period. + * @retval OT_ERROR_INVALID_ARGS Invalid CSL period * */ -otError otLinkCslSetPeriod(otInstance *aInstance, uint16_t aPeriod); +otError otLinkSetCslPeriod(otInstance *aInstance, uint32_t aPeriod); /** * Gets the CSL timeout. @@ -1076,7 +1096,7 @@ otError otLinkCslSetPeriod(otInstance *aInstance, uint16_t aPeriod); * @returns The CSL timeout in seconds. * */ -uint32_t otLinkCslGetTimeout(otInstance *aInstance); +uint32_t otLinkGetCslTimeout(otInstance *aInstance); /** * Sets the CSL timeout in seconds. @@ -1088,7 +1108,7 @@ uint32_t otLinkCslGetTimeout(otInstance *aInstance); * @retval OT_ERROR_INVALID_ARGS Invalid CSL timeout. * */ -otError otLinkCslSetTimeout(otInstance *aInstance, uint32_t aTimeout); +otError otLinkSetCslTimeout(otInstance *aInstance, uint32_t aTimeout); /** * Returns the current CCA (Clear Channel Assessment) failure rate. @@ -1162,6 +1182,39 @@ bool otLinkIsCslSupported(otInstance *aInstance); */ otError otLinkSendEmptyData(otInstance *aInstance); +/** + * Sets the region code. + * + * The radio region format is the 2-bytes ascii representation of the ISO 3166 alpha-2 code. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aRegionCode The radio region code. The `aRegionCode >> 8` is first ascii char + * and the `aRegionCode & 0xff` is the second ascii char. + * + * @retval OT_ERROR_FAILED Other platform specific errors. + * @retval OT_ERROR_NONE Successfully set region code. + * @retval OT_ERROR_NOT_IMPLEMENTED The feature is not implemented. + * + */ +otError otLinkSetRegion(otInstance *aInstance, uint16_t aRegionCode); + +/** + * Get the region code. + * + * The radio region format is the 2-bytes ascii representation of the ISO 3166 alpha-2 code. + + * @param[in] aInstance The OpenThread instance structure. + * @param[out] aRegionCode The radio region code. The `aRegionCode >> 8` is first ascii char + * and the `aRegionCode & 0xff` is the second ascii char. + * + * @retval OT_ERROR_INVALID_ARGS @p aRegionCode is nullptr. + * @retval OT_ERROR_FAILED Other platform specific errors. + * @retval OT_ERROR_NONE Successfully got region code. + * @retval OT_ERROR_NOT_IMPLEMENTED The feature is not implemented. + * + */ +otError otLinkGetRegion(otInstance *aInstance, uint16_t *aRegionCode); + /** * @} * diff --git a/third_party/openthread/repo/include/openthread/link_metrics.h b/third_party/openthread/repo/include/openthread/link_metrics.h index f5813fc9..3b6a76ac 100644 --- a/third_party/openthread/repo/include/openthread/link_metrics.h +++ b/third_party/openthread/repo/include/openthread/link_metrics.h @@ -35,8 +35,6 @@ #ifndef LINK_METRICS_H_ #define LINK_METRICS_H_ -#include "openthread-core-config.h" - #include #include #include @@ -118,7 +116,7 @@ typedef enum otLinkMetricsStatus */ typedef void (*otLinkMetricsReportCallback)(const otIp6Address *aSource, const otLinkMetricsValues *aMetricsValues, - uint8_t aStatus, + otLinkMetricsStatus aStatus, void *aContext); /** * Pointer is called when a Link Metrics Management Response is received. @@ -128,7 +126,9 @@ typedef void (*otLinkMetricsReportCallback)(const otIp6Address *aSource, * @param[in] aContext A pointer to application-specific context. * */ -typedef void (*otLinkMetricsMgmtResponseCallback)(const otIp6Address *aSource, uint8_t aStatus, void *aContext); +typedef void (*otLinkMetricsMgmtResponseCallback)(const otIp6Address *aSource, + otLinkMetricsStatus aStatus, + void *aContext); /** * Pointer is called when Enh-ACK Probing IE is received. @@ -247,6 +247,31 @@ otError otLinkMetricsSendLinkProbe(otInstance *aInstance, uint8_t aSeriesId, uint8_t aLength); +/** + * Enable or disable Link Metrics Manager. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aEnable A boolean indicating to enable or disable. + * + */ +void otLinkMetricsManagerSetEnabled(otInstance *aInstance, bool aEnable); + +/** + * Get Link Metrics data of a neighbor by its extended address. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aExtAddress A pointer to the Mac extended address of the Probing Subject. + * @param[out] aLinkMetricsValues A pointer to the Link Metrics values of the subject. + * + * @retval OT_ERROR_NONE Successfully got the Link Metrics data. + * @retval OT_ERROR_INVALID_ARGS The arguments are invalid. + * @retval OT_ERROR_NOT_FOUND No neighbor with the given extended address is found. + * + */ +otError otLinkMetricsManagerGetMetricsValueByExtAddr(otInstance *aInstance, + const otExtAddress *aExtAddress, + otLinkMetricsValues *aLinkMetricsValues); + /** * @} * diff --git a/third_party/openthread/repo/include/openthread/logging.h b/third_party/openthread/repo/include/openthread/logging.h index 143a0d51..c0fb6100 100644 --- a/third_party/openthread/repo/include/openthread/logging.h +++ b/third_party/openthread/repo/include/openthread/logging.h @@ -201,6 +201,45 @@ void otDumpInfoPlat(const char *aText, const void *aData, uint16_t aDataLength); */ void otDumpDebgPlat(const char *aText, const void *aData, uint16_t aDataLength); +/** + * Emits a log message at given log level using a platform module name. + * + * This is is intended for use by platform. If `OPENTHREAD_CONFIG_LOG_PLATFORM` is not set or the current log + * level is below @p aLogLevel , this function does not emit any log message. + * + * The @p aPlatModuleName name is used to determine the log module name in the emitted log message, following the + * `P-{PlatModuleName}---` format. This means that the prefix string "P-" is added to indicate that this is a platform + * sub-module, followed by the next 12 characters of the @p PlatModuleName string, with padded hyphens `-` at the end + * to ensure that the region name is 14 characters long. + + * @param[in] aLogLevel The log level. + * @param[in] aPlatModuleName The platform sub-module name. + * @param[in] aFormat The format string. + * @param[in] ... Arguments for the format specification. + * + */ +void otLogPlat(otLogLevel aLogLevel, const char *aPlatModuleName, const char *aFormat, ...) + OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(3, 4); + +/** + * Emits a log message at given log level using a platform module name. + * + * This is is intended for use by platform. If `OPENTHREAD_CONFIG_LOG_PLATFORM` is not set or the current log + * level is below @p aLogLevel , this function does not emit any log message. + * + * The @p aPlatModuleName name is used to determine the log module name in the emitted log message, following the + * `P-{PlatModuleName}---` format. This means that the prefix string "P-" is added to indicate that this is a platform + * sub-module, followed by the next 12 characters of the @p PlatModuleName string, with padded hyphens `-` at the end + * to ensure that the region name is 14 characters long. + * + * @param[in] aLogLevel The log level. + * @param[in] aPlatModuleName The platform sub-module name. + * @param[in] aFormat The format string. + * @param[in] aArgs Arguments for the format specification. + * + */ +void otLogPlatArgs(otLogLevel aLogLevel, const char *aPlatModuleName, const char *aFormat, va_list aArgs); + /** * Emits a log message at a given log level. * @@ -214,6 +253,45 @@ void otDumpDebgPlat(const char *aText, const void *aData, uint16_t aDataLength); */ void otLogCli(otLogLevel aLogLevel, const char *aFormat, ...) OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(2, 3); +#define OT_LOG_HEX_DUMP_LINE_SIZE 73 ///< Hex dump line string size. + +/** + * Represents information used for generating hex dump output. + * + */ +typedef struct +{ + const uint8_t *mDataBytes; ///< The data byes. + uint16_t mDataLength; ///< The data length (number of bytes in @p mDataBytes) + const char *mTitle; ///< Title string to add table header (MUST NOT be `NULL`). + char mLine[OT_LOG_HEX_DUMP_LINE_SIZE]; ///< Buffer to output one line of generated hex dump. + uint16_t mIterator; ///< Iterator used by OT stack. MUST be initialized to zero. +} otLogHexDumpInfo; + +/** + * Generates the next hex dump line. + * + * Can call this method back-to-back to generate the hex dump output line by line. On the first call the `mIterator` + * field in @p aInfo MUST be set to zero. + * + * Here is an example of the generated hex dump output: + * + * "==========================[{mTitle} len=070]============================" + * "| 41 D8 87 34 12 FF FF 25 | 4C 57 DA F2 FB 2F 62 7F | A..4...%LW.../b. |" + * "| 3B 01 F0 4D 4C 4D 4C 54 | 4F 00 15 15 00 00 00 00 | ;..MLMLTO....... |" + * "| 00 00 00 01 80 DB 60 82 | 7E 33 72 3B CC B3 A1 84 | ......`.~3r;.... |" + * "| 3B E6 AD B2 0B 45 E7 45 | C5 B9 00 1A CB 2D 6D 1C | ;....E.E.....-m. |" + * "| 10 3E 3C F5 D3 70 | | .><..p |" + * "------------------------------------------------------------------------" + * + * @param[in,out] aInfo A pointer to `otLogHexDumpInfo` to use to generate hex dump. + * + * @retval OT_ERROR_NONE Successfully generated the next line, `mLine` field in @p aInfo is updated. + * @retval OT_ERROR_NOT_FOUND Reached the end and no more line to generate. + * + */ +otError otLogGenerateNextHexDumpLine(otLogHexDumpInfo *aInfo); + /** * @} * diff --git a/third_party/openthread/repo/include/openthread/message.h b/third_party/openthread/repo/include/openthread/message.h index 6bdf5f1b..99dc49cf 100644 --- a/third_party/openthread/repo/include/openthread/message.h +++ b/third_party/openthread/repo/include/openthread/message.h @@ -69,6 +69,17 @@ typedef enum otMessagePriority OT_MESSAGE_PRIORITY_HIGH = 2, ///< High priority level. } otMessagePriority; +/** + * Defines the OpenThread message origins. + * + */ +typedef enum otMessageOrigin +{ + OT_MESSAGE_ORIGIN_THREAD_NETIF = 0, ///< Message from Thread Netif. + OT_MESSAGE_ORIGIN_HOST_TRUSTED = 1, ///< Message from a trusted source on host. + OT_MESSAGE_ORIGIN_HOST_UNTRUSTED = 2, ///< Message from an untrusted source on host. +} otMessageOrigin; + /** * Represents a message settings. * @@ -180,6 +191,45 @@ void otMessageSetOffset(otMessage *aMessage, uint16_t aOffset); */ bool otMessageIsLinkSecurityEnabled(const otMessage *aMessage); +/** + * Indicates whether or not the message is allowed to be looped back to host. + * + * @param[in] aMessage A pointer to a message buffer. + * + * @retval TRUE If the message is allowed to be looped back to host. + * @retval FALSE If the message is not allowed to be looped back to host. + * + */ +bool otMessageIsLoopbackToHostAllowed(const otMessage *aMessage); + +/** + * Sets whether or not the message is allowed to be looped back to host. + * + * @param[in] aMessage A pointer to a message buffer. + * @param[in] aAllowLoopbackToHost Whether to allow the message to be looped back to host. + * + */ +void otMessageSetLoopbackToHostAllowed(otMessage *aMessage, bool aAllowLoopbackToHost); + +/** + * Gets the message origin. + * + * @param[in] aMessage A pointer to a message buffer. + * + * @returns The message origin. + * + */ +otMessageOrigin otMessageGetOrigin(const otMessage *aMessage); + +/** + * Sets the message origin. + * + * @param[in] aMessage A pointer to a message buffer. + * @param[in] aOrigin The message origin. + * + */ +void otMessageSetOrigin(otMessage *aMessage, otMessageOrigin aOrigin); + /** * Sets/forces the message to be forwarded using direct transmission. * Default setting for a new message is `false`. diff --git a/third_party/openthread/repo/include/openthread/nat64.h b/third_party/openthread/repo/include/openthread/nat64.h index 1e69da6e..930c4c34 100644 --- a/third_party/openthread/repo/include/openthread/nat64.h +++ b/third_party/openthread/repo/include/openthread/nat64.h @@ -291,7 +291,7 @@ otNat64State otNat64GetPrefixManagerState(otInstance *aInstance); * @sa otNat64GetPrefixManagerState * */ -void otNat64SetEnabled(otInstance *aInstance, bool aEnable); +void otNat64SetEnabled(otInstance *aInstance, bool aEnabled); /** * Allocate a new message buffer for sending an IPv4 message to the NAT64 translator. @@ -374,7 +374,7 @@ typedef void (*otNat64ReceiveIp4Callback)(otMessage *aMessage, void *aContext); * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aCallback A pointer to a function that is called when an IPv4 datagram is received or * NULL to disable the callback. - * @param[in] aCallbackContext A pointer to application-specific context. + * @param[in] aContext A pointer to application-specific context. * */ void otNat64SetReceiveIp4Callback(otInstance *aInstance, otNat64ReceiveIp4Callback aCallback, void *aContext); diff --git a/third_party/openthread/repo/include/openthread/netdata.h b/third_party/openthread/repo/include/openthread/netdata.h index ea1791e9..08bf504a 100644 --- a/third_party/openthread/repo/include/openthread/netdata.h +++ b/third_party/openthread/repo/include/openthread/netdata.h @@ -35,6 +35,7 @@ #ifndef OPENTHREAD_NETDATA_H_ #define OPENTHREAD_NETDATA_H_ +#include #include #ifdef __cplusplus @@ -94,6 +95,7 @@ typedef struct otExternalRouteConfig bool mNat64 : 1; ///< Whether this is a NAT64 prefix. bool mStable : 1; ///< Whether this configuration is considered Stable Network Data. bool mNextHopIsThisDevice : 1; ///< Whether the next hop is this device (value ignored on config add). + bool mAdvPio : 1; ///< Whether or not BR is advertising a ULA prefix in PIO (AP flag). } otExternalRouteConfig; /** @@ -241,6 +243,15 @@ otError otNetDataGetNextLowpanContextInfo(otInstance *aInstance, otNetworkDataIterator *aIterator, otLowpanContextInfo *aContextInfo); +/** + * Gets the Commissioning Dataset from the partition's Network Data. + * + * @param[in] aInstance A pointer to the OpenThread instance. + * @param[out] aDataset A pointer to a `otCommissioningDataset` to populate. + * + */ +void otNetDataGetCommissioningDataset(otInstance *aInstance, otCommissioningDataset *aDataset); + /** * Get the Network Data Version. * diff --git a/third_party/openthread/repo/include/openthread/netdata_publisher.h b/third_party/openthread/repo/include/openthread/netdata_publisher.h index 60df1f65..21a93452 100644 --- a/third_party/openthread/repo/include/openthread/netdata_publisher.h +++ b/third_party/openthread/repo/include/openthread/netdata_publisher.h @@ -258,9 +258,9 @@ otError otNetDataPublishExternalRoute(otInstance *aInstance, const otExternalRou * Data (monitoring the Network Data to determine when/if to add the prefix, depending on the number of similar * prefixes present in the Network Data). * + * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aPrefix The previously published external route prefix to replace. * @param[in] aConfig The external route config to publish. - * @param[in] aRequester The requester (`kFromUser` or `kFromRoutingManager` module). * * @retval OT_ERROR_NONE The external route is published successfully. * @retval OT_ERROR_INVALID_ARGS The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable). diff --git a/third_party/openthread/repo/include/openthread/ping_sender.h b/third_party/openthread/repo/include/openthread/ping_sender.h index 174cccc2..28b5f9a6 100644 --- a/third_party/openthread/repo/include/openthread/ping_sender.h +++ b/third_party/openthread/repo/include/openthread/ping_sender.h @@ -120,6 +120,7 @@ typedef struct otPingSenderConfig ///< Zero to use default. uint8_t mHopLimit; ///< Hop limit (used if `mAllowZeroHopLimit` is false). Zero for default. bool mAllowZeroHopLimit; ///< Indicates whether hop limit is zero. + bool mMulticastLoop; ///< Allow looping back pings to multicast address that device is subscribed to. } otPingSenderConfig; /** diff --git a/third_party/openthread/repo/include/openthread/platform/misc.h b/third_party/openthread/repo/include/openthread/platform/misc.h index 7fbee54b..b1b20211 100644 --- a/third_party/openthread/repo/include/openthread/platform/misc.h +++ b/third_party/openthread/repo/include/openthread/platform/misc.h @@ -61,6 +61,20 @@ extern "C" { */ void otPlatReset(otInstance *aInstance); +/** + * Performs a hardware reset on the platform to launch bootloader mode, if supported. + * + * Used when `OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE` is enabled. + * + * @param[in] aInstance The OpenThread instance structure. + * + * @retval OT_ERROR_NONE Reset to bootloader successfully. + * @retval OT_ERROR_BUSY Failed due to another operation is ongoing. + * @retval OT_ERROR_NOT_CAPABLE Not capable of resetting to bootloader. + * + */ +otError otPlatResetToBootloader(otInstance *aInstance); + /** * Enumeration of possible reset reason codes. * diff --git a/third_party/openthread/repo/include/openthread/platform/radio.h b/third_party/openthread/repo/include/openthread/platform/radio.h index 578f9946..2cae9855 100644 --- a/third_party/openthread/repo/include/openthread/platform/radio.h +++ b/third_party/openthread/repo/include/openthread/platform/radio.h @@ -287,10 +287,26 @@ typedef struct otRadioFrame */ struct { - const otMacKeyMaterial *mAesKey; ///< The key material used for AES-CCM frame security. - otRadioIeInfo *mIeInfo; ///< The pointer to the Header IE(s) related information. - uint32_t mTxDelay; ///< The delay time for this transmission (based on `mTxDelayBaseTime`). - uint32_t mTxDelayBaseTime; ///< The base time for the transmission delay. + const otMacKeyMaterial *mAesKey; ///< The key material used for AES-CCM frame security. + otRadioIeInfo *mIeInfo; ///< The pointer to the Header IE(s) related information. + + /** + * The base time in microseconds for scheduled transmissions + * relative to the local radio clock, see `otPlatRadioGetNow` and + * `mTxDelay`. + */ + uint32_t mTxDelayBaseTime; + + /** + * The delay time in microseconds for this transmission referenced + * to `mTxDelayBaseTime`. + * + * Note: `mTxDelayBaseTime` + `mTxDelay` SHALL point to the point in + * time when the end of the SFD will be present at the local + * antenna, relative to the local radio clock. + */ + uint32_t mTxDelay; + uint8_t mMaxCsmaBackoffs; ///< Maximum number of backoffs attempts before declaring CCA failure. uint8_t mMaxFrameRetries; ///< Maximum number of retries allowed after a transmission failure. @@ -349,10 +365,8 @@ typedef struct otRadioFrame struct { /** - * The timestamp when the frame was received in microseconds. - * - * The value SHALL be the time when the SFD was received. - * + * The time of the local radio clock in microseconds when the end of + * the SFD was present at the local antenna. */ uint64_t mTimestamp; @@ -669,14 +683,25 @@ void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCoun void otPlatRadioSetMacFrameCounterIfLarger(otInstance *aInstance, uint32_t aMacFrameCounter); /** - * Get the current estimated time (in microseconds) of the radio chip. + * Get the current time in microseconds referenced to a continuous monotonic + * local radio clock (64 bits width). + * + * The radio clock SHALL NOT wrap during the device's uptime. Implementations + * SHALL therefore identify and compensate for internal counter overflows. The + * clock does not have a defined epoch and it SHALL NOT introduce any continuous + * or discontinuous adjustments (e.g. leap seconds). Implementations SHALL + * compensate for any sleep times of the device. * - * This microsecond timer must be a free-running timer. The timer must continue to advance with microsecond precision - * even when the radio is in the sleep state. + * Implementations MAY choose to discipline the radio clock and compensate for + * sleep times by any means (e.g. by combining a high precision/low power RTC + * with a high resolution counter) as long as the exposed combined clock + * provides continuous monotonic microsecond resolution ticks within the + * accuracy limits announced by @ref otPlatRadioGetCslAccuracy. * * @param[in] aInstance A pointer to an OpenThread instance. * - * @returns The current time in microseconds. UINT64_MAX when platform does not support or radio time is not ready. + * @returns The current time in microseconds. UINT64_MAX when platform does not + * support or radio time is not ready. * */ uint64_t otPlatRadioGetNow(otInstance *aInstance); @@ -781,8 +806,17 @@ otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel); * Schedule a radio reception window at a specific time and duration. * * @param[in] aChannel The radio channel on which to receive. - * @param[in] aStart The receive window start time, in microseconds. - * @param[in] aDuration The receive window duration, in microseconds + * @param[in] aStart The receive window start time relative to the local + * radio clock, see `otPlatRadioGetNow`. The radio + * receiver SHALL be on and ready to receive the first + * symbol of a frame's SHR at the window start time. + * @param[in] aDuration The receive window duration, in microseconds, as + * measured by the local radio clock. The radio SHOULD be + * turned off (or switched to TX mode if an ACK frame + * needs to be sent) after that duration unless it is + * still actively receiving a frame. In the latter case + * the radio SHALL be kept in reception mode until frame + * reception has either succeeded or failed. * * @retval OT_ERROR_NONE Successfully scheduled receive window. * @retval OT_ERROR_FAILED The receive window could not be scheduled. @@ -1076,7 +1110,7 @@ otError otPlatRadioGetCoexMetrics(otInstance *aInstance, otRadioCoexMetrics *aCo * Enable or disable CSL receiver. * * @param[in] aInstance The OpenThread instance structure. - * @param[in] aCslPeriod CSL period, 0 for disabling CSL. + * @param[in] aCslPeriod CSL period, 0 for disabling CSL. CSL period is in unit of 10 symbols. * @param[in] aShortAddr The short source address of CSL receiver's peer. * @param[in] aExtAddr The extended source address of CSL receiver's peer. * @@ -1095,28 +1129,50 @@ otError otPlatRadioEnableCsl(otInstance *aInstance, /** * Update CSL sample time in radio driver. * - * Sample time is stored in radio driver as a copy to calculate phase when sending ACK with CSL IE. + * Sample time is stored in radio driver as a copy to calculate phase when + * sending ACK with CSL IE. The CSL sample (window) of the CSL receiver extends + * before and after the sample time. The CSL sample time marks a timestamp in + * the CSL sample window when a frame should be received in "ideal conditions" + * if there would be no inaccuracy/clock-drift. * * @param[in] aInstance The OpenThread instance structure. - * @param[in] aCslSampleTime The latest sample time. - * + * @param[in] aCslSampleTime The next sample time, in microseconds. It is + * the time when the first symbol of the MHR of + * the frame is expected. */ void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime); /** - * Get the current accuracy, in units of ± ppm, of the clock used for scheduling CSL operations. + * Get the current estimated worst case accuracy (maximum ± deviation from the + * nominal frequency) of the local radio clock in units of PPM. This is the + * clock used to schedule CSL operations. + * + * @note Implementations MAY estimate this value based on current operating + * conditions (e.g. temperature). * - * @note Platforms may optimize this value based on operational conditions (i.e.: temperature). + * In case the implementation does not estimate the current value but returns a + * fixed value, this value MUST be the worst-case accuracy over all possible + * foreseen operating conditions (temperature, pressure, etc) of the + * implementation. * * @param[in] aInstance A pointer to an OpenThread instance. * - * @returns The current CSL rx/tx scheduling drift, in units of ± ppm. + * @returns The current CSL rx/tx scheduling drift, in PPM. * */ uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance); /** - * The fixed uncertainty of the Device for scheduling CSL Transmissions in units of 10 microseconds. + * The fixed uncertainty (i.e. random jitter) of the arrival time of CSL + * transmissions received by this device in units of 10 microseconds. + * + * This designates the worst case constant positive or negative deviation of + * the actual arrival time of a transmission from the transmission time + * calculated relative to the local radio clock independent of elapsed time. In + * addition to uncertainty accumulated over elapsed time, the CSL channel sample + * ("RX window") must be extended by twice this deviation such that an actual + * transmission is guaranteed to be detected by the local receiver in the + * presence of random arrival time jitter. * * @param[in] aInstance A pointer to an OpenThread instance. * @@ -1147,7 +1203,8 @@ otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aCh * ISO 3166 alpha-2 code. * * @param[in] aInstance The OpenThread instance structure. - * @param[in] aRegionCode The radio region. + * @param[in] aRegionCode The radio region code. The `aRegionCode >> 8` is first ascii char + * and the `aRegionCode & 0xff` is the second ascii char. * * @retval OT_ERROR_FAILED Other platform specific errors. * @retval OT_ERROR_NONE Successfully set region code. diff --git a/third_party/openthread/repo/include/openthread/platform/time.h b/third_party/openthread/repo/include/openthread/platform/time.h index eecb34b8..1766cc55 100644 --- a/third_party/openthread/repo/include/openthread/platform/time.h +++ b/third_party/openthread/repo/include/openthread/platform/time.h @@ -52,7 +52,20 @@ extern "C" { */ /** - * Get the current time (64bits width). + * Get the current platform time in microseconds referenced to a continuous + * monotonic local clock (64 bits width). + * + * The clock SHALL NOT wrap during the device's uptime. Implementations SHALL + * therefore identify and compensate for internal counter overflows. The clock + * does not have a defined epoch and it SHALL NOT introduce any continuous or + * discontinuous adjustments (e.g. leap seconds). Implementations SHALL + * compensate for any sleep times of the device. + * + * Implementations MAY choose to discipline the platform clock and compensate + * for sleep times by any means (e.g. by combining a high precision/low power + * RTC with a high resolution counter) as long as the exposed combined clock + * provides continuous monotonic microsecond resolution ticks within the + * accuracy limits announced by @ref otPlatTimeGetXtalAccuracy. * * @returns The current time in microseconds. * @@ -60,9 +73,18 @@ extern "C" { uint64_t otPlatTimeGet(void); /** - * Get the device's XTAL accuracy. + * Get the current estimated worst case accuracy (maximum ± deviation from the + * nominal frequency) of the local platform clock in units of PPM. + * + * @note Implementations MAY estimate this value based on current operating + * conditions (e.g. temperature). + * + * In case the implementation does not estimate the current value but returns a + * fixed value, this value MUST be the worst-case accuracy over all possible + * foreseen operating conditions (temperature, pressure, etc) of the + * implementation. * - * @returns The device's XTAL accuracy, in ppm. + * @returns The current platform clock accuracy, in PPM. * */ uint16_t otPlatTimeGetXtalAccuracy(void); diff --git a/third_party/openthread/repo/include/openthread/radio_stats.h b/third_party/openthread/repo/include/openthread/radio_stats.h index f6877a90..2db394d7 100644 --- a/third_party/openthread/repo/include/openthread/radio_stats.h +++ b/third_party/openthread/repo/include/openthread/radio_stats.h @@ -47,6 +47,9 @@ extern "C" { /** * @addtogroup api-radio * + * @brief + * This module includes functions for radio statistics. + * * @{ * */ diff --git a/third_party/openthread/repo/include/openthread/random_crypto.h b/third_party/openthread/repo/include/openthread/random_crypto.h index 0c9dc582..94d3e617 100644 --- a/third_party/openthread/repo/include/openthread/random_crypto.h +++ b/third_party/openthread/repo/include/openthread/random_crypto.h @@ -37,7 +37,6 @@ #include -#include #include #ifdef __cplusplus diff --git a/third_party/openthread/repo/include/openthread/srp_server.h b/third_party/openthread/repo/include/openthread/srp_server.h index 4a37b461..8f45b084 100644 --- a/third_party/openthread/repo/include/openthread/srp_server.h +++ b/third_party/openthread/repo/include/openthread/srp_server.h @@ -73,64 +73,6 @@ typedef struct otSrpServerService otSrpServerService; */ typedef uint32_t otSrpServerServiceUpdateId; -/** - * The service flag type to indicate which services to include or exclude when searching in (or iterating over) the - * list of SRP services. - * - * This is a combination of bit-flags. The specific bit-flags are defined in the enumeration `OT_SRP_SERVER_FLAG_*`. - * - */ -typedef uint8_t otSrpServerServiceFlags; - -enum -{ - OT_SRP_SERVER_SERVICE_FLAG_BASE_TYPE = 1 << 0, ///< Include base services (not a sub-type). - OT_SRP_SERVER_SERVICE_FLAG_SUB_TYPE = 1 << 1, ///< Include sub-type services. - OT_SRP_SERVER_SERVICE_FLAG_ACTIVE = 1 << 2, ///< Include active (not deleted) services. - OT_SRP_SERVER_SERVICE_FLAG_DELETED = 1 << 3, ///< Include deleted services. -}; - -enum -{ - /** - * This constant defines an `otSrpServerServiceFlags` combination accepting any service (base/sub-type, - * active/deleted). - * - */ - OT_SRP_SERVER_FLAGS_ANY_SERVICE = (OT_SRP_SERVER_SERVICE_FLAG_BASE_TYPE | OT_SRP_SERVER_SERVICE_FLAG_SUB_TYPE | - OT_SRP_SERVER_SERVICE_FLAG_ACTIVE | OT_SRP_SERVER_SERVICE_FLAG_DELETED), - - /** - * This constant defines an `otSrpServerServiceFlags` combination accepting base service only. - * - */ - OT_SRP_SERVER_FLAGS_BASE_TYPE_SERVICE_ONLY = - (OT_SRP_SERVER_SERVICE_FLAG_BASE_TYPE | OT_SRP_SERVER_SERVICE_FLAG_ACTIVE | OT_SRP_SERVER_SERVICE_FLAG_DELETED), - - /** - * This constant defines an `otSrpServerServiceFlags` combination accepting sub-type service only. - * - */ - OT_SRP_SERVER_FLAGS_SUB_TYPE_SERVICE_ONLY = - (OT_SRP_SERVER_SERVICE_FLAG_SUB_TYPE | OT_SRP_SERVER_SERVICE_FLAG_ACTIVE | OT_SRP_SERVER_SERVICE_FLAG_DELETED), - - /** - * This constant defines an `otSrpServerServiceFlags` combination accepting any active service (not deleted). - * - */ - OT_SRP_SERVER_FLAGS_ANY_TYPE_ACTIVE_SERVICE = - (OT_SRP_SERVER_SERVICE_FLAG_BASE_TYPE | OT_SRP_SERVER_SERVICE_FLAG_SUB_TYPE | - OT_SRP_SERVER_SERVICE_FLAG_ACTIVE), - - /** - * This constant defines an `otSrpServerServiceFlags` combination accepting any deleted service. - * - */ - OT_SRP_SERVER_FLAGS_ANY_TYPE_DELETED_SERVICE = - (OT_SRP_SERVER_SERVICE_FLAG_BASE_TYPE | OT_SRP_SERVER_SERVICE_FLAG_SUB_TYPE | - OT_SRP_SERVER_SERVICE_FLAG_ACTIVE), -}; - /** * Represents the state of the SRP server. * @@ -505,6 +447,21 @@ bool otSrpServerHostIsDeleted(const otSrpServerHost *aHost); */ const char *otSrpServerHostGetFullName(const otSrpServerHost *aHost); +/** + * Indicates whether the host matches a given host name. + * + * DNS name matches are performed using a case-insensitive string comparison (i.e., "Abc" and "aBc" are considered to + * be the same). + * + * @param[in] aHost A pointer to the SRP service host. + * @param[in] aFullName A full host name. + * + * @retval TRUE If host matches the host name. + * @retval FALSE If host does not match the host name. + * + */ +bool otSrpServerHostMatchesFullName(const otSrpServerHost *aHost, const char *aFullName); + /** * Returns the addresses of given host. * @@ -526,10 +483,7 @@ const otIp6Address *otSrpServerHostGetAddresses(const otSrpServerHost *aHost, ui void otSrpServerHostGetLeaseInfo(const otSrpServerHost *aHost, otSrpServerLeaseInfo *aLeaseInfo); /** - * Returns the next service (excluding any sub-type services) of given host. - * - * @note This function is being deprecated and will be removed. `otSrpServerHostFindNextService()` can be used - * instead. + * Returns the next service of given host. * * @param[in] aHost A pointer to the SRP service host. * @param[in] aService A pointer to current SRP service instance; use NULL to get the first service. @@ -541,122 +495,133 @@ const otSrpServerService *otSrpServerHostGetNextService(const otSrpServerHost const otSrpServerService *aService); /** - * Finds the next matching service on the host. + * Indicates whether or not the SRP service has been deleted. * - * The combination of flags and service and instance names enables iterating over the full list of services and/or a - * subset of them matching certain conditions, or finding a specific service. + * A SRP service can be deleted but retains its name for future uses. + * In this case, the service instance is not removed from the SRP server/registry. + * It is guaranteed that all services are deleted if the host is deleted. * - * To iterate over all services of a host: - * service = otSrpServerHostFindNextService(host, service, OT_SRP_SERVER_FLAGS_ANY_SERVICE, NULL, NULL); + * @param[in] aService A pointer to the SRP service. * - * To iterate over base services only (exclude sub-types): - * service = otSrpServerHostFindNextService(host, service, OT_SRP_SERVER_FLAGS_BASE_TYPE_SERVICE_ONLY, NULL, NULL); + * @returns TRUE if the service has been deleted, FALSE if not. * - * To iterate over sub-types of a specific instance name `instanceName`: - * service = otSrpServerHostFindNextService(host, service, OT_SRP_SERVER_FLAGS_SUB_TYPE_SERVICE_ONLY, NULL, - * instanceName); + */ +bool otSrpServerServiceIsDeleted(const otSrpServerService *aService); + +/** + * Returns the full service instance name of the service. * - * To find a specific service with service name `serviceName` and service instance name `instanceName`: - * service = otSrpServerHostFindNextService(host, NULL, OT_SRP_SERVER_FLAGS_ANY_SERVICE, serviceName, instanceName); + * @param[in] aService A pointer to the SRP service. * - * To find the base type service with a given service instance name `instanceName`: - * service = otSrpServerHostFindNextService(host, NULL, OT_SRP_SERVER_FLAGS_BASE_TYPE_SERVICE_ONLY, NULL, - * instanceName); + * @returns A pointer to the null-terminated service instance name string. * - * @param[in] aHost A pointer to the SRP service host (MUST NOT be NULL). - * @param[in] aPrevService A pointer to the previous service or NULL to start from the beginning of the list. - * @param[in] aFlags Flags indicating which services to include (base/sub-type, active/deleted). - * @param[in] aServiceName The service name to match. Set to NULL to accept any name. - * @param[in] aInstanceName The service instance name to match. Set to NULL to accept any name. + */ +const char *otSrpServerServiceGetInstanceName(const otSrpServerService *aService); + +/** + * Indicates whether this service matches a given service instance name. + * + * DNS name matches are performed using a case-insensitive string comparison (i.e., "Abc" and "aBc" are considered to + * be the same). * - * @returns A pointer to the next matching service or NULL if no matching service could be found. + * @param[in] aService A pointer to the SRP service. + * @param[in] aInstanceName The service instance name. + * + * @retval TRUE If service matches the service instance name. + * @retval FALSE If service does not match the service instance name. * */ -const otSrpServerService *otSrpServerHostFindNextService(const otSrpServerHost *aHost, - const otSrpServerService *aPrevService, - otSrpServerServiceFlags aFlags, - const char *aServiceName, - const char *aInstanceName); +bool otSrpServerServiceMatchesInstanceName(const otSrpServerService *aService, const char *aInstanceName); /** - * Indicates whether or not the SRP service has been deleted. - * - * A SRP service can be deleted but retains its name for future uses. - * In this case, the service instance is not removed from the SRP server/registry. - * It is guaranteed that all services are deleted if the host is deleted. + * Returns the service instance label (first label in instance name) of the service. * * @param[in] aService A pointer to the SRP service. * - * @returns TRUE if the service has been deleted, FALSE if not. + * @returns A pointer to the null-terminated service instance label string.. * */ -bool otSrpServerServiceIsDeleted(const otSrpServerService *aService); +const char *otSrpServerServiceGetInstanceLabel(const otSrpServerService *aService); /** - * Indicates whether or not the SRP service is sub-type. + * Returns the full service name of the service. * * @param[in] aService A pointer to the SRP service. * - * @returns TRUE if the service is a sub-type, FALSE if not. + * @returns A pointer to the null-terminated service name string. * */ -bool otSrpServerServiceIsSubType(const otSrpServerService *aService); +const char *otSrpServerServiceGetServiceName(const otSrpServerService *aService); /** - * Returns the full service instance name of the service. + * Indicates whether this service matches a given service name. * - * @note This function is being deprecated and will be removed. `otSrpServerServiceGetInstanceName()` can be used - * instead. + * DNS name matches are performed using a case-insensitive string comparison (i.e., "Abc" and "aBc" are considered to + * be the same). * - * @param[in] aService A pointer to the SRP service. + * @param[in] aService A pointer to the SRP service. + * @param[in] aServiceName The service name. * - * @returns A pointer to the null-terminated service instance name string. + * @retval TRUE If service matches the service name. + * @retval FALSE If service does not match the service name. * */ -const char *otSrpServerServiceGetFullName(const otSrpServerService *aService); +bool otSrpServerServiceMatchesServiceName(const otSrpServerService *aService, const char *aServiceName); /** - * Returns the full service instance name of the service. + * Gets the number of sub-types of the service. * * @param[in] aService A pointer to the SRP service. * - * @returns A pointer to the null-terminated service instance name string. + * @returns The number of sub-types of @p aService. * */ -const char *otSrpServerServiceGetInstanceName(const otSrpServerService *aService); +uint16_t otSrpServerServiceGetNumberOfSubTypes(const otSrpServerService *aService); /** - * Returns the full service name of the service. + * Gets the sub-type service name (full name) of the service at a given index + * + * The full service name for a sub-type service follows "._sub...". * * @param[in] aService A pointer to the SRP service. + * @param[in] aIndex The index to get. * - * @returns A pointer to the null-terminated service name string. + * @returns A pointer to sub-type service name at @p aIndex, or `NULL` if no sub-type at this index. * */ -const char *otSrpServerServiceGetServiceName(const otSrpServerService *aService); +const char *otSrpServerServiceGetSubTypeServiceNameAt(const otSrpServerService *aService, uint16_t aIndex); /** - * Gets the sub-type label from service name. + * Indicates whether or not the service has a given sub-type. + * + * DNS name matches are performed using a case-insensitive string comparison (i.e., "Abc" and "aBc" are considered to + * be the same). + * + * @param[in] aService A pointer to the SRP service. + * @param[in] aSubTypeServiceName The sub-type service name (full name) to check. * - * Is intended to be used when the @p aService is a sub-type, i.e., `otSrpServerServiceIsSubType()` for - * the service returns TRUE. If it is not a sub-type this function returns `OT_ERROR_INVALID_ARGS`. + * @retval TRUE Service contains the sub-type @p aSubTypeServiceName. + * @retval FALSE Service does not contain the sub-type @p aSubTypeServiceName. * - * The full service name for a sub-type service follows "._sub...". This function - * copies the `` into the @p aLabel buffer. + */ +bool otSrpServerServiceHasSubTypeServiceName(const otSrpServerService *aService, const char *aSubTypeServiceName); + +/** + * Parses a sub-type service name (full name) and extracts the sub-type label. * - * The @p aLabel is ensured to always be null-terminated after returning even in case of failure. + * The full service name for a sub-type service follows "._sub...". * - * @param[in] aService A pointer to the SRP service. - * @param[out] aLabel A pointer to a buffer to copy the sub-type label name into. - * @param[in] aMaxSize Maximum size of @p aLabel buffer. + * @param[in] aSubTypeServiceName A sub-type service name (full name). + * @param[out] aLabel A pointer to a buffer to copy the extracted sub-type label. + * @param[in] aLabelSize Maximum size of @p aLabel buffer. * - * @retval OT_ERROR_NONE @p aLabel was updated successfully. + * @retval OT_ERROR_NONE Name was successfully parsed and @p aLabel was updated. * @retval OT_ERROR_NO_BUFS The sub-type label could not fit in @p aLabel buffer (number of chars from label * that could fit are copied in @p aLabel ensuring it is null-terminated). - * @retval OT_ERROR_INVALID_ARGS SRP service is not a sub-type. + * @retval OT_ERROR_INVALID_ARGS @p aSubTypeServiceName is not a valid sub-type format. * */ -otError otSrpServerServiceGetServiceSubTypeLabel(const otSrpServerService *aService, char *aLabel, uint8_t aMaxSize); +otError otSrpServerParseSubTypeServiceName(const char *aSubTypeServiceName, char *aLabel, uint8_t aLabelSize); /** * Returns the port of the service instance. diff --git a/third_party/openthread/repo/include/openthread/tcp.h b/third_party/openthread/repo/include/openthread/tcp.h index bbcd0ac0..caa0d4ef 100644 --- a/third_party/openthread/repo/include/openthread/tcp.h +++ b/third_party/openthread/repo/include/openthread/tcp.h @@ -225,7 +225,7 @@ typedef void (*otTcpDisconnected)(otTcpEndpoint *aEndpoint, otTcpDisconnectedRea * opaque in its declaration, is treated as struct tcpcb in the TCP * implementation. */ -#define OT_TCP_ENDPOINT_TCB_SIZE_BASE 368 +#define OT_TCP_ENDPOINT_TCB_SIZE_BASE 392 #define OT_TCP_ENDPOINT_TCB_NUM_PTR 36 /** @@ -401,11 +401,16 @@ enum /** * Records the remote host and port for this connection. * - * Caller must wait for `otTcpEstablished` callback indicating that TCP - * connection establishment handshake is done before it can start sending data - * e.g., calling `otTcpSendByReference()`. + * TCP Fast Open must be enabled or disabled using @p aFlags. If it is + * disabled, then the TCP connection establishment handshake is initiated + * immediately. If it is enabled, then this function merely records the + * the remote host and port, and the TCP connection establishment handshake + * only happens on the first call to `otTcpSendByReference()`. * - * The TCP Fast Open is not yet supported and @p aFlags is ignored. + * If TCP Fast Open is disabled, then the caller must wait for the + * `otTcpEstablished` callback indicating that TCP connection establishment + * handshake is done before it can start sending data e.g., by calling + * `otTcpSendByReference()`. * * @param[in] aEndpoint A pointer to the TCP endpoint structure to connect. * @param[in] aSockName The IP address and port of the host to which to connect. diff --git a/third_party/openthread/repo/include/openthread/thread_ftd.h b/third_party/openthread/repo/include/openthread/thread_ftd.h index 24154e45..0928acc8 100644 --- a/third_party/openthread/repo/include/openthread/thread_ftd.h +++ b/third_party/openthread/repo/include/openthread/thread_ftd.h @@ -237,7 +237,7 @@ typedef struct otDeviceProperties /** * Get the current device properties. * - * Requires `OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_3_1`. + * Requires `OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE`. * * @returns The device properties `otDeviceProperties`. * @@ -247,7 +247,7 @@ const otDeviceProperties *otThreadGetDeviceProperties(otInstance *aInstance); /** * Set the device properties which are then used to determine and set the Leader Weight. * - * Requires `OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_3_1`. + * Requires `OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE`. * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aDeviceProperties The device properties. @@ -368,14 +368,14 @@ uint32_t otThreadGetContextIdReuseDelay(otInstance *aInstance); void otThreadSetContextIdReuseDelay(otInstance *aInstance, uint32_t aDelay); /** - * Get the NETWORK_ID_TIMEOUT parameter used in the Router role. + * Get the `NETWORK_ID_TIMEOUT` parameter. * * @note This API is reserved for testing and demo purposes only. Changing settings with * this API will render a production application non-compliant with the Thread Specification. * * @param[in] aInstance A pointer to an OpenThread instance. * - * @returns The NETWORK_ID_TIMEOUT value. + * @returns The `NETWORK_ID_TIMEOUT` value. * * @sa otThreadSetNetworkIdTimeout * @@ -383,10 +383,13 @@ void otThreadSetContextIdReuseDelay(otInstance *aInstance, uint32_t aDelay); uint8_t otThreadGetNetworkIdTimeout(otInstance *aInstance); /** - * Set the NETWORK_ID_TIMEOUT parameter used in the Leader role. + * Set the `NETWORK_ID_TIMEOUT` parameter. + * + * @note This API is reserved for testing and demo purposes only. Changing settings with + * this API will render a production application non-compliant with the Thread Specification. * * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aTimeout The NETWORK_ID_TIMEOUT value. + * @param[in] aTimeout The `NETWORK_ID_TIMEOUT` value. * * @sa otThreadGetNetworkIdTimeout * @@ -689,12 +692,12 @@ otPskcRef otThreadGetPskcRef(otInstance *aInstance); otError otThreadSetPskc(otInstance *aInstance, const otPskc *aPskc); /** - * Set the Thread PSKc + * Set the Key Reference to the Thread PSKc * * Requires the build-time feature `OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE` to be enabled. * - * Will only succeed when Thread protocols are disabled. A successful - * call to this function will also invalidate the Active and Pending Operational Datasets in + * Will only succeed when Thread protocols are disabled. Upon success, + * this will also invalidate the Active and Pending Operational Datasets in * non-volatile memory. * * @param[in] aInstance A pointer to an OpenThread instance. @@ -881,6 +884,16 @@ void otThreadGetRouterIdRange(otInstance *aInstance, uint8_t *aMinRouterId, uint */ otError otThreadSetRouterIdRange(otInstance *aInstance, uint8_t aMinRouterId, uint8_t aMaxRouterId); +/** + * Gets the current Interval Max value used by Advertisement trickle timer. + * + * This API requires `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE`, and is intended for testing only. + * + * @returns The Interval Max of Advertisement trickle timer in milliseconds. + * + */ +uint32_t otThreadGetAdvertisementTrickleIntervalMax(otInstance *aInstance); + /** * Indicates whether or not a Router ID is currently allocated. * @@ -900,7 +913,7 @@ bool otThreadIsRouterIdAllocated(otInstance *aInstance, uint8_t aRouterId); * to get the value. * * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aDesRloct16 The RLOC16 of destination. + * @param[in] aDestRloc16 The RLOC16 of destination. * @param[out] aNextHopRloc16 A pointer to return RLOC16 of next hop, 0xfffe if no next hop. * @param[out] aPathCost A pointer to return path cost towards destination. * diff --git a/third_party/openthread/repo/include/openthread/udp.h b/third_party/openthread/repo/include/openthread/udp.h index 6e577c4a..3512b7bd 100644 --- a/third_party/openthread/repo/include/openthread/udp.h +++ b/third_party/openthread/repo/include/openthread/udp.h @@ -104,8 +104,9 @@ otError otUdpRemoveReceiver(otInstance *aInstance, otUdpReceiver *aUdpReceiver); * @param[in] aMessage A pointer to a message without UDP header. * @param[in] aMessageInfo A pointer to a message info associated with @p aMessage. * - * @retval OT_ERROR_NONE Successfully enqueued the message into an output interface. - * @retval OT_ERROR_NO_BUFS Insufficient available buffer to add the IPv6 headers. + * @retval OT_ERROR_NONE Successfully enqueued the message into an output interface. + * @retval OT_ERROR_NO_BUFS Insufficient available buffer to add the IPv6 headers. + * @retval OT_ERROR_INVALID_ARGS Invalid arguments are given. * */ otError otUdpSendDatagram(otInstance *aInstance, otMessage *aMessage, otMessageInfo *aMessageInfo); diff --git a/third_party/openthread/repo/script/check-arm-build b/third_party/openthread/repo/script/check-arm-build index 398dff76..c4409582 100755 --- a/third_party/openthread/repo/script/check-arm-build +++ b/third_party/openthread/repo/script/check-arm-build @@ -91,7 +91,7 @@ build_nrf52840() main() { - export CPPFLAGS="${CPPFLAGS:-} -DNDEBUG" + export CPPFLAGS="${CPPFLAGS-} -DNDEBUG" if [[ $# == 0 ]]; then build_nrf52840 diff --git a/third_party/openthread/repo/script/check-posix-build-cmake b/third_party/openthread/repo/script/check-posix-build-cmake index 253ab286..63f67c68 100755 --- a/third_party/openthread/repo/script/check-posix-build-cmake +++ b/third_party/openthread/repo/script/check-posix-build-cmake @@ -72,11 +72,11 @@ main() if [[ $OSTYPE != "darwin"* ]]; then reset_source - build -DOT_RCP_RESTORATION_MAX_COUNT=2 -DOT_POSIX_CONFIG_RCP_BUS=SPI "$@" + build -DOT_RCP_RESTORATION_MAX_COUNT=2 -DOT_POSIX_RCP_SPI_BUS=ON "$@" fi reset_source - build -DOT_POSIX_CONFIG_RCP_BUS=VENDOR "$@" + build -DOT_POSIX_RCP_VENDOR_BUS=ON "$@" } main "$@" diff --git a/third_party/openthread/repo/script/check-simulation-build-cmake b/third_party/openthread/repo/script/check-simulation-build-cmake index fc7af8e0..ee1e2ffa 100755 --- a/third_party/openthread/repo/script/check-simulation-build-cmake +++ b/third_party/openthread/repo/script/check-simulation-build-cmake @@ -188,7 +188,7 @@ build_all_features() reset_source "$(dirname "$0")"/cmake-build simulation \ -DOT_THREAD_VERSION=1.1 \ - -DOT_VENDOR_EXTENSION=../../src/core/common/extension_example.cpp + -DOT_VENDOR_EXTENSION=../../src/core/instance/extension_example.cpp # Build Thread 1.3 with no additional features reset_source @@ -249,7 +249,7 @@ build_nest_common() mkdir build && cd build CFLAGS="${cppflags[*]} ${CFLAGS}" CXXFLAGS="${cppflags[*]} ${CXXFLAGS}" \ cmake -GNinja -DOT_PLATFORM=simulation \ - -DOT_VENDOR_EXTENSION=common/extension_example.cpp \ + -DOT_VENDOR_EXTENSION=instance/extension_example.cpp \ -DOT_NCP_VENDOR_HOOK_SOURCE=example_vendor_hook.cpp \ .. ninja diff --git a/third_party/openthread/repo/script/check-size b/third_party/openthread/repo/script/check-size index 90766269..c50ade34 100755 --- a/third_party/openthread/repo/script/check-size +++ b/third_party/openthread/repo/script/check-size @@ -38,8 +38,14 @@ readonly OT_SHA_NEW OT_SHA_OLD="$(git cat-file -p "${OT_SHA_NEW}" | grep 'parent ' | head -n1 | cut -d' ' -f2)" readonly OT_SHA_OLD -OT_REPORT_FILE=/tmp/size_report -readonly OT_REPORT_FILE +OT_REPORT_FILE_TABLE="${OT_TMP_DIR}/report_table" +readonly OT_REPORT_FILE_TABLE + +OT_REPORT_FILE_PR="${OT_TMP_DIR}/report_pr" +readonly OT_REPORT_FILE_TABLE + +OT_REPORTER="${OT_SIZE_REPORTER-}" +readonly OT_REPORTER setup_arm_gcc_7() { @@ -66,19 +72,143 @@ setup() setup_ninja_build } -markdown_init() +nm_size() { - echo '| name | branch | text | data | bss | total |' - echo '| :----: | :------: | -----: | ----: | ---: | ----: |' + arm-none-eabi-nm --print-size --defined-only -C "$1" | cut -d' ' -f2- >nmsize_old + arm-none-eabi-nm --print-size --defined-only -C "$2" | cut -d' ' -f2- >nmsize_new + diff -Nuar nmsize_old nmsize_new || true } -markdown_size() +build_nrf52840() +{ + case "$1" in + ftd) + local ot_ftd=ON + local ot_mtd=OFF + local ot_rcp=ON + ;; + mtd) + local ot_ftd=OFF + local ot_mtd=ON + local ot_rcp=ON + ;; + br) + local ot_ftd=ON + local ot_mtd=OFF + local ot_rcp=OFF + ;; + *) + exit 128 + ;; + esac + + case "$2" in + new) + local sha=${OT_SHA_NEW} + ;; + old) + local sha=${OT_SHA_OLD} + ;; + *) + exit 128 + ;; + esac + + local folder="$1_$2" + local config_name="ot-core-config-check-size-$1.h" + local config_file="../examples/config/${config_name}" + + mkdir -p "${OT_TMP_DIR}/${folder}" + script/git-tool clone https://github.com/openthread/ot-nrf528xx.git "${OT_TMP_DIR}/${folder}" + rm -rf "${OT_TMP_DIR}/${folder}/openthread/*" # replace openthread submodule with latest commit + git archive "${sha}" | tar x -C "${OT_TMP_DIR}/${folder}/openthread" + + if [ ! -e "${OT_TMP_DIR}/${folder}/openthread/examples/config/${config_name}" ]; then + # Check if the the config headers are not present, copy from + # the main sha. + case "$1" in + br) + rm -rf "${OT_TMP_DIR}/${folder}/openthread/*" + git archive "${OT_SHA_NEW}" | tar x -C "${OT_TMP_DIR}/${folder}/openthread" + ;; + *) + mkdir -p "${OT_TMP_DIR}/${folder}/openthread/examples/config" + cp "./examples/config/${config_name}" "${OT_TMP_DIR}/${folder}/openthread/examples/config" + ;; + esac + fi + + local cur_dir + + cur_dir=$(pwd) + + cd "${OT_TMP_DIR}/${folder}" + OT_CMAKE_BUILD_DIR=build script/build nrf52840 UART_trans \ + -DOT_APP_CLI=ON -DOT_APP_NCP=ON -DOT_APP_RCP=${ot_rcp} \ + -DOT_FTD=${ot_ftd} -DOT_MTD=${ot_mtd} -DOT_RCP=${ot_rcp} \ + -DBUILD_TESTING=OFF \ + -DOT_PROJECT_CONFIG="${config_file}" + + if [[ $1 == "br" ]]; then + mv ./build/bin/ot-cli-ftd ./build/bin/ot-cli-ftd-br + mv ./build/lib/libopenthread-ftd.a ./build/lib/libopenthread-ftd-br.a + mv ./build/lib/libopenthread-cli-ftd.a ./build/lib/libopenthread-cli-ftd-br.a + fi + + cd "${cur_dir}" +} + +generate_table_header() +{ + { + printf "+----------------------------+----------+----------+----------+----------+----------+\n" + printf "| name | branch | text | data | bss | total |\n" + printf "+============================+==========+==========+==========+==========+==========+\n" + } >>"${OT_REPORT_FILE_TABLE}" + + { + printf "# Size Report of **OpenThread**\n" + printf "Merging PR into main\n\n" + printf "| name | branch | text | data | bss | total |\n" + printf "| :----: | :------: | -----: | ----: | ---: | ----: |\n" + } >>"${OT_REPORT_FILE_PR}" + + { + printf "\n
Library files\n\n\n" + printf "| name | branch | text | data | bss | total |\n" + printf "| :----: | :------: | -----: | ----: | ---: | ----: |\n" + } >>"${OT_REPORT_FILE_PR}_libs" + + if [ -n "${OT_REPORTER}" ]; then + "${OT_REPORTER}" init OpenThread + fi + +} + +generate_size_diff() { local name - name=$(basename "$1") + local old_file + local new_file + + old_file="$1" + new_file="$2" + + name=$(basename "${old_file}") + + case "${name}" in + lib*) + table_report_file="${OT_REPORT_FILE_TABLE}_libs" + pr_report_file="${OT_REPORT_FILE_PR}"_libs + ;; + *) + table_report_file="${OT_REPORT_FILE_TABLE}" + pr_report_file="${OT_REPORT_FILE_PR}" + ;; + esac - read -r -a size_old <<<"$(size "$1" | awk '{text+=$1} {bss+=$2} {data+=$3} {total+=$4} END {printf "%d %d %d %d", text, bss, data, total}')" - read -r -a size_new <<<"$(size "$2" | awk '{text+=$1} {bss+=$2} {data+=$3} {total+=$4} END {printf "%d %d %d %d", text, bss, data, total}')" + read -r -a size_old <<<"$(size "${old_file}" | awk '{text+=$1} {bss+=$2} {data+=$3} {total+=$4} END {printf "%d %d %d %d", text, bss, data, total}')" + read -r -a size_new <<<"$(size "${new_file}" | awk '{text+=$1} {bss+=$2} {data+=$3} {total+=$4} END {printf "%d %d %d %d", text, bss, data, total}')" local -a size_diff @@ -89,168 +219,141 @@ markdown_size() fi done - echo "| ${name} | -${OT_SHA_OLD:0:7} | ${size_old[0]} | ${size_old[1]} | ${size_old[2]} | ${size_old[3]} |" - echo "| | +${OT_SHA_NEW:0:7} | ${size_new[0]} | ${size_new[1]} | ${size_new[2]} | ${size_new[3]} |" - echo "| | +/- | ${size_diff[0]} | ${size_diff[1]} | ${size_diff[2]} | ${size_diff[3]} |" -} + # Generate table format report -markdown() -{ - case "$1" in - init) - shift - markdown_init "$@" >"${OT_REPORT_FILE}" - ;; - size) - shift - markdown_size "$@" >>"${OT_REPORT_FILE}" - ;; - post) - mdv "${OT_REPORT_FILE}" - ;; - esac + { + printf "| %-26s | %-8s " "${name}" "${OT_SHA_OLD:0:8}" + printf "| %8u | %8u | %8u | %8u |" "${size_old[0]}" "${size_old[1]}" "${size_old[2]}" "${size_old[3]}" + printf "\n" + + printf "| %-26s | %-8s " "" "${OT_SHA_NEW:0:8}" + printf "| %8u | %8u | %8u | %8u |" "${size_new[0]}" "${size_new[1]}" "${size_new[2]}" "${size_new[3]}" + printf "\n" + + printf "| %-26s | %-8s " "" "+/-" + printf "| %+8d | %+8d | %+8d | %+8d |" "${size_diff[0]}" "${size_diff[1]}" "${size_diff[2]}" "${size_diff[3]}" + printf "\n" >>"${table_report_file}" + + printf "+----------------------------+----------+----------+----------+----------+----------+\n" + } >>"${table_report_file}" + + # Generate PR post format report + + { + printf "| %s | %s " "${name}" "${OT_SHA_OLD:0:8}" + printf "| %u | %u | %u | %u |" "${size_old[0]}" "${size_old[1]}" "${size_old[2]}" "${size_old[3]}" + printf "\n" + + printf "| | %s " "${OT_SHA_NEW:0:8}" + printf "| %u | %u | %u | %u |" "${size_new[0]}" "${size_new[1]}" "${size_new[2]}" "${size_new[3]}" + printf "\n" + + printf "| | %s " "+/-" + printf "| %+d | %+d | %+d | %+d |" "${size_diff[0]}" "${size_diff[1]}" "${size_diff[2]}" "${size_diff[3]}" + printf "\n" + } >>"${pr_report_file}" + + if [ -n "${OT_REPORTER}" ]; then + "${OT_REPORTER}" size "${old_file}" "${new_file}" + fi } -nm_size() +generate_report() { - arm-none-eabi-nm --print-size --defined-only -C "$1" | cut -d' ' -f2- >nmsize_old - arm-none-eabi-nm --print-size --defined-only -C "$2" | cut -d' ' -f2- >nmsize_new - diff -Nuar nmsize_old nmsize_new || true + local type="${1}" + shift + + local old_file + local new_file + + for file in "$@"; do + case "${file}" in + lib*) + old_file="${OT_TMP_DIR}"/${type}_old/build/lib/"${file}" + new_file="${OT_TMP_DIR}"/${type}_new/build/lib/"${file}" + ;; + *) + old_file="${OT_TMP_DIR}"/${type}_old/build/bin/"${file}" + new_file="${OT_TMP_DIR}"/${type}_new/build/bin/"${file}" + ;; + esac + + generate_size_diff "${old_file}" "${new_file}" + + echo "nm_size ${old_file} ${new_file}" + nm_size "${old_file}" "${new_file}" + done } -size_nrf52840_version() +finalize_report() { - local options=( - "-DOT_ANYCAST_LOCATOR=ON" - "-DOT_BORDER_AGENT=ON" - "-DOT_BORDER_ROUTER=ON" - "-DOT_CHANNEL_MANAGER=ON" - "-DOT_CHANNEL_MONITOR=ON" - "-DOT_COAP=ON" - "-DOT_COAPS=ON" - "-DOT_COMMISSIONER=ON" - "-DOT_DATASET_UPDATER=ON" - "-DOT_DHCP6_CLIENT=ON" - "-DOT_DHCP6_SERVER=ON" - "-DOT_DIAGNOSTIC=ON" - "-DOT_DNSSD_SERVER=ON" - "-DOT_DNS_CLIENT=ON" - "-DOT_ECDSA=ON" - "-DOT_FULL_LOGS=ON" - "-DOT_JAM_DETECTION=ON" - "-DOT_JOINER=ON" - "-DOT_LINK_RAW=ON" - "-DOT_MAC_FILTER=ON" - "-DOT_MESSAGE_USE_HEAP=ON" - "-DOT_NETDATA_PUBLISHER=ON" - "-DOT_PING_SENDER=ON" - "-DOT_SERVICE=ON" - "-DOT_SLAAC=ON" - "-DOT_SNTP_CLIENT=ON" - "-DOT_SRP_CLIENT=ON" - "-DOT_SRP_SERVER=ON" - "-DOT_TIME_SYNC=ON" - "-DOT_UDP_FORWARD=ON" - "-DOT_UPTIME=ON" - ) + cat "${OT_REPORT_FILE_TABLE}" + cat "${OT_REPORT_FILE_TABLE}_libs" - local thread_version=$1 - - if [[ ${thread_version} != "1.1" ]]; then - options+=( - "-DOT_THREAD_VERSION=1.3" - "-DOT_BACKBONE_ROUTER=ON" - "-DOT_DUA=ON" - "-DOT_MLR=ON" - "-DOT_CSL_RECEIVER=ON" - "-DOT_LINK_METRICS_INITIATOR=ON" - "-DOT_LINK_METRICS_SUBJECT=ON" - ) - fi - - rm -rf "${OT_TMP_DIR}" + printf "
" >>${OT_REPORT_FILE_PR}_libs + cat "${OT_REPORT_FILE_PR}_libs" >>${OT_REPORT_FILE_PR} - local build_dir="build" + if [ -n "${OT_REPORTER}" ]; then + "${OT_REPORTER}" post + fi +} - # new commit - mkdir -p "${OT_TMP_DIR}/b" - script/git-tool clone https://github.com/openthread/ot-nrf528xx.git "${OT_TMP_DIR}/b" - rm -rf "${OT_TMP_DIR}/b/openthread/*" # replace openthread submodule with latest commit - git archive "${OT_SHA_NEW}" | tar x -C "${OT_TMP_DIR}/b/openthread" +size_nrf52840() +{ + export OT_SHA_NEW OT_SHA_OLD - (cd "${OT_TMP_DIR}/b" \ - && OT_CMAKE_BUILD_DIR=${build_dir} script/build nrf52840 UART_trans "${options[@]}") + rm -rf "${OT_TMP_DIR}" + mkdir -p "${OT_TMP_DIR}" - # old commit if [[ "${GITHUB_ACTIONS+x}" ]]; then git fetch --depth 1 --no-recurse-submodules origin "${OT_SHA_OLD}" fi - mkdir -p "${OT_TMP_DIR}/a" - git clone https://github.com/openthread/ot-nrf528xx.git "${OT_TMP_DIR}/a" - rm -rf "${OT_TMP_DIR}/a/openthread/*" # replace openthread submodule with last commit - git archive "${OT_SHA_OLD}" | tar x -C "${OT_TMP_DIR}/a/openthread" - - (cd "${OT_TMP_DIR}/a" \ - && OT_CMAKE_BUILD_DIR=${build_dir} script/build nrf52840 UART_trans "${options[@]}") - - # rename the generated files to be ready for size-report - # shellcheck disable=SC2011 - ( - cd "${OT_TMP_DIR}"/a/"${build_dir}"/bin - ls | xargs -I{} mv {} {}_"${thread_version}" - cd "${OT_TMP_DIR}"/b/"${build_dir}"/bin - ls | xargs -I{} mv {} {}_"${thread_version}" - - cd "${OT_TMP_DIR}"/a/"${build_dir}"/lib - ls ./*.a | xargs -I{} mv {} {}_"${thread_version}" - cd "${OT_TMP_DIR}"/b/"${build_dir}"/lib - ls ./*.a | xargs -I{} mv {} {}_"${thread_version}" - ) + generate_table_header + + build_nrf52840 ftd new + build_nrf52840 mtd new + build_nrf52840 br new + + build_nrf52840 ftd old + build_nrf52840 mtd old + build_nrf52840 br old - local bins=( + local ftd_files=( "ot-cli-ftd" - "ot-cli-mtd" "ot-ncp-ftd" - "ot-ncp-mtd" - "ot-rcp" + "libopenthread-ftd.a" + "libopenthread-cli-ftd.a" + "libopenthread-ncp-ftd.a" ) - local libs=( - "libopenthread-cli-ftd.a" - "libopenthread-cli-mtd.a" - "libopenthread-ftd.a" + local mtd_files=( + "ot-cli-mtd" + "ot-ncp-mtd" "libopenthread-mtd.a" - "libopenthread-ncp-ftd.a" + "libopenthread-cli-mtd.a" "libopenthread-ncp-mtd.a" - "libopenthread-rcp.a" - "libopenthread-radio.a" ) - for file in "${bins[@]}"; do - "${reporter}" size "${OT_TMP_DIR}"/a/"${build_dir}"/bin/"${file}"_"${thread_version}" "${OT_TMP_DIR}"/b/"${build_dir}"/bin/"${file}"_"${thread_version}" - echo nm_size "${OT_TMP_DIR}"/a/"${build_dir}"/bin/"${file}"_"${thread_version}" "${OT_TMP_DIR}"/b/"${build_dir}"/bin/"${file}"_"${thread_version}" - nm_size "${OT_TMP_DIR}"/a/"${build_dir}"/bin/"${file}"_"${thread_version}" "${OT_TMP_DIR}"/b/"${build_dir}"/bin/"${file}"_"${thread_version}" - done - - for file in "${libs[@]}"; do - "${reporter}" size "${OT_TMP_DIR}"/a/"${build_dir}"/lib/"${file}"_"${thread_version}" "${OT_TMP_DIR}"/b/"${build_dir}"/lib/"${file}"_"${thread_version}" - echo nm_size "${OT_TMP_DIR}"/a/"${build_dir}"/lib/"${file}"_"${thread_version}" "${OT_TMP_DIR}"/b/"${build_dir}"/lib/"${file}"_"${thread_version}" - nm_size "${OT_TMP_DIR}"/a/"${build_dir}"/lib/"${file}"_"${thread_version}" "${OT_TMP_DIR}"/b/"${build_dir}"/lib/"${file}"_"${thread_version}" - done -} - -size_nrf52840() -{ - export OT_SHA_NEW OT_SHA_OLD + local br_files=( + "ot-cli-ftd-br" + "libopenthread-ftd-br.a" + "libopenthread-cli-ftd-br.a" + ) - local reporter="${OT_SIZE_REPORTER:-markdown}" - "${reporter}" init OpenThread + # `rcp`` is using same config as `ftd`. + local rcp_files=( + "ot-rcp" + "libopenthread-rcp.a" + "libopenthread-radio.a" + ) - size_nrf52840_version 1.1 - size_nrf52840_version 1.3 + generate_report ftd "${ftd_files[@]}" + generate_report mtd "${mtd_files[@]}" + generate_report br "${br_files[@]}" + generate_report ftd "${rcp_files[@]}" - "${reporter}" post + finalize_report } main() @@ -258,6 +361,7 @@ main() if [[ $# == 0 ]]; then setup size_nrf52840 + cd elif [[ $1 == setup ]]; then setup elif [[ $1 == nrf52840 ]]; then diff --git a/third_party/openthread/repo/script/make-pretty b/third_party/openthread/repo/script/make-pretty index af73554c..086ba4c0 100755 --- a/third_party/openthread/repo/script/make-pretty +++ b/third_party/openthread/repo/script/make-pretty @@ -142,27 +142,6 @@ OT_CLANG_TIDY_BUILD_OPTS=( ) readonly OT_CLANG_TIDY_BUILD_OPTS -OT_CLANG_TIDY_CHECKS="\ --*,\ -google-explicit-constructor,\ -google-readability-casting,\ -misc-unused-using-decls,\ -modernize-loop-convert,\ -modernize-use-bool-literals,\ -modernize-use-equals-default,\ -modernize-use-equals-delete,\ -modernize-use-nullptr,\ -readability-avoid-const-params-in-decls,\ -readability-else-after-return,\ -readability-inconsistent-declaration-parameter-name,\ -readability-make-member-function-const,\ -readability-redundant-control-flow,\ -readability-redundant-member-init,\ -readability-simplify-boolean-expr,\ -readability-static-accessed-through-instance,\ -" -readonly OT_CLANG_TIDY_CHECKS - do_clang_format() { echo -e '========================================' @@ -192,7 +171,7 @@ do_clang_tidy_fix() (mkdir -p ./build/cmake-tidy \ && cd ./build/cmake-tidy \ && THREAD_VERSION=1.3 cmake "${OT_CLANG_TIDY_BUILD_OPTS[@]}" ../.. \ - && ../../script/clang-tidy -header-filter='.*' -checks="${OT_CLANG_TIDY_CHECKS}" -j"$OT_BUILD_JOBS" "${OT_CLANG_TIDY_FIX_DIRS[@]}" -fix) + && ../../script/clang-tidy -j"$OT_BUILD_JOBS" "${OT_CLANG_TIDY_FIX_DIRS[@]}" -fix) } do_clang_tidy_check() @@ -201,19 +180,10 @@ do_clang_tidy_check() echo -e ' check c/c++ (clang-tidy)' echo -e '========================================' - ( - mkdir -p ./build/cmake-tidy \ - && cd ./build/cmake-tidy \ - && THREAD_VERSION=1.3 cmake "${OT_CLANG_TIDY_BUILD_OPTS[@]}" ../.. \ - && ../../script/clang-tidy -header-filter='.*' -checks="${OT_CLANG_TIDY_CHECKS}" -j"$OT_BUILD_JOBS" "${OT_CLANG_TIDY_FIX_DIRS[@]}" \ - | grep -v -E "third_party" >output.txt - if grep -q "warning: \|error: " output.txt; then - echo "You must pass the clang tidy checks before submitting a pull request" - echo "" - grep --color -E 'warning: |error: ' -A 5 output.txt - exit 1 - fi - ) + (mkdir -p ./build/cmake-tidy \ + && cd ./build/cmake-tidy \ + && THREAD_VERSION=1.3 cmake "${OT_CLANG_TIDY_BUILD_OPTS[@]}" ../.. \ + && ../../script/clang-tidy -j"$OT_BUILD_JOBS" "${OT_CLANG_TIDY_FIX_DIRS[@]}") } do_markdown_format() diff --git a/third_party/openthread/repo/script/test b/third_party/openthread/repo/script/test index 8a237259..a9a71b3b 100755 --- a/third_party/openthread/repo/script/test +++ b/third_party/openthread/repo/script/test @@ -129,6 +129,18 @@ build_simulation() options+=("-DOT_CSL_RECEIVER=ON") options+=("-DOT_LINK_METRICS_INITIATOR=ON") options+=("-DOT_LINK_METRICS_SUBJECT=ON") + options+=("-DOT_LINK_METRICS_MANAGER=ON") + fi + + if [[ ${OT_NODE_TYPE} == cli* ]]; then + # Only enable OT_PLATFORM_BOOTLOADER_MODE when testing cli. + # This is intended to test that the "reset bootloader" CLI command returns a "NotCapable" error + + # Note: Setting this option to ON for all OT_NODE_TYPEs will cause the posix/expects CI check to fail. + # This is because the simulation RCP will have the SPINEL_CAP_RCP_RESET_TO_BOOTLOADER capability, + # causing the ot-cli POSIX app to send the reset to simulation RCP successfully instead of printing + # the expected error. + options+=("-DOT_PLATFORM_BOOTLOADER_MODE=ON") fi if [[ ${ot_extra_options[*]+x} ]]; then @@ -157,11 +169,19 @@ build_simulation() build_posix() { local version="$1" - local options=("-DOT_MESSAGE_USE_HEAP=ON" "-DOT_THREAD_VERSION=${version}" "-DBUILD_TESTING=ON") + local options=( + "-DBUILD_TESTING=ON" + "-DOT_MESSAGE_USE_HEAP=ON" + "-DOT_PLATFORM_BOOTLOADER_MODE=ON" + "-DOT_THREAD_VERSION=${version}" + ) if [[ ${version} != "1.1" ]]; then options+=("-DOT_DUA=ON") options+=("-DOT_MLR=ON") + options+=("-DOT_LINK_METRICS_INITIATOR=ON") + options+=("-DOT_LINK_METRICS_SUBJECT=ON") + options+=("-DOT_LINK_METRICS_MANAGER=ON") fi if [[ ${FULL_LOGS} == 1 ]]; then @@ -338,6 +358,7 @@ do_build_otbr_docker() "REST_API=0" "WEB_GUI=0" "MDNS=${OTBR_MDNS:-mDNSResponder}" + "FIREWALL=${FIREWALL:-1}" ) if [[ ${NAT64} != 1 ]]; then @@ -377,6 +398,8 @@ do_build_otbr_docker() rm -rf third_party/openthread/repo rsync -r \ --exclude=build \ + --exclude=ot_testing \ + --exclude=__pycache__ \ "${otdir}/." \ third_party/openthread/repo rm -rf .git @@ -656,7 +679,7 @@ main() { envsetup "$@" - if [[ -z ${1:-} ]]; then + if [[ -z ${1-} ]]; then print_usage 1 fi diff --git a/third_party/openthread/repo/src/cli/README.md b/third_party/openthread/repo/src/cli/README.md index 1fbb49ff..9bc0ffb3 100644 --- a/third_party/openthread/repo/src/cli/README.md +++ b/third_party/openthread/repo/src/cli/README.md @@ -41,6 +41,7 @@ Done - [csl](#csl) - [dataset](README_DATASET.md) - [delaytimermin](#delaytimermin) +- [detach](#detach) - [deviceprops](#deviceprops) - [diag](#diag) - [discover](#discover-channel) @@ -65,6 +66,7 @@ Done - [leaderdata](#leaderdata) - [leaderweight](#leaderweight) - [linkmetrics](#linkmetrics-mgmt-ipaddr-enhanced-ack-clear) +- [linkmetricsmgr](#linkmetricsmgr-disable) - [locate](#locate) - [log](#log-filename-filename) - [mac](#mac-retries-direct) @@ -87,7 +89,7 @@ Done - [parent](#parent) - [parentpriority](#parentpriority) - [partitionid](#partitionid) -- [ping](#ping-async--i-source-ipaddr-size-count-interval-hoplimit-timeout) +- [ping](#ping-async--i-source--m-ipaddr-size-count-interval-hoplimit-timeout) - [platform](#platform) - [pollperiod](#pollperiod-pollperiod) - [preferrouterid](#preferrouterid-routerid) @@ -983,10 +985,12 @@ Done Get the CSL configuration. +CSL period is shown in microseconds. + ```bash > csl Channel: 11 -Period: 1000 (in units of 10 symbols), 160ms +Period: 160000us Timeout: 1000s Done ``` @@ -1002,10 +1006,12 @@ Done ### csl period \ -Set CSL period in units of 10 symbols. Disable CSL by setting this parameter to `0`. +Set CSL period in microseconds. Disable CSL by setting this parameter to `0`. + +The CSL period MUST be a multiple 160 microseconds which is 802.15.4 "ten symbols time". ```bash -> csl period 3000 +> csl period 30000000 Done ``` @@ -1061,6 +1067,25 @@ Set the minimal delay timer (in seconds). Done ``` +### detach + +Start the graceful detach process by first notifying other nodes (sending Address Release if acting as a router, or setting Child Timeout value to zero on parent if acting as a child) and then stopping Thread protocol operation. + +```bash +> detach +Finished detaching +Done +``` + +### detach async + +Start the graceful detach process similar to the `detach` command without blocking and waiting for the callback indicating that detach is finished. + +```bash +> detach async +Done +``` + ### deviceprops Get the current device properties. @@ -1236,6 +1261,19 @@ Send a browse (service instance enumeration) DNS query to get the list of servic The parameters after `service-name` are optional. Any unspecified (or zero) value for these optional parameters is replaced by the value from the current default config (`dns config`). +```bash +> dns browse _service._udp.example.com +DNS browse response for _service._udp.example.com. +inst1 +inst2 +inst3 +Done +``` + +The detailed service info (port number, weight, host name, TXT data, host addresses) is outputted only when provided by server/resolver in the browse response (in additional Data Section). This is a SHOULD and not a MUST requirement, and servers/resolvers are not required to provide this. + +The recommended behavior, which is supported by the OpenThread DNS-SD resolver, is to only provide the additional data when there is a single instance in the response. However, users should assume that the browse response may only contain the list of matching service instances and not any detail service info. To resolve a service instance, users can use the `dns service` or `dns servicehost` commands. + ```bash > dns browse _service._udp.example.com DNS browse response for _service._udp.example.com. @@ -1244,11 +1282,6 @@ inst1 Host:host.example.com. HostAddress:fd00:0:0:0:0:0:0:abcd TTL:7200 TXT:[a=6531, b=6c12] TTL:7300 -instance2 - Port:1234, Priority:1, Weight:2, TTL:7200 - Host:host.example.com. - HostAddress:fd00:0:0:0:0:0:0:abcd TTL:7200 - TXT:[a=1234] TTL:7300 Done ``` @@ -1516,13 +1549,19 @@ fe80:0:0:0:f3d9:2a82:c8d8:fe43 Done ``` -Use `-v` to get more verbose information about the address. +Use `-v` to get more verbose information about the address: + +- `origin`: can be `thread`, `slaac`, `dhcp6`, or `manual`, and indicates the origin of the address +- `plen`: prefix length (in bits) +- `preferred`: preferred flag (boolean) +- `valid`: valid flag (boolean) ```bash > ipaddr -v -fdde:ad00:beef:0:0:ff:fe00:0 origin:thread -fdde:ad00:beef:0:558:f56b:d688:799 origin:thread -fe80:0:0:0:f3d9:2a82:c8d8:fe43 origin:thread +fd5e:18fa:f4a5:b8:0:ff:fe00:fc00 origin:thread plen:64 preferred:0 valid:1 +fd5e:18fa:f4a5:b8:0:ff:fe00:dc00 origin:thread plen:64 preferred:0 valid:1 +fd5e:18fa:f4a5:b8:f8e:5d95:87a0:e82c origin:thread plen:64 preferred:0 valid:1 +fe80:0:0:0:4891:b191:e277:8826 origin:thread plen:64 preferred:1 valid:1 Done ``` @@ -1845,6 +1884,41 @@ Done - RSSI: -18 (dBm) (Exponential Moving Average) ``` +### linkmetricsmgr disable + +Disable the Link Metrics Manager. + +`OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE` is required. + +```bash +> linkmetricsmgr disable +Done +``` + +### linkmetricsmgr enable + +Enable the Link Metrics Manager. + +`OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE` is required. + +```bash +> linkmetricsmgr enable +Done +``` + +### linkmetricsmgr show + +Display the Link Metrics data of all subjects. The subjects are identified by its extended address. + +`OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE` is required. + +```bash + +> linkmetricsmgr show +ExtAddr:827aa7f7f63e1234, LinkMargin:80, Rssi:-20 +Done +``` + ### locate Gets the current state (`In Progress` or `Idle`) of anycast locator. @@ -2654,12 +2728,13 @@ Set the preferred Thread Leader Partition ID. Done ``` -### ping \[async\] \[-I source\] \ \[size\] \[count\] \[interval\] \[hoplimit\] \[timeout\] +### ping \[async\] \[-I source\] \[-m] \ \[size\] \[count\] \[interval\] \[hoplimit\] \[timeout\] Send an ICMPv6 Echo Request. - async: Use the non-blocking mode. New commands are allowed before the ping process terminates. - source: The source IPv6 address of the echo request. +- -m: multicast loop, which allows looping back pings to multicast addresses that the device itself is subscribed to. - size: The number of data bytes to be sent. - count: The number of ICMPv6 Echo Requests to be sent. - interval: The interval between two consecutive ICMPv6 Echo Requests in seconds. The value may have fractional form, for example `0.5`. @@ -3000,6 +3075,17 @@ Signal a platform reset. > reset ``` +### reset bootloader + +Signal a platform reset to bootloader mode, if supported. + +Requires `OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE`. + +```bash +> reset bootloader +Done +``` + ### rloc16 Get the Thread RLOC16 value. @@ -3020,12 +3106,13 @@ Get the external route list in the local Network Data. Done ``` -### route add \ [sn][prf] +### route add \ [sna][prf] Add a valid external route to the Network Data. - s: Stable flag - n: NAT64 flag +- a: Advertising PIO (AP) flag - prf: Default Router Preference, which may be: 'high', 'med', or 'low'. ```bash @@ -3885,7 +3972,7 @@ Done ``` ```bash -> macfilter rss add 0f6127e33af6b404 2 +> macfilter rss add-lqi 0f6127e33af6b404 2 Done ``` diff --git a/third_party/openthread/repo/src/cli/README_BR.md b/third_party/openthread/repo/src/cli/README_BR.md index 4761d879..b48eec29 100644 --- a/third_party/openthread/repo/src/cli/README_BR.md +++ b/third_party/openthread/repo/src/cli/README_BR.md @@ -8,6 +8,7 @@ Usage : `br [command] ...` - [disable](#disable) - [enable](#enable) - [help](#help) +- [init](#init) - [nat64prefix](#nat64prefix) - [omrprefix](#omrprefix) - [onlinkprefix](#onlinkprefix) @@ -38,6 +39,17 @@ state Done ``` +### init + +Usage: `br init ` + +Initializes the Border Routing Manager on given infrastructure interface. + +```bash +> br init 2 1 +Done +``` + ### enable Usage: `br enable` diff --git a/third_party/openthread/repo/src/cli/README_DATASET.md b/third_party/openthread/repo/src/cli/README_DATASET.md index cba2b9bc..54f4c1e7 100644 --- a/third_party/openthread/repo/src/cli/README_DATASET.md +++ b/third_party/openthread/repo/src/cli/README_DATASET.md @@ -107,6 +107,117 @@ After the device successfully attaches to a Thread network, the device will retr Done ``` +### Using the Pending Operational Dataset for Delayed Dataset Updates + +The Pending Operational Dataset can be used for a delayed update of network parameters on all devices of a Thread Network. If certain Active Operational Dataset parameters need to be changed, but the change would impact the connectivity of the network, delaying the update helps to let all devices receive the new parameters before the update is applied. Examples of such parameters are the channel, PAN ID, certain Security Policy bits, or Network Key. + +The delay timer determines the time period after which the Pending Operational Dataset takes effect and becomes the Active Operational Dataset. The following example shows how a Pending Operational Dataset with delay timer can be set at a Leader device. The Leader will initiate the distribution of the Pending Operational Dataset to the rest of the devices in the network. + +Normally, an active Commissioner will set a new Pending Operational Dataset. For testing purposes, we will do this in the example directly on the Leader using the CLI - so without using a Commissioner. + +1. The main parameter to change is the channel. We can display the current Active Operational Dataset to see that the current channel is 16. + + ```bash + > dataset active + Active Timestamp: 1691070443 + Channel: 16 + Channel Mask: 0x07fff800 + Ext PAN ID: 324a71d90cdc8345 + Mesh Local Prefix: fd7d:da74:df5e:80c::/64 + Network Key: be768535bac1b8d228960038311d6ca2 + Network Name: OpenThread-bcaf + PAN ID: 0xbcaf + PSKc: e79b274ab22414a814ed5cce6a30be67 + Security Policy: 672 onrc 0 + Done + ``` + +2. Create a new Dataset in the dataset buffer, by copying the Active Operational Dataset. Then change the channel number to 12 and increase the timestamp. + + ```bash + > dataset init active + Done + > dataset activetimestamp 1696177379 + Done + > dataset pendingtimestamp 1696177379 + Done + > dataset channel 12 + Done + ``` + +3. Set the delay timer parameter to 5 minutes (300000 ms). Show the resulting Dataset that's ready to be used. + + ```bash + > dataset delay 300000 + Done + > dataset + Pending Timestamp: 1696177379 + Active Timestamp: 1696177379 + Channel: 12 + Channel Mask: 0x07fff800 + Delay: 300000 + Ext PAN ID: 324a71d90cdc8345 + Mesh Local Prefix: fd7d:da74:df5e:80c::/64 + Network Key: be768535bac1b8d228960038311d6ca2 + Network Name: OpenThread-bcaf + PAN ID: 0xbcaf + PSKc: e79b274ab22414a814ed5cce6a30be67 + Security Policy: 672 onrc 0 + Done + ``` + +4. Commit the new Dataset as the Pending Operational Dataset. This also starts the delay timer countdown. The Leader then starts the distribution of the Pending Operational Dataset to other devices in the network. + + ```bash + > dataset commit pending + Done + ``` + +5. To verify that the delay timer is counting down, display the Pending Operational Dataset after a few seconds. + + ```bash + > dataset pending + Pending Timestamp: 1696177379 + Active Timestamp: 1696177379 + Channel: 12 + Channel Mask: 0x07fff800 + Delay: 293051 + Ext PAN ID: 324a71d90cdc8345 + Mesh Local Prefix: fd7d:da74:df5e:80c::/64 + Network Key: be768535bac1b8d228960038311d6ca2 + Network Name: OpenThread-bcaf + PAN ID: 0xbcaf + PSKc: e79b274ab22414a814ed5cce6a30be67 + Security Policy: 672 onrc 0 + Done + ``` + + This shows that indeed the delay timer has started counting down from its initial value `300000`. The same can be optionally checked on other devices in the network. + +6) After about 5 minutes, check that the Pending Operational Dataset has been applied at the Leader. This can also be checked at other devices on the network: these should have applied the new Dataset too, at approximately the same time as the Leader has done this. + + ```bash + > dataset active + Active Timestamp: 1696177379 + Channel: 12 + Channel Mask: 0x07fff800 + Ext PAN ID: 324a71d90cdc8345 + Mesh Local Prefix: fd7d:da74:df5e:80c::/64 + Network Key: be768535bac1b8d228960038311d6ca2 + Network Name: OpenThread-bcaf + PAN ID: 0xbcaf + PSKc: e79b274ab22414a814ed5cce6a30be67 + Security Policy: 672 onrc 0 + Done + ``` + + This shows that the Active Operational Dataset has now been updated to use channel 12. And the Pending Operational Dataset is no longer present, as can be seen by this command: + + ```bash + > dataset pending + Error 23: NotFound + ``` + ## Command List - [help](#help) @@ -199,7 +310,7 @@ Done Usage: `dataset activetimestamp [timestamp]` -Get active timestamp seconds. +Get active timestamp seconds. It represents a "Unix time", in number of seconds since Jan 1st, 1970. ```bash > dataset activetimestamp @@ -278,7 +389,7 @@ Done Usage: `dataset delay [delay]` -Get delay timer value. +Get delay timer value. The timer value is in milliseconds. ```bash > dataset delay @@ -289,7 +400,7 @@ Done Set delay timer value. ```bash -> dataset delay 1000 +> dataset delay 100000 Done ``` @@ -318,13 +429,27 @@ Done Usage: `dataset init >` -Initialize operational dataset buffer. +Initialize operational dataset buffer. Use `new` to initialize with randomly selected values: ```bash > dataset init new Done ``` +Use `active` or `pending` to initialize the dataset buffer with a copy of the current Active Operational Dataset or Pending Operational Dataset, respectively: + +```bash +> dataset init active +Done +``` + +Use the `tlvs` option to initialize the dataset buffer from a string of hex-encoded TLVs: + +```bash +> dataset init tlvs 0e080000000000010000000300001235060004001fffe002088665f03e6e42e7750708fda576e5f9a5bd8c0510506071d8391be671569e080d52870fd5030f4f70656e5468726561642d633538640102c58d04108a926cf8b13275a012ceedeeae40910d0c0402a0f7f8 +Done +``` + ### meshlocalprefix Usage: `dataset meshlocalprefix [prefix]` @@ -460,7 +585,7 @@ Done Usage: `dataset pendingtimestamp [timestamp]` -Get pending timestamp seconds. +Get pending timestamp seconds. It represents a "Unix time", in number of seconds since Jan 1st, 1970. ```bash > dataset pendingtimestamp @@ -479,7 +604,7 @@ Done Usage: `pskc [-p] [|]` -Get pskc. +Get PSKc. ```bash > dataset pskc @@ -487,9 +612,9 @@ Get pskc. Done ``` -Set pskc. +Set PSKc. -With `-p`(**only for FTD**) generate pskc from \ (UTF-8 encoded) together with network name and extended PAN ID in the dataset buffer if set or values in the current stack if not, otherwise set pskc as \ (hex format). +With `-p`(**only for FTD**) generate PSKc from \ (UTF-8 encoded) together with network name and extended PAN ID in the dataset buffer if set or values in the current stack if not, otherwise set PSKc as \ (hex format). ```bash > dataset pskc 67c0c203aa0b042bfb5381c47aef4d9e diff --git a/third_party/openthread/repo/src/cli/README_NETDATA.md b/third_party/openthread/repo/src/cli/README_NETDATA.md index f41f8998..ad33bb99 100644 --- a/third_party/openthread/repo/src/cli/README_NETDATA.md +++ b/third_party/openthread/repo/src/cli/README_NETDATA.md @@ -297,6 +297,7 @@ Publish an external route entry. - s: Stable flag - n: NAT64 flag +- a: Advertising PIO (AP) flag - prf: Preference, which may be: 'high', 'med', or 'low'. ```bash @@ -312,6 +313,7 @@ If there is no previously published external route matching old prefix, this com - s: Stable flag - n: NAT64 flag +- a: Advertising PIO (AP) flag - prf: Preference, which may be: 'high', 'med', or 'low'. ```bash @@ -358,6 +360,7 @@ External Routes are listed under `Routes` header: - Flags - s: Stable flag - n: NAT64 flag + - a: Advertising PIO (AP) flag - Preference `high`, `med`, or `low` - RLOC16 of device which added the route prefix @@ -376,6 +379,15 @@ Service entries are listed under `Services` header: - Context ID - Compress flag (`c` if marked or `-` otherwise). +Commissioning Dataset information is printed under `Commissioning` header: + +- Session ID if present in Dataset or `-` otherwise +- Border Agent RLOC16 (in hex) if present in Dataset or `-` otherwise +- Joiner UDP port number if present in Dataset or `-` otherwise +- Steering Data (as hex bytes) if present in Dataset or `-` otherwise +- Flags: + - e: if Dataset contains any extra unknown TLV + Print Network Data received from the Leader. ```bash @@ -389,6 +401,8 @@ Services: 44970 5d fddead00beef00007bad0069ce45948504d2 s a000 Contexts: fd00:dead:beef:cafe::/64 1 c +Commissioning: +1248 dc00 9988 00000000000120000000000000000000 e Done ``` diff --git a/third_party/openthread/repo/src/cli/README_TCP.md b/third_party/openthread/repo/src/cli/README_TCP.md index 6281fd88..8e341453 100644 --- a/third_party/openthread/repo/src/cli/README_TCP.md +++ b/third_party/openthread/repo/src/cli/README_TCP.md @@ -58,7 +58,7 @@ For a more in-depth example, see [this video](https://youtu.be/ppZ784YUKlI). - [init](#init-size) - [deinit](#deinit) - [bind](#bind-ip-port) -- [connect](#connect-ip-port) +- [connect](#connect-ip-port-fastopen) - [send](#send-message) - [benchmark](#benchmark-run-size) - [sendend](#sendend) @@ -118,7 +118,7 @@ Associates a name (i.e. IPv6 address and port) to the example TCP endpoint. Done ``` -### connect \ \ +### connect \ \ [\] Establishes a connection with the specified peer. @@ -126,6 +126,7 @@ If the connection establishment is successful, the resulting TCP connection is a - ip: the peer's IP address. - port: the peer's TCP port. +- fastopen: if "fast", TCP Fast Open is enabled for this connection; if "slow", it is not. Defaults to "slow". ```bash > tcp connect fe80:0:0:0:a8df:580a:860:ffa4 30000 diff --git a/third_party/openthread/repo/src/cli/README_UDP.md b/third_party/openthread/repo/src/cli/README_UDP.md index 14444cda..720aa880 100644 --- a/third_party/openthread/repo/src/cli/README_UDP.md +++ b/third_party/openthread/repo/src/cli/README_UDP.md @@ -169,7 +169,7 @@ The address can be an IPv4 address, which will be synthesized to an IPv6 address > Note: The command will return `InvalidState` when the preferred NAT64 prefix is unavailable. ```bash -> udp send 172.17.0.1 1234 +> udp send 172.17.0.1 1234 hello Sending to synthesized IPv6 address: fdde:ad00:beef:2:0:0:ac11:1 Done ``` diff --git a/third_party/openthread/repo/src/cli/cli.cpp b/third_party/openthread/repo/src/cli/cli.cpp index 9b8a454b..e4e62620 100644 --- a/third_party/openthread/repo/src/cli/cli.cpp +++ b/third_party/openthread/repo/src/cli/cli.cpp @@ -237,10 +237,31 @@ template <> otError Interpreter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; + /** + * @cli version + * @code + * version + * OPENTHREAD/gf4f2f04; Jul 1 2016 17:00:09 + * Done + * @endcode + * @par api_copy + * #otGetVersionString + */ if (aArgs[0].IsEmpty()) { OutputLine("%s", otGetVersionString()); } + + /** + * @cli version api + * @code + * version api + * 28 + * Done + * @endcode + * @par + * Prints the API version number. + */ else if (aArgs[0] == "api") { OutputLine("%u", OPENTHREAD_API_VERSION); @@ -255,11 +276,34 @@ template <> otError Interpreter::Process(Arg aArgs[]) template <> otError Interpreter::Process(Arg aArgs[]) { - OT_UNUSED_VARIABLE(aArgs); + otError error = OT_ERROR_NONE; + + if (aArgs[0].IsEmpty()) + { + otInstanceReset(GetInstancePtr()); + } - otInstanceReset(GetInstancePtr()); +#if OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE + /** + * @cli reset bootloader + * @code + * reset bootloader + * @endcode + * @cparam reset bootloader + * @par api_copy + * #otInstanceResetToBootloader + */ + else if (aArgs[0] == "bootloader") + { + error = otInstanceResetToBootloader(GetInstancePtr()); + } +#endif + else + { + error = OT_ERROR_INVALID_COMMAND; + } - return OT_ERROR_NONE; + return error; } void Interpreter::ProcessLine(char *aBuf) @@ -546,7 +590,7 @@ template <> otError Interpreter::Process(Arg aArgs[]) else if (aArgs[0] == "state") { static const char *const kStateStrings[] = { - "Stopped" // (0) OT_BORDER_AGENT_STATE_STOPPED + "Stopped", // (0) OT_BORDER_AGENT_STATE_STOPPED "Started", // (1) OT_BORDER_AGENT_STATE_STARTED "Active", // (2) OT_BORDER_AGENT_STATE_ACTIVE }; @@ -1136,6 +1180,22 @@ template <> otError Interpreter::Process(Arg aArgs[]) return ProcessEnableDisable(aArgs, otThreadSetCcmEnabled); } +/** + * @cli tvcheck (enable,disable) + * @code + * tvcheck enable + * Done + * @endcode + * @code + * tvcheck disable + * Done + * @endcode + * @par + * Enables or disables the Thread version check when upgrading to router or leader. + * This check is enabled by default. + * @note `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is required. + * @sa otThreadSetThreadVersionCheckEnabled + */ template <> otError Interpreter::Process(Arg aArgs[]) { return ProcessEnableDisable(aArgs, otThreadSetThreadVersionCheckEnabled); @@ -2327,23 +2387,22 @@ template <> otError Interpreter::Process(Arg aArgs[]) * @code * csl * Channel: 11 - * Period: 1000 (in units of 10 symbols), 160ms + * Period: 160000us * Timeout: 1000s * Done * @endcode * @par * Gets the CSL configuration. - * @sa otLinkCslGetChannel - * @sa otLinkCslGetPeriod - * @sa otLinkCslGetPeriod - * @sa otLinkCslGetTimeout + * @sa otLinkGetCslChannel + * @sa otLinkGetCslPeriod + * @sa otLinkGetCslPeriod + * @sa otLinkGetCslTimeout */ if (aArgs[0].IsEmpty()) { - OutputLine("Channel: %u", otLinkCslGetChannel(GetInstancePtr())); - OutputLine("Period: %u(in units of 10 symbols), %lums", otLinkCslGetPeriod(GetInstancePtr()), - ToUlong(otLinkCslGetPeriod(GetInstancePtr()) * kUsPerTenSymbols / 1000)); - OutputLine("Timeout: %lus", ToUlong(otLinkCslGetTimeout(GetInstancePtr()))); + OutputLine("Channel: %u", otLinkGetCslChannel(GetInstancePtr())); + OutputLine("Period: %luus", ToUlong(otLinkGetCslPeriod(GetInstancePtr()))); + OutputLine("Timeout: %lus", ToUlong(otLinkGetCslTimeout(GetInstancePtr()))); } /** * @cli csl channel @@ -2353,25 +2412,25 @@ template <> otError Interpreter::Process(Arg aArgs[]) * @endcode * @cparam csl channel @ca{channel} * @par api_copy - * #otLinkCslSetChannel + * #otLinkSetCslChannel */ else if (aArgs[0] == "channel") { - error = ProcessSet(aArgs + 1, otLinkCslSetChannel); + error = ProcessSet(aArgs + 1, otLinkSetCslChannel); } /** * @cli csl period * @code - * csl period 3000 + * csl period 3000000 * Done * @endcode * @cparam csl period @ca{period} * @par api_copy - * #otLinkCslSetPeriod + * #otLinkSetCslPeriod */ else if (aArgs[0] == "period") { - error = ProcessSet(aArgs + 1, otLinkCslSetPeriod); + error = ProcessSet(aArgs + 1, otLinkSetCslPeriod); } /** * @cli csl timeout @@ -2381,11 +2440,11 @@ template <> otError Interpreter::Process(Arg aArgs[]) * @endcode * @cparam csl timeout @ca{timeout} * @par api_copy - * #otLinkCslSetTimeout + * #otLinkSetCslTimeout */ else if (aArgs[0] == "timeout") { - error = ProcessSet(aArgs + 1, otLinkCslSetTimeout); + error = ProcessSet(aArgs + 1, otLinkSetCslTimeout); } else { @@ -2443,18 +2502,41 @@ template <> otError Interpreter::Process(Arg aArgs[]) } #endif +/** + * @cli detach + * @code + * detach + * Finished detaching + * Done + * @endcode + * @par + * Start the graceful detach process by first notifying other nodes (sending Address Release if acting as a router, or + * setting Child Timeout value to zero on parent if acting as a child) and then stopping Thread protocol operation. + * @sa otThreadDetachGracefully + */ template <> otError Interpreter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; + /** + * @cli detach async + * @code + * detach async + * Done + * @endcode + * @par + * Start the graceful detach process similar to the `detach` command without blocking and waiting for the callback + * indicating that detach is finished. + * @csa{detach} + * @sa otThreadDetachGracefully + */ if (aArgs[0] == "async") { SuccessOrExit(error = otThreadDetachGracefully(GetInstancePtr(), nullptr, nullptr)); } else { - SuccessOrExit(error = - otThreadDetachGracefully(GetInstancePtr(), &Interpreter::HandleDetachGracefullyResult, this)); + SuccessOrExit(error = otThreadDetachGracefully(GetInstancePtr(), HandleDetachGracefullyResult, this)); error = OT_ERROR_PENDING; } @@ -2462,6 +2544,17 @@ template <> otError Interpreter::Process(Arg aArgs[]) return error; } +void Interpreter::HandleDetachGracefullyResult(void *aContext) +{ + static_cast(aContext)->HandleDetachGracefullyResult(); +} + +void Interpreter::HandleDetachGracefullyResult(void) +{ + OutputLine("Finished detaching"); + OutputResult(OT_ERROR_NONE); +} + /** * @cli discover * @code @@ -2689,6 +2782,17 @@ template <> otError Interpreter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; + /** + * @cli log level + * @code + * log level + * 1 + * Done + * @endcode + * @par + * Get the log level. + * @sa otLoggingGetLevel + */ if (aArgs[0] == "level") { if (aArgs[1].IsEmpty()) @@ -2700,6 +2804,16 @@ template <> otError Interpreter::Process(Arg aArgs[]) #if OPENTHREAD_CONFIG_LOG_LEVEL_DYNAMIC_ENABLE uint8_t level; + /** + * @cli log level (set) + * @code + * log level 4 + * Done + * @endcode + * @par api_copy + * #otLoggingSetLevel + * @cparam log level @ca{level} + */ VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS); SuccessOrExit(error = aArgs[1].ParseAsUint8(level)); error = otLoggingSetLevel(static_cast(level)); @@ -2709,6 +2823,18 @@ template <> otError Interpreter::Process(Arg aArgs[]) } } #if (OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_DEBUG_UART) && OPENTHREAD_POSIX + /** + * @cli log filename + * @par + * Specifies filename to capture `otPlatLog()` messages, useful when debugging + * automated test scripts on Linux when logging disrupts the automated test scripts. + * @par + * Requires `OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_DEBUG_UART` + * and `OPENTHREAD_POSIX`. + * @par api_copy + * #otPlatDebugUart_logfile + * @cparam log filename @ca{filename} + */ else if (aArgs[0] == "filename") { VerifyOrExit(!aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); @@ -3022,13 +3148,18 @@ template <> otError Interpreter::Process(Arg aArgs[]) * @endcode * @code * ipaddr -v - * fdde:ad00:beef:0:0:ff:fe00:0 origin:thread - * fdde:ad00:beef:0:558:f56b:d688:799 origin:thread - * fe80:0:0:0:f3d9:2a82:c8d8:fe43 origin:thread + * fd5e:18fa:f4a5:b8:0:ff:fe00:fc00 origin:thread plen:64 preferred:0 valid:1 + * fd5e:18fa:f4a5:b8:0:ff:fe00:dc00 origin:thread plen:64 preferred:0 valid:1 + * fd5e:18fa:f4a5:b8:f8e:5d95:87a0:e82c origin:thread plen:64 preferred:0 valid:1 + * fe80:0:0:0:4891:b191:e277:8826 origin:thread plen:64 preferred:1 valid:1 * Done * @endcode * @cparam ipaddr [@ca{-v}] - * Use `-v` to get verbose IP Address information. + * Use `-v` to get more verbose information about the address: + * - `origin`: can be `thread`, `slaac`, `dhcp6`, `manual` and indicates the origin of the address + * - `plen`: prefix length + * - `preferred`: preferred flag (boolean) + * - `valid`: valid flag (boolean) * @par api_copy * #otIp6GetUnicastAddresses */ @@ -3042,7 +3173,8 @@ template <> otError Interpreter::Process(Arg aArgs[]) if (verbose) { - OutputFormat(" origin:%s", AddressOriginToString(addr->mAddressOrigin)); + OutputFormat(" origin:%s plen:%u preferred:%u valid:%u", AddressOriginToString(addr->mAddressOrigin), + addr->mPrefixLength, addr->mPreferred, addr->mValid); } OutputNewLine(); @@ -3436,7 +3568,7 @@ template <> otError Interpreter::Process(Arg aArgs[]) return ProcessGetSet(aArgs, otThreadGetLocalLeaderWeight, otThreadSetLocalLeaderWeight); } -#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_3_1) +#if OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE template <> otError Interpreter::Process(Arg aArgs[]) { static const char *const kPowerSupplyStrings[4] = { @@ -3535,14 +3667,14 @@ template <> otError Interpreter::Process(Arg aArgs[]) exit: return error; } -#endif // #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_3_1) +#endif // OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE #endif // OPENTHREAD_FTD #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE void Interpreter::HandleLinkMetricsReport(const otIp6Address *aAddress, const otLinkMetricsValues *aMetricsValues, - uint8_t aStatus, + otLinkMetricsStatus aStatus, void *aContext) { static_cast(aContext)->HandleLinkMetricsReport(aAddress, aMetricsValues, aStatus); @@ -3575,7 +3707,7 @@ void Interpreter::PrintLinkMetricsValue(const otLinkMetricsValues *aMetricsValue void Interpreter::HandleLinkMetricsReport(const otIp6Address *aAddress, const otLinkMetricsValues *aMetricsValues, - uint8_t aStatus) + otLinkMetricsStatus aStatus) { OutputFormat("Received Link Metrics Report from: "); OutputIp6AddressLine(*aAddress); @@ -3596,12 +3728,14 @@ void Interpreter::HandleLinkMetricsReport(const otIp6Address *aAddress, } } -void Interpreter::HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, uint8_t aStatus, void *aContext) +void Interpreter::HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, + otLinkMetricsStatus aStatus, + void *aContext) { static_cast(aContext)->HandleLinkMetricsMgmtResponse(aAddress, aStatus); } -void Interpreter::HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, uint8_t aStatus) +void Interpreter::HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, otLinkMetricsStatus aStatus) { OutputFormat("Received Link Metrics Management Response from: "); OutputIp6AddressLine(*aAddress); @@ -3631,7 +3765,7 @@ void Interpreter::HandleLinkMetricsEnhAckProbingIe(otShortAddress aS } } -const char *Interpreter::LinkMetricsStatusToStr(uint8_t aStatus) +const char *Interpreter::LinkMetricsStatusToStr(otLinkMetricsStatus aStatus) { static const char *const kStatusStrings[] = { "Success", // (0) OT_LINK_METRICS_STATUS_SUCCESS @@ -3774,6 +3908,72 @@ template <> otError Interpreter::Process(Arg aArgs[]) return error; } +#if OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE +template <> otError Interpreter::Process(Arg aArgs[]) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(!aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS); + + /** + * @cli linkmetricsmgr (enable,disable) + * @code + * linkmetricmgr enable + * Done + * @endcode + * @code + * linkmetricmgr disable + * Done + * @endcode + * @cparam linkmetricsmgr @ca{enable|disable} + * @par api_copy + * #otLinkMetricsManagerSetEnabled + * + */ + if (ProcessEnableDisable(aArgs, otLinkMetricsManagerSetEnabled) == OT_ERROR_NONE) + { + } + /** + * @cli linkmetricsmgr show + * @code + * linkmetricsmgr show + * ExtAddr:827aa7f7f63e1234, LinkMargin:80, Rssi:-20 + * Done + * @endcode + * @par api_copy + * #otLinkMetricsManagerGetMetricsValueByExtAddr + * + */ + else if (aArgs[0] == "show") + { + otNeighborInfoIterator iterator = OT_NEIGHBOR_INFO_ITERATOR_INIT; + otNeighborInfo neighborInfo; + + while (otThreadGetNextNeighborInfo(GetInstancePtr(), &iterator, &neighborInfo) == OT_ERROR_NONE) + { + otLinkMetricsValues linkMetricsValues; + + if (otLinkMetricsManagerGetMetricsValueByExtAddr(GetInstancePtr(), &neighborInfo.mExtAddress, + &linkMetricsValues) != OT_ERROR_NONE) + { + continue; + } + + OutputFormat("ExtAddr:"); + OutputExtAddress(neighborInfo.mExtAddress); + OutputLine(", LinkMargin:%u, Rssi:%d", linkMetricsValues.mLinkMarginValue, linkMetricsValues.mRssiValue); + } + } + else + { + error = OT_ERROR_INVALID_COMMAND; + } + +exit: + return error; +} +#endif // OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE + otError Interpreter::ParseLinkMetricsFlags(otLinkMetrics &aLinkMetrics, const Arg &aFlags) { otError error = OT_ERROR_NONE; @@ -3990,12 +4190,51 @@ template <> otError Interpreter::Process(Arg aArgs[]) otError error = OT_ERROR_INVALID_ARGS; otIp6Address anycastAddress; + /** + * @cli locate + * @code + * locate + * Idle + * Done + * @endcode + * @code + * locate fdde:ad00:beef:0:0:ff:fe00:fc10 + * @endcode + * @code + * locate + * In Progress + * Done + * @endcode + * @par + * Gets the current state (`In Progress` or `Idle`) of anycast locator. + * @par + * Available when `OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE` is enabled. + * @sa otThreadIsAnycastLocateInProgress + */ if (aArgs[0].IsEmpty()) { OutputLine(otThreadIsAnycastLocateInProgress(GetInstancePtr()) ? "In Progress" : "Idle"); ExitNow(error = OT_ERROR_NONE); } + /** + * @cli locate (set) + * @code + * locate fdde:ad00:beef:0:0:ff:fe00:fc00 + * fdde:ad00:beef:0:d9d3:9000:16b:d03b 0xc800 + * Done + * @endcode + * @par + * Locate the closest destination of an anycast address (i.e., find the + * destination's mesh local EID and RLOC16). + * @par + * The closest destination is determined based on the current routing + * table and path costs within the Thread mesh. + * @par + * Available when `OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE` is enabled. + * @sa otThreadLocateAnycastDestination + * @cparam locate @ca{anycastaddr} + */ SuccessOrExit(error = aArgs[0].ParseAsIp6Address(anycastAddress)); SuccessOrExit(error = otThreadLocateAnycastDestination(GetInstancePtr(), &anycastAddress, HandleLocateResult, this)); @@ -4041,17 +4280,48 @@ template <> otError Interpreter::Process(Arg aArgs[]) otError error = OT_ERROR_NONE; otPskc pskc; + /** + * @cli pskc + * @code + * pskc + * 67c0c203aa0b042bfb5381c47aef4d9e + * Done + * @endcode + * @par api_copy + * #otThreadGetPskc + */ if (aArgs[0].IsEmpty()) { otThreadGetPskc(GetInstancePtr(), &pskc); OutputBytesLine(pskc.m8); } else + /** + * @cli pskc (set) + * @code + * pskc 67c0c203aa0b042bfb5381c47aef4d9e + * Done + * @endcode + * @cparam pskc @ca{key} + * @par + * Sets the pskc in hexadecimal format. + */ { if (aArgs[1].IsEmpty()) { SuccessOrExit(error = aArgs[0].ParseAsHexString(pskc.m8)); } + /** + * @cli pskc -p + * @code + * pskc -p 123456 + * Done + * @endcode + * @cparam pskc -p @ca{passphrase} + * @par + * Generates the pskc from the passphrase (UTF-8 encoded), together with the current network name and extended + * PAN ID. + */ else if (aArgs[0] == "-p") { SuccessOrExit(error = otDatasetGeneratePskc( @@ -4076,6 +4346,16 @@ template <> otError Interpreter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; + /** + * @cli pskcref + * @code + * pskcref + * 0x80000000 + * Done + * @endcode + * @par api_copy + * #otThreadGetPskcRef + */ if (aArgs[0].IsEmpty()) { OutputLine("0x%08lx", ToUlong(otThreadGetPskcRef(GetInstancePtr()))); @@ -4084,6 +4364,16 @@ template <> otError Interpreter::Process(Arg aArgs[]) { otPskcRef pskcRef; + /** + * @cli pskcref (set) + * @code + * pskc 0x20017 + * Done + * @endcode + * @cparam pskc @ca{keyref} + * @par api_copy + * #otThreadSetPskcRef + */ if (aArgs[1].IsEmpty()) { SuccessOrExit(error = aArgs[0].ParseAsUint32(pskcRef)); @@ -4102,6 +4392,23 @@ template <> otError Interpreter::Process(Arg aArgs[]) #endif #endif // OPENTHREAD_FTD +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE +/** + * @cli mleadvimax + * @code + * mleadvimax + * 12000 + * Done + * @endcode + * @par api_copy + * #otThreadGetAdvertisementTrickleIntervalMax + */ +template <> otError Interpreter::Process(Arg aArgs[]) +{ + return ProcessGet(aArgs, otThreadGetAdvertisementTrickleIntervalMax); +} +#endif + #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE /** * @cli mliid @@ -4447,6 +4754,29 @@ template <> otError Interpreter::Process(Arg aArgs[]) while (otThreadGetNextNeighborInfo(GetInstancePtr(), &iterator, &neighborInfo) == OT_ERROR_NONE) { + /** + * @cli neighbor table + * @code + * neighbor table + * | Role | RLOC16 | Age | Avg RSSI | Last RSSI |R|D|N| Extended MAC | + * +------+--------+-----+----------+-----------+-+-+-+------------------+ + * | C | 0xcc01 | 96 | -46 | -46 |1|1|1| 1eb9ba8a6522636b | + * | R | 0xc800 | 2 | -29 | -29 |1|1|1| 9a91556102c39ddb | + * | R | 0xf000 | 3 | -28 | -28 |1|1|1| 0ad7ed6beaa6016d | + * Done + * @endcode + * @par + * Prints information in table format about all neighbors. + * @par + * For `Role`, the only possible values for this table are `C` (Child) or `R` (Router). + * @par + * The following columns provide information about the device mode of neighbors. + * Each column has a value of `0` (off) or `1` (on). + * - `R`: RX on when idle + * - `D`: Full Thread device + * - `N`: Full network data + * @sa otThreadGetNextNeighborInfo + */ if (isTable) { OutputFormat("| %3c ", neighborInfo.mIsChild ? 'C' : 'R'); @@ -4461,6 +4791,16 @@ template <> otError Interpreter::Process(Arg aArgs[]) OutputExtAddress(neighborInfo.mExtAddress); OutputLine(" | %7d |", neighborInfo.mVersion); } + /** + * @cli neighbor list + * @code + * neighbor list + * 0xcc01 0xc800 0xf000 + * Done + * @endcode + * @par + * Lists the RLOC16 of each neighbor. + */ else { OutputFormat("0x%04x ", neighborInfo.mRloc16); @@ -4469,6 +4809,19 @@ template <> otError Interpreter::Process(Arg aArgs[]) OutputNewLine(); } + /** + * @cli neighbor linkquality + * @code + * neighbor linkquality + * | RLOC16 | Extended MAC | Frame Error | Msg Error | Avg RSS | Last RSS | Age | + * +--------+------------------+-------------+-----------+---------+----------+-------+ + * | 0xe800 | 9e2fa4e1b84f92db | 0.00 % | 0.00 % | -46 | -48 | 1 | + * | 0xc001 | 0ad7ed6beaa6016d | 4.67 % | 0.08 % | -68 | -72 | 10 | + * Done + * @endcode + * @par + * Prints link quality information about all neighbors. + */ else if (aArgs[0] == "linkquality") { static const char *const kLinkQualityTableTitles[] = { @@ -4507,13 +4860,14 @@ template <> otError Interpreter::Process(Arg aArgs[]) * Done * @endcode * @par - * Print the connection time and age of neighbors. Info per neighbor: + * Prints the connection time and age of neighbors. Information per neighbor: * - RLOC16 - * - Extended MAC address - * - Last Heard (seconds since last heard from neighbor) - * - Connection time (seconds since link establishment with neighbor) + * - Extended MAC + * - Last Heard (Age): Number of seconds since last heard from neighbor. + * - Connection Time: Number of seconds since link establishment with neighbor. * Duration intervals are formatted as `{hh}:{mm}:{ss}` for hours, minutes, and seconds if the duration is less * than one day. If the duration is longer than one day, the format is `{dd}d.{hh}:{mm}:{ss}`. + * @csa{neighbor conntime list} */ else if (aArgs[0] == "conntime") { @@ -4527,9 +4881,10 @@ template <> otError Interpreter::Process(Arg aArgs[]) * Done * @endcode * @par - * Print connection time and age of neighbors. + * Prints the connection time and age of neighbors. * This command is similar to `neighbor conntime`, but it displays the information in a list format. The age * and connection time are both displayed in seconds. + * @csa{neighbor conntime} */ if (aArgs[1] == "list") { @@ -4581,6 +4936,21 @@ template <> otError Interpreter::Process(Arg aArgs[]) } #endif // OPENTHREAD_FTD +/** + * @cli netstat + * @code + * netstat + * | Local Address | Peer Address | + * +-------------------------------------------------+-------------------------------------------------+ + * | [0:0:0:0:0:0:0:0]:49153 | [0:0:0:0:0:0:0:0]:0 | + * | [0:0:0:0:0:0:0:0]:49152 | [0:0:0:0:0:0:0:0]:0 | + * | [0:0:0:0:0:0:0:0]:61631 | [0:0:0:0:0:0:0:0]:0 | + * | [0:0:0:0:0:0:0:0]:19788 | [0:0:0:0:0:0:0:0]:0 | + * Done + * @endcode + * @par api_copy + * #otUdpGetSockets + */ template <> otError Interpreter::Process(Arg aArgs[]) { OT_UNUSED_VARIABLE(aArgs); @@ -4632,6 +5002,29 @@ template <> otError Interpreter::Process(Arg aArgs[]) VerifyOrExit(length > 0, error = OT_ERROR_INVALID_ARGS); cfg.mServiceDataLength = static_cast(length); + /** + * @cli service add + * @code + * service add 44970 112233 aabbcc + * Done + * @endcode + * @code + * netdata register + * Done + * @endcode + * @cparam service add @ca{enterpriseNumber} @ca{serviceData} @ca{serverData} + * @par + * Adds service to the network data. + * @par + * - enterpriseNumber: IANA enterprise number + * - serviceData: Hex-encoded binary service data + * - serverData: Hex-encoded binary server data + * @par + * Note: For each change in service registration to take effect, run + * the `netdata register` command after running the `service add` command to notify the leader. + * @sa otServerAddService + * @csa{netdata register} + */ if (aArgs[0] == "add") { length = sizeof(cfg.mServerConfig.mServerData); @@ -4643,6 +5036,28 @@ template <> otError Interpreter::Process(Arg aArgs[]) error = otServerAddService(GetInstancePtr(), &cfg); } + /** + * @cli service remove + * @code + * service remove 44970 112233 + * Done + * @endcode + * @code + * netdata register + * Done + * @endcode + * @cparam service remove @ca{enterpriseNumber} @ca{serviceData} + * @par + * Removes service from the network data. + * @par + * - enterpriseNumber: IANA enterprise number + * - serviceData: Hex-encoded binary service data + * @par + * Note: For each change in service registration to take effect, run + * the `netdata register` command after running the `service remove` command to notify the leader. + * @sa otServerRemoveService + * @csa{netdata register} + */ else if (aArgs[0] == "remove") { error = otServerRemoveService(GetInstancePtr(), cfg.mEnterpriseNumber, cfg.mServiceData, @@ -4658,6 +5073,27 @@ template <> otError Interpreter::Process(Arg aArgs[]) template <> otError Interpreter::Process(Arg aArgs[]) { return mNetworkData.Process(aArgs); } #if OPENTHREAD_FTD +/** + * @cli networkidtimeout (get,set) + * @code + * networkidtimeout 120 + * Done + * @endcode + * @code + * networkidtimeout + * 120 + * Done + * @endcode + * @cparam networkidtimeout [@ca{timeout}] + * Use the optional `timeout` argument to set the value of the `NETWORK_ID_TIMEOUT` parameter. + * @par + * Gets or sets the `NETWORK_ID_TIMEOUT` parameter. + * @note This command is reserved for testing and demo purposes only. + * Changing settings with this API will render a production application + * non-compliant with the Thread Specification. + * @sa otThreadGetNetworkIdTimeout + * @sa otThreadSetNetworkIdTimeout + */ template <> otError Interpreter::Process(Arg aArgs[]) { return ProcessGetSet(aArgs, otThreadGetNetworkIdTimeout, otThreadSetNetworkIdTimeout); @@ -5206,7 +5642,7 @@ void Interpreter::HandleMeshDiagDiscoverDone(otError aError, otMeshDiagRouterInf { OutputFormat(kIndentSize, "%u-links:{ ", linkQuality); - for (uint8_t id = 0; id < OT_ARRAY_LENGTH(aRouterInfo->mLinkQualities); id++) + for (uint8_t id = 0; id < static_cast(OT_ARRAY_LENGTH(aRouterInfo->mLinkQualities)); id++) { if (aRouterInfo->mLinkQualities[id] == linkQuality) { @@ -5606,7 +6042,7 @@ void Interpreter::HandlePingStatistics(const otPingSenderStatistics *aStatistics * 1 packets transmitted, 1 packets received. Packet loss = 0.0%. Round-trip min/avg/max = 0/0.0/0 ms. * Done * @endcode - * @cparam ping [@ca{async}] [@ca{-I source}] @ca{ipaddrc} [@ca{size}] [@ca{count}] [@ca{interval}] [@ca{hoplimit}] [@ca{timeout}] * @par * Send an ICMPv6 Echo Request. @@ -5614,6 +6050,9 @@ void Interpreter::HandlePingStatistics(const otPingSenderStatistics *aStatistics * The address can be an IPv4 address, which will be synthesized to an IPv6 address using the preferred NAT64 prefix * from the network data. * @par + * The optional `-m` flag sets the multicast loop flag, which allows looping back pings to multicast addresses that the + * device itself is subscribed to. + * @par * Note: The command will return InvalidState when the preferred NAT64 prefix is unavailable. * @sa otPingSenderPing */ @@ -5652,26 +6091,17 @@ template <> otError Interpreter::Process(Arg aArgs[]) SuccessOrExit(error = aArgs[1].ParseAsIp6Address(config.mSource)); #if !OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE - { - bool valid = false; - const otNetifAddress *unicastAddrs = otIp6GetUnicastAddresses(GetInstancePtr()); - - for (const otNetifAddress *addr = unicastAddrs; addr; addr = addr->mNext) - { - if (otIp6IsAddressEqual(&addr->mAddress, &config.mSource)) - { - valid = true; - break; - } - } - - VerifyOrExit(valid, error = OT_ERROR_INVALID_ARGS); - } + VerifyOrExit(otIp6HasUnicastAddress(GetInstancePtr(), &config.mSource), error = OT_ERROR_INVALID_ARGS); #endif - aArgs += 2; } + if (aArgs[0] == "-m") + { + config.mMulticastLoop = true; + aArgs++; + } + SuccessOrExit(error = ParseToIp6Address(GetInstancePtr(), aArgs[0], config.mDestination, nat64SynthesizedAddress)); if (nat64SynthesizedAddress) { @@ -5772,6 +6202,17 @@ template <> otError Interpreter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; + /** + * @cli promiscuous + * @code + * promiscuous + * Disabled + * Done + * @endcode + * @par api_copy + * #otLinkIsPromiscuous + * @sa otPlatRadioGetPromiscuous + */ if (aArgs[0].IsEmpty()) { OutputEnabledDisabledStatus(otLinkIsPromiscuous(GetInstancePtr()) && @@ -5783,6 +6224,20 @@ template <> otError Interpreter::Process(Arg aArgs[]) SuccessOrExit(error = ParseEnableOrDisable(aArgs[0], enable)); + /** + * @cli promiscuous (enable,disable) + * @code + * promiscuous enable + * Done + * @endcode + * @code + * promiscuous disable + * Done + * @endcode + * @cparam promiscuous @ca{enable|disable} + * @par api_copy + * #otLinkSetPromiscuous + */ if (!enable) { otLinkSetPcapCallback(GetInstancePtr(), nullptr, nullptr); @@ -5807,70 +6262,19 @@ void Interpreter::HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx, void Interpreter::HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx) { - OT_UNUSED_VARIABLE(aIsTx); - - OutputNewLine(); - - for (size_t i = 0; i < 44; i++) - { - OutputFormat("="); - } - - OutputFormat("[len = %3u]", aFrame->mLength); + otLogHexDumpInfo info; - for (size_t i = 0; i < 28; i++) - { - OutputFormat("="); - } + info.mDataBytes = aFrame->mPsdu; + info.mDataLength = aFrame->mLength; + info.mTitle = (aIsTx) ? "TX" : "RX"; + info.mIterator = 0; OutputNewLine(); - for (size_t i = 0; i < aFrame->mLength; i += 16) - { - OutputFormat("|"); - - for (size_t j = 0; j < 16; j++) - { - if (i + j < aFrame->mLength) - { - OutputFormat(" %02X", aFrame->mPsdu[i + j]); - } - else - { - OutputFormat(" .."); - } - } - - OutputFormat("|"); - - for (size_t j = 0; j < 16; j++) - { - if (i + j < aFrame->mLength) - { - if (31 < aFrame->mPsdu[i + j] && aFrame->mPsdu[i + j] < 127) - { - OutputFormat(" %c", aFrame->mPsdu[i + j]); - } - else - { - OutputFormat(" ?"); - } - } - else - { - OutputFormat(" ."); - } - } - - OutputLine("|"); - } - - for (size_t i = 0; i < 83; i++) + while (otLogGenerateNextHexDumpLine(&info) == OT_ERROR_NONE) { - OutputFormat("-"); + OutputLine("%s", info.mLine); } - - OutputNewLine(); } #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE @@ -6063,6 +6467,17 @@ template <> otError Interpreter::Process(Arg aArgs[]) } #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE +/** + * @cli preferrouterid + * @code + * preferrouterid 16 + * Done + * @endcode + * @cparam preferrouterid @ca{routerid} + * @par + * Specifies the preferred router ID that the leader should provide when solicited. + * @sa otThreadSetPreferredRouterId + */ #if OPENTHREAD_FTD template <> otError Interpreter::Process(Arg aArgs[]) { @@ -6105,7 +6520,7 @@ template <> otError Interpreter::Process(Arg aArgs[]) * radio disable * Done * @endcode - * @cparam radio [@ca{enable|disable}] + * @cparam radio @ca{enable|disable} * @sa otLinkSetEnabled * @par * Enables or disables the radio. @@ -6215,7 +6630,7 @@ template <> otError Interpreter::Process(Arg aArgs[]) * Done * @endcode * @par api_copy - * #otPlatRadioGetRegion + * #otLinkGetRegion */ template <> otError Interpreter::Process(Arg aArgs[]) { @@ -6224,7 +6639,7 @@ template <> otError Interpreter::Process(Arg aArgs[]) if (aArgs[0].IsEmpty()) { - SuccessOrExit(error = otPlatRadioGetRegion(GetInstancePtr(), ®ionCode)); + SuccessOrExit(error = otLinkGetRegion(GetInstancePtr(), ®ionCode)); OutputLine("%c%c", regionCode >> 8, regionCode & 0xff); } /** @@ -6234,7 +6649,7 @@ template <> otError Interpreter::Process(Arg aArgs[]) * Done * @endcode * @par api_copy - * #otPlatRadioSetRegion + * #otLinkSetRegion * @par * Changing this can affect the transmit power limit. */ @@ -6245,7 +6660,7 @@ template <> otError Interpreter::Process(Arg aArgs[]) regionCode = static_cast(static_cast(aArgs[0].GetCString()[0]) << 8) + static_cast(aArgs[0].GetCString()[1]); - error = otPlatRadioSetRegion(GetInstancePtr(), regionCode); + error = otLinkSetRegion(GetInstancePtr(), regionCode); } exit: @@ -6321,6 +6736,10 @@ otError Interpreter::ParseRoute(Arg aArgs[], otExternalRouteConfig &aConfig) aConfig.mNat64 = true; break; + case 'a': + aConfig.mAdvPio = true; + break; + case '-': break; @@ -6698,6 +7117,44 @@ template <> otError Interpreter::Process(Arg aArgs[]) scanChannels = 1 << channel; } + /** + * @cli scan energy + * @code + * scan energy 10 + * | Ch | RSSI | + * +----+------+ + * | 11 | -59 | + * | 12 | -62 | + * | 13 | -67 | + * | 14 | -61 | + * | 15 | -87 | + * | 16 | -86 | + * | 17 | -86 | + * | 18 | -52 | + * | 19 | -58 | + * | 20 | -82 | + * | 21 | -76 | + * | 22 | -82 | + * | 23 | -74 | + * | 24 | -81 | + * | 25 | -88 | + * | 26 | -71 | + * Done + * @endcode + * @code + * scan energy 10 20 + * | Ch | RSSI | + * +----+------+ + * | 20 | -82 | + * Done + * @endcode + * @cparam scan energy [@ca{duration}] [@ca{channel}] + * @par + * Performs an IEEE 802.15.4 energy scan, and displays the time in milliseconds + * to use for scanning each channel. All channels are shown unless you specify a certain channel + * by using the channel option. + * @sa otLinkEnergyScan + */ if (energyScan) { static const char *const kEnergyScanTableTitles[] = {"Ch", "RSSI"}; @@ -6707,6 +7164,21 @@ template <> otError Interpreter::Process(Arg aArgs[]) SuccessOrExit(error = otLinkEnergyScan(GetInstancePtr(), scanChannels, scanDuration, &Interpreter::HandleEnergyScanResult, this)); } + /** + * @cli scan + * @code + * scan + * | PAN | MAC Address | Ch | dBm | LQI | + * +------+------------------+----+-----+-----+ + * | ffff | f1d92a82c8d8fe43 | 11 | -20 | 0 | + * Done + * @endcode + * @cparam scan [@ca{channel}] + * @par + * Performs an active IEEE 802.15.4 scan. The scan covers all channels if no channel is specified; otherwise the + * span covers only the channel specified. + * @sa otLinkActiveScan + */ else { static const char *const kScanTableTitles[] = {"PAN", "MAC Address", "Ch", "dBm", "LQI"}; @@ -6775,6 +7247,18 @@ void Interpreter::HandleEnergyScanResult(otEnergyScanResult *aResult) return; } +/** + * @cli singleton + * @code + * singleton + * true + * Done + * @endcode + * @par + * Indicates whether a node is the only router on the network. + * Returns either `true` or `false`. + * @sa otThreadIsSingleton + */ template <> otError Interpreter::Process(Arg aArgs[]) { OT_UNUSED_VARIABLE(aArgs); @@ -6792,6 +7276,26 @@ template <> otError Interpreter::Process(Arg aArgs[]) Ip6::MessageInfo messageInfo; otSntpQuery query; + /** + * @cli sntp query + * @code + * sntp query + * SNTP response - Unix time: 1540894725 (era: 0) + * Done + * @endcode + * @code + * sntp query 64:ff9b::d8ef:2308 + * SNTP response - Unix time: 1540898611 (era: 0) + * Done + * @endcode + * @cparam sntp query [@ca{SNTP server IP}] [@ca{SNTP server port}] + * @par + * Sends an SNTP query to obtain the current unix epoch time (from January 1, 1970). + * - SNTP server default IP address: `2001:4860:4806:8::` (Google IPv6 NTP Server) + * - SNTP server default port: `123` + * @note This command is available only if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE is enabled. + * @sa #otSntpClientQuery + */ if (aArgs[0] == "query") { VerifyOrExit(!mSntpQueryingInProgress, error = OT_ERROR_BUSY); @@ -6894,6 +7398,35 @@ template <> otError Interpreter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; + /** + * @cli state + * @code + * state + * child + * Done + * @endcode + * @code + * state leader + * Done + * @endcode + * @cparam state [@ca{child}|@ca{router}|@ca{leader}|@ca{detached}] + * @par + * Returns the current role of the Thread device, or changes the role as specified with one of the options. + * Possible values returned when inquiring about the device role: + * - `child`: The device is currently operating as a Thread child. + * - `router`: The device is currently operating as a Thread router. + * - `leader`: The device is currently operating as a Thread leader. + * - `detached`: The device is not currently participating in a Thread network/partition. + * - `disabled`: The Thread stack is currently disabled. + * @par + * Using one of the options allows you to change the current role of a device, with the exclusion of + * changing to or from a `disabled` state. + * @sa otThreadGetDeviceRole + * @sa otThreadBecomeChild + * @sa otThreadBecomeRouter + * @sa otThreadBecomeLeader + * @sa otThreadBecomeDetached + */ if (aArgs[0].IsEmpty()) { OutputLine("%s", otThreadDeviceRoleToString(otThreadGetDeviceRole(GetInstancePtr()))); @@ -6928,14 +7461,43 @@ template <> otError Interpreter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; + /** + * @cli thread start + * @code + * thread start + * Done + * @endcode + * @par + * Starts the Thread protocol operation. + * @note The interface must be up when running this command. + * @sa otThreadSetEnabled + */ if (aArgs[0] == "start") { error = otThreadSetEnabled(GetInstancePtr(), true); } + /** + * @cli thread stop + * @code + * thread stop + * Done + * @endcode + * @par + * Stops the Thread protocol operation. + */ else if (aArgs[0] == "stop") { error = otThreadSetEnabled(GetInstancePtr(), false); } + /** + * @cli thread version + * @code thread version + * 2 + * Done + * @endcode + * @par api_copy + * #otThreadGetVersion + */ else if (aArgs[0] == "version") { OutputLine("%u", otThreadGetVersion()); @@ -7083,6 +7645,23 @@ template <> otError Interpreter::Process(Arg aArgs[]) template <> otError Interpreter::Process(Arg aArgs[]) { return mDataset.Process(aArgs); } +/** + * @cli txpower (get,set) + * @code + * txpower -10 + * Done + * @endcode + * @code + * txpower + * -10 dBm + * Done + * @endcode + * @cparam txpower [@ca{txpower}] + * @par + * Gets (or sets with the use of the optional `txpower` argument) the transmit power in dBm. + * @sa otPlatRadioGetTransmitPower + * @sa otPlatRadioSetTransmitPower + */ template <> otError Interpreter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; @@ -7113,10 +7692,36 @@ template <> otError Interpreter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; + /** + * @cli unsecureport add + * @code + * unsecureport add 1234 + * Done + * @endcode + * @cparam unsecureport add @ca{port} + * @par api_copy + * #otIp6AddUnsecurePort + */ if (aArgs[0] == "add") { error = ProcessSet(aArgs + 1, otIp6AddUnsecurePort); } + /** + * @cli unsecureport remove + * @code + * unsecureport remove 1234 + * Done + * @endcode + * @code + * unsecureport remove all + * Done + * @endcode + * @cparam unsecureport remove @ca{port}|all + * @par + * Removes a specified port or all ports from the allowed unsecured port list. + * @sa otIp6AddUnsecurePort + * @sa otIp6RemoveAllUnsecurePorts + */ else if (aArgs[0] == "remove") { if (aArgs[1] == "all") @@ -7128,6 +7733,17 @@ template <> otError Interpreter::Process(Arg aArgs[]) error = ProcessSet(aArgs + 1, otIp6RemoveUnsecurePort); } } + /** + * @cli unsecure get + * @code + * unsecure get + * 1234 + * Done + * @endcode + * @par + * Lists all ports from the allowed unsecured port list. + * @sa otIp6GetUnsecurePorts + */ else if (aArgs[0] == "get") { const uint16_t *ports; @@ -7158,6 +7774,16 @@ template <> otError Interpreter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; + /** + * @cli uptime + * @code + * uptime + * 12:46:35.469 + * Done + * @endcode + * @par api_copy + * #otInstanceGetUptimeAsString + */ if (aArgs[0].IsEmpty()) { char string[OT_UPTIME_STRING_SIZE]; @@ -7165,6 +7791,17 @@ template <> otError Interpreter::Process(Arg aArgs[]) otInstanceGetUptimeAsString(GetInstancePtr(), string, sizeof(string)); OutputLine("%s", string); } + + /** + * @cli uptime ms + * @code + * uptime ms + * 426238 + * Done + * @endcode + * @par api_copy + * #otInstanceGetUptime + */ else if (aArgs[0] == "ms") { OutputUint64Line(otInstanceGetUptime(GetInstancePtr())); @@ -7223,11 +7860,46 @@ template <> otError Interpreter::Process(Arg aArgs[]) if (aArgs[0] == "retries") { + /** + * @cli mac retries direct (get,set) + * @code + * mac retries direct + * 3 + * Done + * @endcode + * @code + * mac retries direct 5 + * Done + * @endcode + * @cparam mac retries direct [@ca{number}] + * Use the optional `number` argument to set the number of direct TX retries. + * @par + * Gets or sets the number of direct TX retries on the MAC layer. + * @sa otLinkGetMaxFrameRetriesDirect + * @sa otLinkSetMaxFrameRetriesDirect + */ if (aArgs[1] == "direct") { error = ProcessGetSet(aArgs + 2, otLinkGetMaxFrameRetriesDirect, otLinkSetMaxFrameRetriesDirect); } #if OPENTHREAD_FTD + /** + * @cli mac retries indirect (get,set) + * @code + * mac retries indirect + * 3 + * Done + * @endcode + * @code max retries indirect 5 + * Done + * @endcode + * @cparam mac retries indirect [@ca{number}] + * Use the optional `number` argument to set the number of indirect Tx retries. + * @par + * Gets or sets the number of indirect TX retries on the MAC layer. + * @sa otLinkGetMaxFrameRetriesIndirect + * @sa otLinkSetMaxFrameRetriesIndirect + */ else if (aArgs[1] == "indirect") { error = ProcessGetSet(aArgs + 2, otLinkGetMaxFrameRetriesIndirect, otLinkSetMaxFrameRetriesIndirect); @@ -7239,6 +7911,27 @@ template <> otError Interpreter::Process(Arg aArgs[]) } } #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + /** + * @cli mac send + * @code + * mac send datarequest + * Done + * @endcode + * @code + * mac send emptydata + * Done + * @endcode + * @cparam mac send @ca{datarequest} | @ca{emptydata} + * You must choose one of the following two arguments: + * - `datarequest`: Enqueues an IEEE 802.15.4 Data Request message for transmission. + * - `emptydata`: Instructs the device to send an empty IEEE 802.15.4 data frame. + * @par + * Instructs an `Rx-Off-When-Idle` device to send a MAC frame to its parent. + * This command is for certification, and can only be used when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is + * enabled. + * @sa otLinkSendDataRequest + * @sa otLinkSendEmptyData + */ else if (aArgs[0] == "send") { VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS); @@ -7267,18 +7960,94 @@ template <> otError Interpreter::Process(Arg aArgs[]) return error; } +/** + * @cli trel + * @code + * trel + * Enabled + * Done + * @endcode + * @par api_copy + * #otTrelIsEnabled + * @note `OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE` is required for all `trel` sub-commands. + */ #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE template <> otError Interpreter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; + /** + * @cli trel (enable,disable) + * @code + * trel enable + * Done + * @endcode + * @code + * trel disable + * Done + * @endcode + * @cparam trel @ca{enable}|@ca{disable} + * @par + * Enables or disables the TREL radio operation. + * @sa otTrelSetEnabled + */ if (ProcessEnableDisable(aArgs, otTrelIsEnabled, otTrelSetEnabled) == OT_ERROR_NONE) { } + /** + * @cli trel filter + * @code + * trel filter + * Disabled + * Done + * @endcode + * @par + * Indicates whether TREL filter mode is enabled. + * @par + * When filter mode is enabled, all Rx and Tx traffic sent through the TREL interface gets silently dropped. + * @note This mode is used mostly for testing. + * @sa otTrelIsFilterEnabled + */ else if (aArgs[0] == "filter") + /** + * @cli trel filter (enable,disable) + * @code + * trel filter enable + * Done + * @endcode + * @code + * trel filter disable + * Done + * @endcode + * @cparam trel filter @ca{enable}|@ca{disable} + * @par + * Enables or disables TREL filter mode. + * @sa otTrelSetFilterEnabled + */ { error = ProcessEnableDisable(aArgs + 1, otTrelIsFilterEnabled, otTrelSetFilterEnabled); } + /** + * @cli trel peers + * @code + * trel peers + * | No | Ext MAC Address | Ext PAN Id | IPv6 Socket Address | + * +-----+------------------+------------------+--------------------------------------------------+ + * | 1 | 5e5785ba3a63adb9 | f0d9c001f00d2e43 | [fe80:0:0:0:cc79:2a29:d311:1aea]:9202 | + * | 2 | ce792a29d3111aea | dead00beef00cafe | [fe80:0:0:0:5c57:85ba:3a63:adb9]:9203 | + * Done + * @endcode + * @code + * trel peers list + * 001 ExtAddr:5e5785ba3a63adb9 ExtPanId:f0d9c001f00d2e43 SockAddr:[fe80:0:0:0:cc79:2a29:d311:1aea]:9202 + * 002 ExtAddr:ce792a29d3111aea ExtPanId:dead00beef00cafe SockAddr:[fe80:0:0:0:5c57:85ba:3a63:adb9]:9203 + * Done + * @endcode + * @cparam trel peers [@ca{list}] + * @par + * Gets the TREL peer table in table or list format. + * @sa otTrelGetNextPeer + */ else if (aArgs[0] == "peers") { uint16_t index = 0; @@ -7456,6 +8225,63 @@ template <> otError Interpreter::Process(Arg aArgs[]) SuccessOrExit(error = arg->ParseAsUint8(tlvTypes[count++])); } + /** + * @cli networkdiagnostic get + * @code + * networkdiagnostic get fdde:ad00:beef:0:0:ff:fe00:fc00 0 1 6e + * DIAG_GET.rsp/ans: 00080e336e1c41494e1c01020c000608640b0f674074c503 + * Ext Address: '0e336e1c41494e1c' + * Rloc16: 0x0c00 + * Leader Data: + * PartitionId: 0x640b0f67 + * Weighting: 64 + * DataVersion: 116 + * StableDataVersion: 197 + * LeaderRouterId: 0x03 + * Done + * @endcode + * @code + * networkdiagnostic get ff02::1 0 1 + * DIAG_GET.rsp/ans: 00080e336e1c41494e1c01020c00 + * Ext Address: '0e336e1c41494e1c' + * Rloc16: 0x0c00 + * Done + * DIAG_GET.rsp/ans: 00083efcdb7e3f9eb0f201021800 + * Ext Address: '3efcdb7e3f9eb0f2' + * Rloc16: 0x1800 + * Done + * @endcode + * @cparam networkdiagnostic get @ca{addr} @ca{type(s)} + * For `addr`, a unicast address triggers a `Diagnostic Get`. + * A multicast address triggers a `Diagnostic Query`. + * TLV values you can specify (separated by a space if you specify more than one TLV): + * - `0`: MAC Extended Address TLV + * - `1`: Address16 TLV + * - `2`: Mode TLV + * - `3`: Timeout TLV (the maximum polling time period for SEDs) + * - `4`: Connectivity TLV + * - `5`: Route64 TLV + * - `6`: Leader Data TLV + * - `7`: Network Data TLV + * - `8`: IPv6 Address List TLV + * - `9`: MAC Counters TLV + * - `14`: Battery Level TLV + * - `15`: Supply Voltage TLV + * - `16`: Child Table TLV + * - `17`: Channel Pages TLV + * - `19`: Max Child Timeout TLV + * - `25`: Vendor Name TLV + * - `26`: Vendor Model TLV + * - `27`: Vendor SW Version TLV + * - `28`: Thread Stack Version TLV + * - `29`: Child TLV + * - `34`: MLE Counters TLV + * @par + * Sends a network diagnostic request to retrieve specified Type Length Values (TLVs) + * for the specified addresses(es). + * @sa otThreadSendDiagnosticGet + */ + if (aArgs[0] == "get") { SuccessOrExit(error = otThreadSendDiagnosticGet(GetInstancePtr(), &address, tlvTypes, count, @@ -7463,6 +8289,19 @@ template <> otError Interpreter::Process(Arg aArgs[]) SetCommandTimeout(kNetworkDiagnosticTimeoutMsecs); error = OT_ERROR_PENDING; } + /** + * @cli networkdiagnostic reset + * @code + * networkdiagnostic reset fd00:db8::ff:fe00:0 9 + * Done + * @endcode + * @cparam networkdiagnostic reset @ca{addr} @ca{type(s)} + * @par + * Sends a network diagnostic request to reset the specified Type Length Values (TLVs) + * on the specified address(es). The only supported TLV value at this time for this + * command is `9` (MAC Counters TLV). + * @sa otThreadSendDiagnosticReset + */ else if (aArgs[0] == "reset") { IgnoreError(otThreadSendDiagnosticReset(GetInstancePtr(), &address, tlvTypes, count)); @@ -7745,17 +8584,6 @@ void Interpreter::OutputChildTableEntry(uint8_t aIndentSize, const otNetworkDiag } #endif // OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE -void Interpreter::HandleDetachGracefullyResult(void *aContext) -{ - static_cast(aContext)->HandleDetachGracefullyResult(); -} - -void Interpreter::HandleDetachGracefullyResult(void) -{ - OutputLine("Finished detaching"); - OutputResult(OT_ERROR_NONE); -} - #if OPENTHREAD_FTD void Interpreter::HandleDiscoveryRequest(const otThreadDiscoveryRequestInfo *aInfo, void *aContext) { @@ -7957,7 +8785,7 @@ otError Interpreter::ProcessCommand(Arg aArgs[]) #endif CmdEntry("detach"), #endif // OPENTHREAD_FTD || OPENTHREAD_MTD -#if OPENTHREAD_FTD && (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_3_1) +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE CmdEntry("deviceprops"), #endif #if OPENTHREAD_CONFIG_DIAG_ENABLE @@ -8008,6 +8836,9 @@ otError Interpreter::ProcessCommand(Arg aArgs[]) #endif #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE CmdEntry("linkmetrics"), +#if OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE + CmdEntry("linkmetricsmgr"), +#endif #endif #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE CmdEntry("locate"), @@ -8020,6 +8851,9 @@ otError Interpreter::ProcessCommand(Arg aArgs[]) #if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD CmdEntry("meshdiag"), #endif +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + CmdEntry("mleadvimax"), +#endif #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE CmdEntry("mliid"), #endif diff --git a/third_party/openthread/repo/src/cli/cli.hpp b/third_party/openthread/repo/src/cli/cli.hpp index 4b7b913f..9efaaf1f 100644 --- a/third_party/openthread/repo/src/cli/cli.hpp +++ b/third_party/openthread/repo/src/cli/cli.hpp @@ -82,8 +82,8 @@ #include "common/array.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/type_traits.hpp" +#include "instance/instance.hpp" namespace ot { @@ -511,16 +511,18 @@ class Interpreter : public OutputImplementer, public Output static void HandleLinkMetricsReport(const otIp6Address *aAddress, const otLinkMetricsValues *aMetricsValues, - uint8_t aStatus, + otLinkMetricsStatus aStatus, void *aContext); void HandleLinkMetricsReport(const otIp6Address *aAddress, const otLinkMetricsValues *aMetricsValues, - uint8_t aStatus); + otLinkMetricsStatus aStatus); - static void HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, uint8_t aStatus, void *aContext); + static void HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, + otLinkMetricsStatus aStatus, + void *aContext); - void HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, uint8_t aStatus); + void HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, otLinkMetricsStatus aStatus); static void HandleLinkMetricsEnhAckProbingIe(otShortAddress aShortAddress, const otExtAddress *aExtAddress, @@ -531,7 +533,7 @@ class Interpreter : public OutputImplementer, public Output const otExtAddress *aExtAddress, const otLinkMetricsValues *aMetricsValues); - const char *LinkMetricsStatusToStr(uint8_t aStatus); + const char *LinkMetricsStatusToStr(otLinkMetricsStatus aStatus); #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE static void HandleDetachGracefullyResult(void *aContext); diff --git a/third_party/openthread/repo/src/cli/cli_dataset.cpp b/third_party/openthread/repo/src/cli/cli_dataset.cpp index e74ec635..32a4372e 100644 --- a/third_party/openthread/repo/src/cli/cli_dataset.cpp +++ b/third_party/openthread/repo/src/cli/cli_dataset.cpp @@ -47,451 +47,470 @@ namespace Cli { otOperationalDatasetTlvs Dataset::sDatasetTlvs; -otError Dataset::Print(otOperationalDatasetTlvs &aDatasetTlvs) +const Dataset::ComponentMapper *Dataset::LookupMapper(const char *aName) const { - otError error; - otOperationalDataset dataset; - - SuccessOrExit(error = otDatasetParseTlvs(&aDatasetTlvs, &dataset)); - - if (dataset.mComponents.mIsPendingTimestampPresent) - { - OutputFormat("Pending Timestamp: "); - OutputUint64Line(dataset.mPendingTimestamp.mSeconds); - } - - if (dataset.mComponents.mIsActiveTimestampPresent) - { - OutputFormat("Active Timestamp: "); - OutputUint64Line(dataset.mActiveTimestamp.mSeconds); - } - - if (dataset.mComponents.mIsChannelPresent) - { - OutputLine("Channel: %d", dataset.mChannel); - } - - if (dataset.mComponents.mIsChannelMaskPresent) - { - OutputLine("Channel Mask: 0x%08lx", ToUlong(dataset.mChannelMask)); - } - - if (dataset.mComponents.mIsDelayPresent) - { - OutputLine("Delay: %lu", ToUlong(dataset.mDelay)); - } - - if (dataset.mComponents.mIsExtendedPanIdPresent) - { - OutputFormat("Ext PAN ID: "); - OutputBytesLine(dataset.mExtendedPanId.m8); - } - - if (dataset.mComponents.mIsMeshLocalPrefixPresent) - { - OutputFormat("Mesh Local Prefix: "); - OutputIp6PrefixLine(dataset.mMeshLocalPrefix); - } - - if (dataset.mComponents.mIsNetworkKeyPresent) - { - OutputFormat("Network Key: "); - OutputBytesLine(dataset.mNetworkKey.m8); - } - - if (dataset.mComponents.mIsNetworkNamePresent) - { - OutputFormat("Network Name: "); - OutputLine("%s", dataset.mNetworkName.m8); - } - - if (dataset.mComponents.mIsPanIdPresent) - { - OutputLine("PAN ID: 0x%04x", dataset.mPanId); - } - - if (dataset.mComponents.mIsPskcPresent) - { - OutputFormat("PSKc: "); - OutputBytesLine(dataset.mPskc.m8); - } + static constexpr ComponentMapper kMappers[] = { + { + "activetimestamp", + &Components::mIsActiveTimestampPresent, + &Dataset::OutputActiveTimestamp, + &Dataset::ParseActiveTimestamp, + }, + { + "channel", + &Components::mIsChannelPresent, + &Dataset::OutputChannel, + &Dataset::ParseChannel, + }, + { + "channelmask", + &Components::mIsChannelMaskPresent, + &Dataset::OutputChannelMask, + &Dataset::ParseChannelMask, + }, + { + "delay", + &Components::mIsDelayPresent, + &Dataset::OutputDelay, + &Dataset::ParseDelay, + }, + { + "delaytimer", // Alias for "delay "to ensure backward compatibility for "mgmtsetcommand" command + &Components::mIsDelayPresent, + &Dataset::OutputDelay, + &Dataset::ParseDelay, + }, + { + "extpanid", + &Components::mIsExtendedPanIdPresent, + &Dataset::OutputExtendedPanId, + &Dataset::ParseExtendedPanId, + }, + { + "localprefix", // Alias for "meshlocalprefix" to ensure backward compatibility in "mgmtsetcommand" command + &Components::mIsMeshLocalPrefixPresent, + &Dataset::OutputMeshLocalPrefix, + &Dataset::ParseMeshLocalPrefix, + }, + { + "meshlocalprefix", + &Components::mIsMeshLocalPrefixPresent, + &Dataset::OutputMeshLocalPrefix, + &Dataset::ParseMeshLocalPrefix, + }, + { + "networkkey", + &Components::mIsNetworkKeyPresent, + &Dataset::OutputNetworkKey, + &Dataset::ParseNetworkKey, + }, + { + "networkname", + &Components::mIsNetworkNamePresent, + &Dataset::OutputNetworkName, + &Dataset::ParseNetworkName, + }, + { + "panid", + &Components::mIsPanIdPresent, + &Dataset::OutputPanId, + &Dataset::ParsePanId, + }, + { + "pendingtimestamp", + &Components::mIsPendingTimestampPresent, + &Dataset::OutputPendingTimestamp, + &Dataset::ParsePendingTimestamp, + }, + { + "pskc", + &Components::mIsPskcPresent, + &Dataset::OutputPskc, + &Dataset::ParsePskc, + }, + { + "securitypolicy", + &Components::mIsSecurityPolicyPresent, + &Dataset::OutputSecurityPolicy, + &Dataset::ParseSecurityPolicy, + }, + }; - if (dataset.mComponents.mIsSecurityPolicyPresent) - { - OutputFormat("Security Policy: "); - OutputSecurityPolicy(dataset.mSecurityPolicy); - } + static_assert(BinarySearch::IsSorted(kMappers), "kMappers is not sorted"); -exit: - return error; + return BinarySearch::Find(aName, kMappers); } +//--------------------------------------------------------------------------------------------------------------------- + /** - * @cli dataset init (active,new,pending,tlvs) + * @cli dataset activetimestamp (get, set) * @code - * dataset init new + * dataset activetimestamp + * 123456789 * Done * @endcode - * @cparam dataset init {@ca{active}|@ca{new}|@ca{pending}|@ca{tlvs}} [@ca{hex-encoded-tlvs}] - * Use `new` to initialize a new dataset, then enter the command `dataset commit active`. - * Use `tlvs` for hex-encoded TLVs. + * @code + * dataset activetimestamp 123456789 + * Done + * @endcode + * @cparam dataset activetimestamp [@ca{timestamp}] + * Pass the optional `timestamp` argument to set the active timestamp. * @par - * OT CLI checks for `active`, `pending`, or `tlvs` and returns the corresponding values. Otherwise, - * OT CLI creates a new, random network and returns a new dataset. - * @csa{dataset commit active} - * @csa{dataset active} + * Gets or sets #otOperationalDataset::mActiveTimestamp. */ -template <> otError Dataset::Process(Arg aArgs[]) +void Dataset::OutputActiveTimestamp(const otOperationalDataset &aDataset) { - otError error = OT_ERROR_INVALID_ARGS; - - if (aArgs[0] == "active") - { - error = otDatasetGetActiveTlvs(GetInstancePtr(), &sDatasetTlvs); - } - else if (aArgs[0] == "pending") - { - error = otDatasetGetPendingTlvs(GetInstancePtr(), &sDatasetTlvs); - } -#if OPENTHREAD_FTD - else if (aArgs[0] == "new") - { - otOperationalDataset dataset; - - SuccessOrExit(error = otDatasetCreateNewNetwork(GetInstancePtr(), &dataset)); - SuccessOrExit(error = otDatasetConvertToTlvs(&dataset, &sDatasetTlvs)); - } -#endif - else if (aArgs[0] == "tlvs") - { - uint16_t size = sizeof(sDatasetTlvs.mTlvs); - - SuccessOrExit(error = aArgs[1].ParseAsHexString(size, sDatasetTlvs.mTlvs)); - sDatasetTlvs.mLength = static_cast(size); - } - -exit: - return error; + OutputUint64Line(aDataset.mActiveTimestamp.mSeconds); } /** - * @cli dataset active + * @cli dataset channel (get,set) * @code - * dataset active - * Active Timestamp: 1 - * Channel: 13 - * Channel Mask: 0x07fff800 - * Ext PAN ID: d63e8e3e495ebbc3 - * Mesh Local Prefix: fd3d:b50b:f96d:722d::/64 - * Network Key: dfd34f0f05cad978ec4e32b0413038ff - * Network Name: OpenThread-8f28 - * PAN ID: 0x8f28 - * PSKc: c23a76e98f1a6483639b1ac1271e2e27 - * Security Policy: 0, onrcb + * dataset channel + * 12 * Done * @endcode * @code - * dataset active -x - * 0e08000000000001000000030000103506000...3023d82c841eff0e68db86f35740c030000ff + * dataset channel 12 * Done * @endcode - * @cparam dataset active [-x] - * The optional `-x` argument prints the Active Operational %Dataset values as hex-encoded TLVs. - * @par api_copy - * #otDatasetGetActive + * @cparam dataset channel [@ca{channel-num}] + * Use the optional `channel-num` argument to set the channel. * @par - * OT CLI uses #otOperationalDataset members to return dataset values to the console. + * Gets or sets #otOperationalDataset::mChannel. */ -template <> otError Dataset::Process(Arg aArgs[]) -{ - otError error; - otOperationalDatasetTlvs dataset; +void Dataset::OutputChannel(const otOperationalDataset &aDataset) { OutputLine("%u", aDataset.mChannel); } - SuccessOrExit(error = otDatasetGetActiveTlvs(GetInstancePtr(), &dataset)); +/** + * @cli dataset channelmask (get,set) + * @code + * dataset channelmask + * 0x07fff800 + * Done + * @endcode + * @code + * dataset channelmask 0x07fff800 + * Done + * @endcode + * @cparam dataset channelmask [@ca{channel-mask}] + * Use the optional `channel-mask` argument to set the channel mask. + * @par + * Gets or sets #otOperationalDataset::mChannelMask + */ +void Dataset::OutputChannelMask(const otOperationalDataset &aDataset) +{ + OutputLine("0x%08lx", ToUlong(aDataset.mChannelMask)); +} - if (aArgs[0].IsEmpty()) - { - error = Print(dataset); - } - else if (aArgs[0] == "-x") - { - OutputBytesLine(dataset.mTlvs, dataset.mLength); - } - else - { - error = OT_ERROR_INVALID_ARGS; - } +/** + * @cli dataset delay (get,set) + * @code + * dataset delay + * 1000 + * Done + * @endcode + * @code + * dataset delay 1000 + * Done + * @endcode + * @cparam dataset delay [@ca{delay}] + * Use the optional `delay` argument to set the delay timer value. + * @par + * Gets or sets #otOperationalDataset::mDelay. + * @sa otDatasetSetDelayTimerMinimal + */ +void Dataset::OutputDelay(const otOperationalDataset &aDataset) { OutputLine("%lu", ToUlong(aDataset.mDelay)); } -exit: - return error; -} +/** + * @cli dataset extpanid (get,set) + * @code + * dataset extpanid + * 000db80123456789 + * Done + * @endcode + * @code + * dataset extpanid 000db80123456789 + * Done + * @endcode + * @cparam dataset extpanid [@ca{extpanid}] + * Use the optional `extpanid` argument to set the Extended Personal Area Network ID. + * @par + * Gets or sets #otOperationalDataset::mExtendedPanId. + * @note The commissioning credential in the dataset buffer becomes stale after changing + * this value. Use `dataset pskc` to reset. + * @csa{dataset pskc (get,set)} + */ +void Dataset::OutputExtendedPanId(const otOperationalDataset &aDataset) { OutputBytesLine(aDataset.mExtendedPanId.m8); } -template <> otError Dataset::Process(Arg aArgs[]) +/** + * @cli dataset meshlocalprefix (get,set) + * @code + * dataset meshlocalprefix + * fd00:db8:0:0::/64 + * Done + * @endcode + * @code + * dataset meshlocalprefix fd00:db8:0:0:: + * Done + * @endcode + * @cparam dataset meshlocalprefix [@ca{meshlocalprefix}] + * Use the optional `meshlocalprefix` argument to set the Mesh-Local Prefix. + * @par + * Gets or sets #otOperationalDataset::mMeshLocalPrefix. + */ +void Dataset::OutputMeshLocalPrefix(const otOperationalDataset &aDataset) { - otError error; - otOperationalDatasetTlvs datasetTlvs; + OutputIp6PrefixLine(aDataset.mMeshLocalPrefix); +} - SuccessOrExit(error = otDatasetGetPendingTlvs(GetInstancePtr(), &datasetTlvs)); +/** + * @cli dataset networkkey (get,set) + * @code + * dataset networkkey + * 00112233445566778899aabbccddeeff + * Done + * @endcode + * @code + * dataset networkkey 00112233445566778899aabbccddeeff + * Done + * @endcode + * @cparam dataset networkkey [@ca{key}] + * Use the optional `key` argument to set the Network Key. + * @par + * Gets or sets #otOperationalDataset::mNetworkKey. + */ +void Dataset::OutputNetworkKey(const otOperationalDataset &aDataset) { OutputBytesLine(aDataset.mNetworkKey.m8); } - if (aArgs[0].IsEmpty()) - { - error = Print(datasetTlvs); - } - else if (aArgs[0] == "-x") - { - OutputBytesLine(datasetTlvs.mTlvs, datasetTlvs.mLength); - } - else - { - error = OT_ERROR_INVALID_ARGS; - } +/** + * @cli dataset networkname (get,set) + * @code + * dataset networkname + * OpenThread + * Done + * @endcode + * @code + * dataset networkname OpenThread + * Done + * @endcode + * @cparam dataset networkname [@ca{name}] + * Use the optional `name` argument to set the Network Name. + * @par + * Gets or sets #otOperationalDataset::mNetworkName. + * @note The Commissioning Credential in the dataset buffer becomes stale after changing this value. + * Use `dataset pskc` to reset. + * @csa{dataset pskc (get,set)} + */ +void Dataset::OutputNetworkName(const otOperationalDataset &aDataset) { OutputLine("%s", aDataset.mNetworkName.m8); } -exit: - return error; -} +/** + * @cli dataset panid (get,set) + * @code + * dataset panid + * 0x1234 + * Done + * @endcode + * @code + * dataset panid 0x1234 + * Done + * @endcode + * @cparam dataset panid [@ca{panid}] + * Use the optional `panid` argument to set the PAN ID. + * @par + * Gets or sets #otOperationalDataset::mPanId. + */ +void Dataset::OutputPanId(const otOperationalDataset &aDataset) { OutputLine("0x%04x", aDataset.mPanId); } /** - * @cli dataset activetimestamp (get, set) + * @cli dataset pendingtimestamp (get,set) * @code - * dataset activetimestamp + * dataset pendingtimestamp * 123456789 * Done * @endcode * @code - * dataset activetimestamp 123456789 + * dataset pendingtimestamp 123456789 * Done * @endcode - * @cparam dataset activetimestamp [@ca{timestamp}] - * Pass the optional `timestamp` argument to set the active timestamp. + * @cparam dataset pendingtimestamp [@ca{timestamp}] + * Use the optional `timestamp` argument to set the pending timestamp seconds. * @par - * Gets or sets #otOperationalDataset::mActiveTimestamp. + * Gets or sets #otOperationalDataset::mPendingTimestamp. */ -template <> otError Dataset::Process(Arg aArgs[]) +void Dataset::OutputPendingTimestamp(const otOperationalDataset &aDataset) { - otError error = OT_ERROR_NONE; - otOperationalDataset dataset; - - if (aArgs[0].IsEmpty()) - { - SuccessOrExit(error = otDatasetParseTlvs(&sDatasetTlvs, &dataset)); - if (dataset.mComponents.mIsActiveTimestampPresent) - { - OutputUint64Line(dataset.mActiveTimestamp.mSeconds); - } - } - else - { - memset(&dataset, 0, sizeof(dataset)); - SuccessOrExit(error = aArgs[0].ParseAsUint64(dataset.mActiveTimestamp.mSeconds)); - dataset.mActiveTimestamp.mTicks = 0; - dataset.mActiveTimestamp.mAuthoritative = false; - dataset.mComponents.mIsActiveTimestampPresent = true; - SuccessOrExit(error = otDatasetUpdateTlvs(&dataset, &sDatasetTlvs)); - } - -exit: - return error; + OutputUint64Line(aDataset.mPendingTimestamp.mSeconds); } /** - * @cli dataset channel (get,set) + * @cli dataset pskc (get,set) * @code - * dataset channel - * 12 + * dataset pskc + * 67c0c203aa0b042bfb5381c47aef4d9e * Done * @endcode * @code - * dataset channel 12 + * dataset pskc -p 123456 * Done * @endcode - * @cparam dataset channel [@ca{channel-num}] - * Use the optional `channel-num` argument to set the channel. + * @code + * dataset pskc 67c0c203aa0b042bfb5381c47aef4d9e + * Done + * @endcode + * @cparam dataset pskc [@ca{-p} @ca{passphrase}] | [@ca{key}] + * For FTD only, use `-p` with the `passphrase` argument. `-p` generates a pskc from + * the UTF-8 encoded `passphrase` that you provide, together with + * the network name and extended PAN ID. If set, `-p` uses the dataset buffer; + * otherwise, it uses the current stack. + * Alternatively, you can set pskc as `key` (hex format). * @par - * Gets or sets #otOperationalDataset::mChannel. + * Gets or sets #otOperationalDataset::mPskc. */ -template <> otError Dataset::Process(Arg aArgs[]) +void Dataset::OutputPskc(const otOperationalDataset &aDataset) { OutputBytesLine(aDataset.mPskc.m8); } + +/** + * @cli dataset securitypolicy (get,set) + * @code + * dataset securitypolicy + * 672 onrc + * Done + * @endcode + * @code + * dataset securitypolicy 672 onrc + * Done + * @endcode + * @cparam dataset securitypolicy [@ca{rotationtime} [@ca{onrcCepR}]] + * * Use `rotationtime` for `thrKeyRotation`, in units of hours. + * * Security Policy commands use the `onrcCepR` argument mappings to get and set + * #otSecurityPolicy members, for example `o` represents + * #otSecurityPolicy::mObtainNetworkKeyEnabled. + * @moreinfo{@dataset}. + * @par + * Gets or sets the %Dataset security policy. + */ +void Dataset::OutputSecurityPolicy(const otOperationalDataset &aDataset) { - otError error = OT_ERROR_NONE; - otOperationalDataset dataset; + OutputSecurityPolicy(aDataset.mSecurityPolicy); +} - if (aArgs[0].IsEmpty()) - { - SuccessOrExit(error = otDatasetParseTlvs(&sDatasetTlvs, &dataset)); - if (dataset.mComponents.mIsChannelPresent) - { - OutputLine("%d", dataset.mChannel); - } - } - else - { - memset(&dataset, 0, sizeof(dataset)); - SuccessOrExit(error = aArgs[0].ParseAsUint16(dataset.mChannel)); - dataset.mComponents.mIsChannelPresent = true; - SuccessOrExit(error = otDatasetUpdateTlvs(&dataset, &sDatasetTlvs)); - } +//--------------------------------------------------------------------------------------------------------------------- + +otError Dataset::ParseActiveTimestamp(Arg *&aArgs, otOperationalDataset &aDataset) +{ + otError error; + + SuccessOrExit(error = aArgs++->ParseAsUint64(aDataset.mActiveTimestamp.mSeconds)); + aDataset.mActiveTimestamp.mTicks = 0; + aDataset.mActiveTimestamp.mAuthoritative = false; + +exit: + return error; +} + +otError Dataset::ParseChannel(Arg *&aArgs, otOperationalDataset &aDataset) +{ + return aArgs++->ParseAsUint16(aDataset.mChannel); +} + +otError Dataset::ParseChannelMask(Arg *&aArgs, otOperationalDataset &aDataset) +{ + return aArgs++->ParseAsUint32(aDataset.mChannelMask); +} + +otError Dataset::ParseDelay(Arg *&aArgs, otOperationalDataset &aDataset) +{ + return aArgs++->ParseAsUint32(aDataset.mDelay); +} + +otError Dataset::ParseExtendedPanId(Arg *&aArgs, otOperationalDataset &aDataset) +{ + return aArgs++->ParseAsHexString(aDataset.mExtendedPanId.m8); +} + +otError Dataset::ParseMeshLocalPrefix(Arg *&aArgs, otOperationalDataset &aDataset) +{ + otError error; + otIp6Address prefix; + + SuccessOrExit(error = aArgs++->ParseAsIp6Address(prefix)); + + memcpy(aDataset.mMeshLocalPrefix.m8, prefix.mFields.m8, sizeof(aDataset.mMeshLocalPrefix.m8)); exit: return error; } -/** - * @cli dataset channelmask (get,set) - * @code - * dataset channelmask - * 0x07fff800 - * Done - * @endcode - * @code - * dataset channelmask 0x07fff800 - * Done - * @endcode - * @cparam dataset channelmask [@ca{channel-mask}] - * Use the optional `channel-mask` argument to set the channel mask. - * @par - * Gets or sets #otOperationalDataset::mChannelMask - */ -template <> otError Dataset::Process(Arg aArgs[]) +otError Dataset::ParseNetworkKey(Arg *&aArgs, otOperationalDataset &aDataset) { - otError error = OT_ERROR_NONE; - otOperationalDataset dataset; + return aArgs++->ParseAsHexString(aDataset.mNetworkKey.m8); +} - if (aArgs[0].IsEmpty()) - { - SuccessOrExit(error = otDatasetParseTlvs(&sDatasetTlvs, &dataset)); - if (dataset.mComponents.mIsChannelMaskPresent) - { - OutputLine("0x%08lx", ToUlong(dataset.mChannelMask)); - } - } - else - { - memset(&dataset, 0, sizeof(dataset)); - SuccessOrExit(error = aArgs[0].ParseAsUint32(dataset.mChannelMask)); - dataset.mComponents.mIsChannelMaskPresent = true; - SuccessOrExit(error = otDatasetUpdateTlvs(&dataset, &sDatasetTlvs)); - } +otError Dataset::ParseNetworkName(Arg *&aArgs, otOperationalDataset &aDataset) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(!aArgs->IsEmpty(), error = OT_ERROR_INVALID_ARGS); + error = otNetworkNameFromString(&aDataset.mNetworkName, aArgs++->GetCString()); exit: return error; } -/** - * @cli dataset clear - * @code - * dataset clear - * Done - * @endcode - * @par - * Reset the Operational %Dataset buffer. - */ -template <> otError Dataset::Process(Arg aArgs[]) +otError Dataset::ParsePanId(Arg *&aArgs, otOperationalDataset &aDataset) { - OT_UNUSED_VARIABLE(aArgs); - - memset(&sDatasetTlvs, 0, sizeof(sDatasetTlvs)); - return OT_ERROR_NONE; + return aArgs++->ParseAsUint16(aDataset.mPanId); } -template <> otError Dataset::Process(Arg aArgs[]) +otError Dataset::ParsePendingTimestamp(Arg *&aArgs, otOperationalDataset &aDataset) { - otError error = OT_ERROR_INVALID_ARGS; + otError error; - /** - * @cli dataset commit active - * @code - * dataset commit active - * Done - * @endcode - * @par - * Commit the Operational %Dataset buffer to Active Operational %Dataset. - * @csa{dataset commit pending} - * @sa #otDatasetSetPending - */ - if (aArgs[0] == "active") - { - error = otDatasetSetActiveTlvs(GetInstancePtr(), &sDatasetTlvs); - } - /** - * @cli dataset commit pending - * @code - * dataset commit pending - * Done - * @endcode - * @par - * Commit the Operational %Dataset buffer to Pending Operational %Dataset. - * @csa{dataset commit active} - * @sa #otDatasetSetActive - */ - else if (aArgs[0] == "pending") - { - error = otDatasetSetPendingTlvs(GetInstancePtr(), &sDatasetTlvs); - } + SuccessOrExit(error = aArgs++->ParseAsUint64(aDataset.mPendingTimestamp.mSeconds)); + aDataset.mPendingTimestamp.mTicks = 0; + aDataset.mPendingTimestamp.mAuthoritative = false; +exit: return error; } -/** - * @cli dataset delay (get,set) - * @code - * dataset delay - * 1000 - * Done - * @endcode - * @code - * dataset delay 1000 - * Done - * @endcode - * @cparam dataset delay [@ca{delay}] - * Use the optional `delay` argument to set the delay timer value. - * @par - * Gets or sets #otOperationalDataset::mDelay. - * @sa otDatasetSetDelayTimerMinimal - */ -template <> otError Dataset::Process(Arg aArgs[]) +otError Dataset::ParsePskc(Arg *&aArgs, otOperationalDataset &aDataset) { - otError error = OT_ERROR_NONE; - otOperationalDataset dataset; + otError error; - if (aArgs[0].IsEmpty()) +#if OPENTHREAD_FTD + if (*aArgs == "-p") { - SuccessOrExit(error = otDatasetParseTlvs(&sDatasetTlvs, &dataset)); - if (dataset.mComponents.mIsDelayPresent) - { - OutputLine("%lu", ToUlong(dataset.mDelay)); - } + aArgs++; + VerifyOrExit(!aArgs->IsEmpty(), error = OT_ERROR_INVALID_ARGS); + + SuccessOrExit(error = otDatasetGeneratePskc( + aArgs->GetCString(), + (aDataset.mComponents.mIsNetworkNamePresent + ? &aDataset.mNetworkName + : reinterpret_cast(otThreadGetNetworkName(GetInstancePtr()))), + (aDataset.mComponents.mIsExtendedPanIdPresent ? &aDataset.mExtendedPanId + : otThreadGetExtendedPanId(GetInstancePtr())), + &aDataset.mPskc)); + aArgs++; } else +#endif { - memset(&dataset, 0, sizeof(dataset)); - SuccessOrExit(error = aArgs[0].ParseAsUint32(dataset.mDelay)); - dataset.mComponents.mIsDelayPresent = true; - SuccessOrExit(error = otDatasetUpdateTlvs(&dataset, &sDatasetTlvs)); + ExitNow(error = aArgs++->ParseAsHexString(aDataset.mPskc.m8)); } exit: return error; } -/** - * @cli dataset extpanid (get,set) - * @code - * dataset extpanid - * 000db80123456789 - * Done - * @endcode - * @code - * dataset extpanid 000db80123456789 - * Done - * @endcode - * @cparam dataset extpanid [@ca{extpanid}] - * Use the optional `extpanid` argument to set the Extended Personal Area Network ID. - * @par - * Gets or sets #otOperationalDataset::mExtendedPanId. - * @note The commissioning credential in the dataset buffer becomes stale after changing - * this value. Use `dataset pskc` to reset. - * @csa{dataset pskc (get,set)} - */ -template <> otError Dataset::Process(Arg aArgs[]) +otError Dataset::ParseSecurityPolicy(Arg *&aArgs, otOperationalDataset &aDataset) +{ + return ParseSecurityPolicy(aDataset.mSecurityPolicy, aArgs); +} + +//--------------------------------------------------------------------------------------------------------------------- + +otError Dataset::ProcessCommand(const ComponentMapper &aMapper, Arg aArgs[]) { otError error = OT_ERROR_NONE; otOperationalDataset dataset; @@ -499,16 +518,17 @@ template <> otError Dataset::Process(Arg aArgs[]) if (aArgs[0].IsEmpty()) { SuccessOrExit(error = otDatasetParseTlvs(&sDatasetTlvs, &dataset)); - if (dataset.mComponents.mIsExtendedPanIdPresent) + + if (dataset.mComponents.*aMapper.mIsPresentPtr) { - OutputBytesLine(dataset.mExtendedPanId.m8); + (this->*aMapper.mOutput)(dataset); } } else { memset(&dataset, 0, sizeof(dataset)); - SuccessOrExit(error = aArgs[0].ParseAsHexString(dataset.mExtendedPanId.m8)); - dataset.mComponents.mIsExtendedPanIdPresent = true; + SuccessOrExit(error = (this->*aMapper.mParse)(aArgs, dataset)); + dataset.mComponents.*aMapper.mIsPresentPtr = true; SuccessOrExit(error = otDatasetUpdateTlvs(&dataset, &sDatasetTlvs)); } @@ -516,87 +536,91 @@ template <> otError Dataset::Process(Arg aArgs[]) return error; } -/** - * @cli dataset meshlocalprefix (get,set) - * @code - * dataset meshlocalprefix - * fd00:db8:0:0::/64 - * Done - * @endcode - * @code - * dataset meshlocalprefix fd00:db8:0:0::/64 - * Done - * @endcode - * @cparam dataset meshlocalprefix [@ca{meshlocalprefix}] - * Use the optional `meshlocalprefix` argument to set the Mesh-Local Prefix. - * @par - * Gets or sets #otOperationalDataset::mMeshLocalPrefix. - */ -template <> otError Dataset::Process(Arg aArgs[]) +otError Dataset::Print(otOperationalDatasetTlvs &aDatasetTlvs) { - otError error = OT_ERROR_NONE; + struct ComponentTitle + { + const char *mTitle; // Title to output. + const char *mName; // To use with `LookupMapper()`. + }; + + static const ComponentTitle kTitles[] = { + {"Pending Timestamp", "pendingtimestamp"}, + {"Active Timestamp", "activetimestamp"}, + {"Channel", "channel"}, + {"Channel Mask", "channelmask"}, + {"Delay", "delay"}, + {"Ext PAN ID", "extpanid"}, + {"Mesh Local Prefix", "meshlocalprefix"}, + {"Network Key", "networkkey"}, + {"Network Name", "networkname"}, + {"PAN ID", "panid"}, + {"PSKc", "pskc"}, + {"Security Policy", "securitypolicy"}, + }; + + otError error; otOperationalDataset dataset; - if (aArgs[0].IsEmpty()) + SuccessOrExit(error = otDatasetParseTlvs(&aDatasetTlvs, &dataset)); + + for (const ComponentTitle &title : kTitles) { - SuccessOrExit(error = otDatasetParseTlvs(&sDatasetTlvs, &dataset)); - if (dataset.mComponents.mIsMeshLocalPrefixPresent) + const ComponentMapper *mapper = LookupMapper(title.mName); + + if (dataset.mComponents.*mapper->mIsPresentPtr) { - OutputFormat("Mesh Local Prefix: "); - OutputIp6PrefixLine(dataset.mMeshLocalPrefix); + OutputFormat("%s: ", title.mTitle); + (this->*mapper->mOutput)(dataset); } } - else - { - otIp6Address prefix; - - SuccessOrExit(error = aArgs[0].ParseAsIp6Address(prefix)); - - memset(&dataset, 0, sizeof(dataset)); - memcpy(dataset.mMeshLocalPrefix.m8, prefix.mFields.m8, sizeof(dataset.mMeshLocalPrefix.m8)); - dataset.mComponents.mIsMeshLocalPrefixPresent = true; - SuccessOrExit(error = otDatasetUpdateTlvs(&dataset, &sDatasetTlvs)); - } exit: return error; } /** - * @cli dataset networkkey (get,set) - * @code - * dataset networkkey - * 00112233445566778899aabbccddeeff - * Done - * @endcode + * @cli dataset init (active,new,pending,tlvs) * @code - * dataset networkkey 00112233445566778899aabbccddeeff + * dataset init new * Done * @endcode - * @cparam dataset networkkey [@ca{key}] - * Use the optional `key` argument to set the Network Key. + * @cparam dataset init {@ca{active}|@ca{new}|@ca{pending}|@ca{tlvs}} [@ca{hex-encoded-tlvs}] + * Use `new` to initialize a new dataset, then enter the command `dataset commit active`. + * Use `tlvs` for hex-encoded TLVs. * @par - * Gets or sets #otOperationalDataset::mNetworkKey. + * OT CLI checks for `active`, `pending`, or `tlvs` and returns the corresponding values. Otherwise, + * OT CLI creates a new, random network and returns a new dataset. + * @csa{dataset commit active} + * @csa{dataset active} */ -template <> otError Dataset::Process(Arg aArgs[]) +template <> otError Dataset::Process(Arg aArgs[]) { - otError error = OT_ERROR_NONE; - otOperationalDataset dataset; + otError error = OT_ERROR_INVALID_ARGS; - if (aArgs[0].IsEmpty()) + if (aArgs[0] == "active") { - SuccessOrExit(error = otDatasetParseTlvs(&sDatasetTlvs, &dataset)); - if (dataset.mComponents.mIsNetworkKeyPresent) - { - OutputBytesLine(dataset.mNetworkKey.m8); - } + error = otDatasetGetActiveTlvs(GetInstancePtr(), &sDatasetTlvs); } - else + else if (aArgs[0] == "pending") { - memset(&dataset, 0, sizeof(dataset)); - SuccessOrExit(error = aArgs[0].ParseAsHexString(dataset.mNetworkKey.m8)); - dataset.mComponents.mIsNetworkKeyPresent = true; - SuccessOrExit(error = otDatasetUpdateTlvs(&dataset, &sDatasetTlvs)); + error = otDatasetGetPendingTlvs(GetInstancePtr(), &sDatasetTlvs); + } +#if OPENTHREAD_FTD + else if (aArgs[0] == "new") + { + otOperationalDataset dataset; + + SuccessOrExit(error = otDatasetCreateNewNetwork(GetInstancePtr(), &dataset)); + SuccessOrExit(error = otDatasetConvertToTlvs(&dataset, &sDatasetTlvs)); + } +#endif + else if (aArgs[0] == "tlvs") + { + uint16_t size = sizeof(sDatasetTlvs.mTlvs); + + SuccessOrExit(error = aArgs[1].ParseAsHexString(size, sDatasetTlvs.mTlvs)); + sDatasetTlvs.mLength = static_cast(size); } exit: @@ -604,84 +628,75 @@ template <> otError Dataset::Process(Arg aArgs[]) } /** - * @cli dataset networkname (get,set) + * @cli dataset active * @code - * dataset networkname - * OpenThread + * dataset active + * Active Timestamp: 1 + * Channel: 13 + * Channel Mask: 0x07fff800 + * Ext PAN ID: d63e8e3e495ebbc3 + * Mesh Local Prefix: fd3d:b50b:f96d:722d::/64 + * Network Key: dfd34f0f05cad978ec4e32b0413038ff + * Network Name: OpenThread-8f28 + * PAN ID: 0x8f28 + * PSKc: c23a76e98f1a6483639b1ac1271e2e27 + * Security Policy: 0, onrcb * Done * @endcode * @code - * dataset networkname OpenThread + * dataset active -x + * 0e08000000000001000000030000103506000...3023d82c841eff0e68db86f35740c030000ff * Done * @endcode - * @cparam dataset networkname [@ca{name}] - * Use the optional `name` argument to set the Network Name. + * @cparam dataset active [-x] + * The optional `-x` argument prints the Active Operational %Dataset values as hex-encoded TLVs. + * @par api_copy + * #otDatasetGetActive * @par - * Gets or sets #otOperationalDataset::mNetworkName. - * @note The Commissioning Credential in the dataset buffer becomes stale after changing this value. - * Use `dataset pskc` to reset. - * @csa{dataset pskc (get,set)} + * OT CLI uses #otOperationalDataset members to return dataset values to the console. */ -template <> otError Dataset::Process(Arg aArgs[]) +template <> otError Dataset::Process(Arg aArgs[]) { - otError error = OT_ERROR_NONE; - otOperationalDataset dataset; + otError error; + otOperationalDatasetTlvs dataset; + + SuccessOrExit(error = otDatasetGetActiveTlvs(GetInstancePtr(), &dataset)); if (aArgs[0].IsEmpty()) { - SuccessOrExit(error = otDatasetParseTlvs(&sDatasetTlvs, &dataset)); - if (dataset.mComponents.mIsNetworkNamePresent) - { - OutputLine("%s", dataset.mNetworkName.m8); - } + error = Print(dataset); + } + else if (aArgs[0] == "-x") + { + OutputBytesLine(dataset.mTlvs, dataset.mLength); } else { - memset(&dataset, 0, sizeof(dataset)); - SuccessOrExit(error = otNetworkNameFromString(&dataset.mNetworkName, aArgs[0].GetCString())); - dataset.mComponents.mIsNetworkNamePresent = true; - SuccessOrExit(error = otDatasetUpdateTlvs(&dataset, &sDatasetTlvs)); + error = OT_ERROR_INVALID_ARGS; } exit: return error; } -/** - * @cli dataset panid (get,set) - * @code - * dataset panid - * 0x1234 - * Done - * @endcode - * @code - * dataset panid 0x1234 - * Done - * @endcode - * @cparam dataset panid [@ca{panid}] - * Use the optional `panid` argument to set the PAN ID. - * @par - * Gets or sets #otOperationalDataset::mPanId. - */ -template <> otError Dataset::Process(Arg aArgs[]) +template <> otError Dataset::Process(Arg aArgs[]) { - otError error = OT_ERROR_NONE; - otOperationalDataset dataset; + otError error; + otOperationalDatasetTlvs datasetTlvs; + + SuccessOrExit(error = otDatasetGetPendingTlvs(GetInstancePtr(), &datasetTlvs)); if (aArgs[0].IsEmpty()) { - SuccessOrExit(error = otDatasetParseTlvs(&sDatasetTlvs, &dataset)); - if (dataset.mComponents.mIsPanIdPresent) - { - OutputLine("0x%04x", dataset.mPanId); - } + error = Print(datasetTlvs); + } + else if (aArgs[0] == "-x") + { + OutputBytesLine(datasetTlvs.mTlvs, datasetTlvs.mLength); } else { - memset(&dataset, 0, sizeof(dataset)); - SuccessOrExit(error = aArgs[0].ParseAsUint16(dataset.mPanId)); - dataset.mComponents.mIsPanIdPresent = true; - SuccessOrExit(error = otDatasetUpdateTlvs(&dataset, &sDatasetTlvs)); + error = OT_ERROR_INVALID_ARGS; } exit: @@ -689,45 +704,57 @@ template <> otError Dataset::Process(Arg aArgs[]) } /** - * @cli dataset pendingtimestamp (get,set) - * @code - * dataset pendingtimestamp - * 123456789 - * Done - * @endcode + * @cli dataset clear * @code - * dataset pendingtimestamp 123456789 + * dataset clear * Done * @endcode - * @cparam dataset pendingtimestamp [@ca{timestamp}] - * Use the optional `timestamp` argument to set the pending timestamp seconds. * @par - * Gets or sets #otOperationalDataset::mPendingTimestamp. + * Reset the Operational %Dataset buffer. */ -template <> otError Dataset::Process(Arg aArgs[]) +template <> otError Dataset::Process(Arg aArgs[]) { - otError error = OT_ERROR_NONE; - otOperationalDataset dataset; + OT_UNUSED_VARIABLE(aArgs); - if (aArgs[0].IsEmpty()) + memset(&sDatasetTlvs, 0, sizeof(sDatasetTlvs)); + return OT_ERROR_NONE; +} + +template <> otError Dataset::Process(Arg aArgs[]) +{ + otError error = OT_ERROR_INVALID_ARGS; + + /** + * @cli dataset commit active + * @code + * dataset commit active + * Done + * @endcode + * @par + * Commit the Operational %Dataset buffer to Active Operational %Dataset. + * @csa{dataset commit pending} + * @sa #otDatasetSetPending + */ + if (aArgs[0] == "active") { - SuccessOrExit(error = otDatasetParseTlvs(&sDatasetTlvs, &dataset)); - if (dataset.mComponents.mIsPendingTimestampPresent) - { - OutputUint64Line(dataset.mPendingTimestamp.mSeconds); - } + error = otDatasetSetActiveTlvs(GetInstancePtr(), &sDatasetTlvs); } - else + /** + * @cli dataset commit pending + * @code + * dataset commit pending + * Done + * @endcode + * @par + * Commit the Operational %Dataset buffer to Pending Operational %Dataset. + * @csa{dataset commit active} + * @sa #otDatasetSetActive + */ + else if (aArgs[0] == "pending") { - memset(&dataset, 0, sizeof(dataset)); - SuccessOrExit(error = aArgs[0].ParseAsUint64(dataset.mPendingTimestamp.mSeconds)); - dataset.mPendingTimestamp.mTicks = 0; - dataset.mPendingTimestamp.mAuthoritative = false; - dataset.mComponents.mIsPendingTimestampPresent = true; - SuccessOrExit(error = otDatasetUpdateTlvs(&dataset, &sDatasetTlvs)); + error = otDatasetSetPendingTlvs(GetInstancePtr(), &sDatasetTlvs); } -exit: return error; } @@ -740,81 +767,15 @@ template <> otError Dataset::Process(Arg aArgs[]) memset(&dataset, 0, sizeof(dataset)); - for (Arg *arg = &aArgs[1]; !arg->IsEmpty(); arg++) + for (Arg *arg = &aArgs[1]; !arg->IsEmpty();) { - if (*arg == "activetimestamp") - { - arg++; - SuccessOrExit(error = arg->ParseAsUint64(dataset.mActiveTimestamp.mSeconds)); - dataset.mActiveTimestamp.mTicks = 0; - dataset.mActiveTimestamp.mAuthoritative = false; - dataset.mComponents.mIsActiveTimestampPresent = true; - } - else if (*arg == "pendingtimestamp") - { - arg++; - SuccessOrExit(error = arg->ParseAsUint64(dataset.mPendingTimestamp.mSeconds)); - dataset.mPendingTimestamp.mTicks = 0; - dataset.mPendingTimestamp.mAuthoritative = false; - dataset.mComponents.mIsPendingTimestampPresent = true; - } - else if (*arg == "networkkey") - { - arg++; - dataset.mComponents.mIsNetworkKeyPresent = true; - SuccessOrExit(error = arg->ParseAsHexString(dataset.mNetworkKey.m8)); - } - else if (*arg == "networkname") - { - arg++; - dataset.mComponents.mIsNetworkNamePresent = true; - VerifyOrExit(!arg->IsEmpty(), error = OT_ERROR_INVALID_ARGS); - SuccessOrExit(error = otNetworkNameFromString(&dataset.mNetworkName, arg->GetCString())); - } - else if (*arg == "extpanid") - { - arg++; - dataset.mComponents.mIsExtendedPanIdPresent = true; - SuccessOrExit(error = arg->ParseAsHexString(dataset.mExtendedPanId.m8)); - } - else if (*arg == "localprefix") - { - otIp6Address prefix; + const ComponentMapper *mapper = LookupMapper(arg->GetCString()); - arg++; - dataset.mComponents.mIsMeshLocalPrefixPresent = true; - SuccessOrExit(error = arg->ParseAsIp6Address(prefix)); - memcpy(dataset.mMeshLocalPrefix.m8, prefix.mFields.m8, sizeof(dataset.mMeshLocalPrefix.m8)); - } - else if (*arg == "delaytimer") - { - arg++; - dataset.mComponents.mIsDelayPresent = true; - SuccessOrExit(error = arg->ParseAsUint32(dataset.mDelay)); - } - else if (*arg == "panid") - { - arg++; - dataset.mComponents.mIsPanIdPresent = true; - SuccessOrExit(error = arg->ParseAsUint16(dataset.mPanId)); - } - else if (*arg == "channel") - { - arg++; - dataset.mComponents.mIsChannelPresent = true; - SuccessOrExit(error = arg->ParseAsUint16(dataset.mChannel)); - } - else if (*arg == "channelmask") - { - arg++; - dataset.mComponents.mIsChannelMaskPresent = true; - SuccessOrExit(error = arg->ParseAsUint32(dataset.mChannelMask)); - } - else if (*arg == "securitypolicy") + if (mapper != nullptr) { arg++; - SuccessOrExit(error = ParseSecurityPolicy(dataset.mSecurityPolicy, arg)); - dataset.mComponents.mIsSecurityPolicyPresent = true; + SuccessOrExit(error = (this->*mapper->mParse)(arg, dataset)); + dataset.mComponents.*mapper->mIsPresentPtr = true; } else if (*arg == "-x") { @@ -824,6 +785,7 @@ template <> otError Dataset::Process(Arg aArgs[]) length = sizeof(tlvs); SuccessOrExit(error = arg->ParseAsHexString(length, tlvs)); tlvsLength = static_cast(length); + arg++; } else { @@ -895,45 +857,11 @@ template <> otError Dataset::Process(Arg aArgs[]) for (Arg *arg = &aArgs[1]; !arg->IsEmpty(); arg++) { - if (*arg == "activetimestamp") - { - datasetComponents.mIsActiveTimestampPresent = true; - } - else if (*arg == "pendingtimestamp") - { - datasetComponents.mIsPendingTimestampPresent = true; - } - else if (*arg == "networkkey") - { - datasetComponents.mIsNetworkKeyPresent = true; - } - else if (*arg == "networkname") - { - datasetComponents.mIsNetworkNamePresent = true; - } - else if (*arg == "extpanid") - { - datasetComponents.mIsExtendedPanIdPresent = true; - } - else if (*arg == "localprefix") - { - datasetComponents.mIsMeshLocalPrefixPresent = true; - } - else if (*arg == "delaytimer") - { - datasetComponents.mIsDelayPresent = true; - } - else if (*arg == "panid") - { - datasetComponents.mIsPanIdPresent = true; - } - else if (*arg == "channel") - { - datasetComponents.mIsChannelPresent = true; - } - else if (*arg == "securitypolicy") + const ComponentMapper *mapper = LookupMapper(arg->GetCString()); + + if (mapper != nullptr) { - datasetComponents.mIsSecurityPolicyPresent = true; + datasetComponents.*mapper->mIsPresentPtr = true; } else if (*arg == "-x") { @@ -1020,77 +948,6 @@ template <> otError Dataset::Process(Arg aArgs[]) return error; } -/** - * @cli dataset pskc (get,set) - * @code - * dataset pskc - * 67c0c203aa0b042bfb5381c47aef4d9e - * Done - * @endcode - * @code - * dataset pskc -p 123456 - * Done - * @endcode - * @code - * dataset pskc 67c0c203aa0b042bfb5381c47aef4d9e - * Done - * @endcode - * @cparam dataset pskc [@ca{-p} @ca{passphrase}] | [@ca{key}] - * For FTD only, use `-p` with the `passphrase` argument. `-p` generates a pskc from - * the UTF-8 encoded `passphrase` that you provide, together with - * the network name and extended PAN ID. If set, `-p` uses the dataset buffer; - * otherwise, it uses the current stack. - * Alternatively, you can set pskc as `key` (hex format). - * @par - * Gets or sets #otOperationalDataset::mPskc. - */ -template <> otError Dataset::Process(Arg aArgs[]) -{ - otError error = OT_ERROR_NONE; - otOperationalDataset dataset; - - if (aArgs[0].IsEmpty()) - { - SuccessOrExit(error = otDatasetParseTlvs(&sDatasetTlvs, &dataset)); - // dataset holds the key as a literal string, we don't - // need to export it from PSA ITS. - if (dataset.mComponents.mIsPskcPresent) - { - OutputBytesLine(dataset.mPskc.m8); - } - } - else - { - memset(&dataset, 0, sizeof(dataset)); -#if OPENTHREAD_FTD - if (aArgs[0] == "-p") - { - VerifyOrExit(!aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); - - SuccessOrExit( - error = otDatasetGeneratePskc( - aArgs[1].GetCString(), - (dataset.mComponents.mIsNetworkNamePresent - ? &dataset.mNetworkName - : reinterpret_cast(otThreadGetNetworkName(GetInstancePtr()))), - (dataset.mComponents.mIsExtendedPanIdPresent ? &dataset.mExtendedPanId - : otThreadGetExtendedPanId(GetInstancePtr())), - &dataset.mPskc)); - } - else -#endif - { - SuccessOrExit(error = aArgs[0].ParseAsHexString(dataset.mPskc.m8)); - } - - dataset.mComponents.mIsPskcPresent = true; - SuccessOrExit(error = otDatasetUpdateTlvs(&dataset, &sDatasetTlvs)); - } - -exit: - return error; -} - void Dataset::OutputSecurityPolicy(const otSecurityPolicy &aSecurityPolicy) { OutputFormat("%u ", aSecurityPolicy.mRotationTime); @@ -1198,6 +1055,7 @@ otError Dataset::ParseSecurityPolicy(otSecurityPolicy &aSecurityPolicy, Arg *&aA VerifyOrExit(!aArgs->IsEmpty()); SuccessOrExit(error = aArgs->ParseAsUint8(versionThreshold)); + aArgs++; VerifyOrExit(versionThreshold <= kMaxVersionThreshold, error = OT_ERROR_INVALID_ARGS); policy.mVersionThresholdForRouting = versionThreshold; @@ -1210,53 +1068,6 @@ otError Dataset::ParseSecurityPolicy(otSecurityPolicy &aSecurityPolicy, Arg *&aA return error; } -/** - * @cli dataset securitypolicy (get,set) - * @code - * dataset securitypolicy - * 672 onrc - * Done - * @endcode - * @code - * dataset securitypolicy 672 onrc - * Done - * @endcode - * @cparam dataset securitypolicy [@ca{rotationtime} [@ca{onrcCepR}]] - * * Use `rotationtime` for `thrKeyRotation`, in units of hours. - * * Security Policy commands use the `onrcCepR` argument mappings to get and set - * #otSecurityPolicy members, for example `o` represents - * #otSecurityPolicy::mObtainNetworkKeyEnabled. - * @moreinfo{@dataset}. - * @par - * Gets or sets the %Dataset security policy. - */ -template <> otError Dataset::Process(Arg aArgs[]) -{ - otError error = OT_ERROR_NONE; - otOperationalDataset dataset; - - if (aArgs[0].IsEmpty()) - { - SuccessOrExit(error = otDatasetParseTlvs(&sDatasetTlvs, &dataset)); - if (dataset.mComponents.mIsSecurityPolicyPresent) - { - OutputSecurityPolicy(dataset.mSecurityPolicy); - } - } - else - { - Arg *arg = &aArgs[0]; - - memset(&dataset, 0, sizeof(dataset)); - SuccessOrExit(error = ParseSecurityPolicy(dataset.mSecurityPolicy, arg)); - dataset.mComponents.mIsSecurityPolicyPresent = true; - SuccessOrExit(error = otDatasetUpdateTlvs(&dataset, &sDatasetTlvs)); - } - -exit: - return error; -} - /** * @cli dataset set (active,pending) * @code @@ -1389,24 +1200,12 @@ otError Dataset::Process(Arg aArgs[]) static constexpr Command kCommands[] = { CmdEntry("active"), - CmdEntry("activetimestamp"), - CmdEntry("channel"), - CmdEntry("channelmask"), CmdEntry("clear"), CmdEntry("commit"), - CmdEntry("delay"), - CmdEntry("extpanid"), CmdEntry("init"), - CmdEntry("meshlocalprefix"), CmdEntry("mgmtgetcommand"), CmdEntry("mgmtsetcommand"), - CmdEntry("networkkey"), - CmdEntry("networkname"), - CmdEntry("panid"), CmdEntry("pending"), - CmdEntry("pendingtimestamp"), - CmdEntry("pskc"), - CmdEntry("securitypolicy"), CmdEntry("set"), CmdEntry("tlvs"), #if OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE && OPENTHREAD_FTD @@ -1418,8 +1217,9 @@ otError Dataset::Process(Arg aArgs[]) static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted"); - otError error = OT_ERROR_INVALID_COMMAND; - const Command *command; + otError error = OT_ERROR_INVALID_COMMAND; + const Command *command; + const ComponentMapper *mapper; if (aArgs[0].IsEmpty()) { @@ -1463,6 +1263,14 @@ otError Dataset::Process(Arg aArgs[]) ExitNow(error = OT_ERROR_NONE); } + mapper = LookupMapper(aArgs[0].GetCString()); + + if (mapper != nullptr) + { + error = ProcessCommand(*mapper, aArgs + 1); + ExitNow(); + } + command = BinarySearch::Find(aArgs[0].GetCString(), kCommands); VerifyOrExit(command != nullptr); diff --git a/third_party/openthread/repo/src/cli/cli_dataset.hpp b/third_party/openthread/repo/src/cli/cli_dataset.hpp index 4663650f..85878623 100644 --- a/third_party/openthread/repo/src/cli/cli_dataset.hpp +++ b/third_party/openthread/repo/src/cli/cli_dataset.hpp @@ -74,7 +74,53 @@ class Dataset : private Output otError Process(Arg aArgs[]); private: - using Command = CommandEntry; + using Command = CommandEntry; + using Components = otOperationalDatasetComponents; + + struct ComponentMapper + { + int Compare(const char *aName) const { return strcmp(aName, mName); } + + constexpr static bool AreInOrder(const ComponentMapper &aFirst, const ComponentMapper &aSecond) + { + return AreStringsInOrder(aFirst.mName, aSecond.mName); + } + + const char *mName; + bool Components::*mIsPresentPtr; + void (Dataset::*mOutput)(const otOperationalDataset &aDataset); + otError (Dataset::*mParse)(Arg *&aArgs, otOperationalDataset &aDataset); + }; + + const ComponentMapper *LookupMapper(const char *aName) const; + + void OutputActiveTimestamp(const otOperationalDataset &aDataset); + void OutputChannel(const otOperationalDataset &aDataset); + void OutputChannelMask(const otOperationalDataset &aDataset); + void OutputDelay(const otOperationalDataset &aDataset); + void OutputExtendedPanId(const otOperationalDataset &aDataset); + void OutputMeshLocalPrefix(const otOperationalDataset &aDataset); + void OutputNetworkKey(const otOperationalDataset &aDataset); + void OutputNetworkName(const otOperationalDataset &aDataset); + void OutputPanId(const otOperationalDataset &aDataset); + void OutputPendingTimestamp(const otOperationalDataset &aDataset); + void OutputPskc(const otOperationalDataset &aDataset); + void OutputSecurityPolicy(const otOperationalDataset &aDataset); + + otError ParseActiveTimestamp(Arg *&aArgs, otOperationalDataset &aDataset); + otError ParseChannel(Arg *&aArgs, otOperationalDataset &aDataset); + otError ParseChannelMask(Arg *&aArgs, otOperationalDataset &aDataset); + otError ParseDelay(Arg *&aArgs, otOperationalDataset &aDataset); + otError ParseExtendedPanId(Arg *&aArgs, otOperationalDataset &aDataset); + otError ParseMeshLocalPrefix(Arg *&aArgs, otOperationalDataset &aDataset); + otError ParseNetworkKey(Arg *&aArgs, otOperationalDataset &aDataset); + otError ParseNetworkName(Arg *&aArgs, otOperationalDataset &aDataset); + otError ParsePanId(Arg *&aArgs, otOperationalDataset &aDataset); + otError ParsePendingTimestamp(Arg *&aArgs, otOperationalDataset &aDataset); + otError ParsePskc(Arg *&aArgs, otOperationalDataset &aDataset); + otError ParseSecurityPolicy(Arg *&aArgs, otOperationalDataset &aDataset); + + otError ProcessCommand(const ComponentMapper &aMapper, Arg aArgs[]); template otError Process(Arg aArgs[]); diff --git a/third_party/openthread/repo/src/cli/cli_dns.cpp b/third_party/openthread/repo/src/cli/cli_dns.cpp index 8d7e0a41..c532a0f6 100644 --- a/third_party/openthread/repo/src/cli/cli_dns.cpp +++ b/third_party/openthread/repo/src/cli/cli_dns.cpp @@ -496,7 +496,7 @@ otError Dns::ParseDnsServiceMode(const Arg &aArg, otDnsServiceMode &aMode) const ExitNow(); } - for (uint8_t index = 0; index < OT_ARRAY_LENGTH(kServiceModeStrings); index++) + for (size_t index = 0; index < OT_ARRAY_LENGTH(kServiceModeStrings); index++) { if (aArg == kServiceModeStrings[index]) { diff --git a/third_party/openthread/repo/src/cli/cli_history.cpp b/third_party/openthread/repo/src/cli/cli_history.cpp index e2fa0875..b44a74fc 100644 --- a/third_party/openthread/repo/src/cli/cli_history.cpp +++ b/third_party/openthread/repo/src/cli/cli_history.cpp @@ -375,10 +375,10 @@ template <> otError History::Process(Arg aArgs[]) otHistoryTrackerEntryAgeToString(entryAge, ageString, sizeof(ageString)); - OutputLine(isList ? "%s -> role:%s mode:%s rloc16:0x%04x partition-id:%u" - : "| %20s | %-8s | %-4s | 0x%04x | %12u |", - ageString, otThreadDeviceRoleToString(info->mRole), - Interpreter::LinkModeToString(info->mMode, linkModeString), info->mRloc16, info->mPartitionId); + OutputLine( + isList ? "%s -> role:%s mode:%s rloc16:0x%04x partition-id:%lu" : "| %20s | %-8s | %-4s | 0x%04x | %12lu |", + ageString, otThreadDeviceRoleToString(info->mRole), + Interpreter::LinkModeToString(info->mMode, linkModeString), info->mRloc16, ToUlong(info->mPartitionId)); } exit: diff --git a/third_party/openthread/repo/src/cli/cli_mac_filter.cpp b/third_party/openthread/repo/src/cli/cli_mac_filter.cpp index 6525a20a..547fbed5 100644 --- a/third_party/openthread/repo/src/cli/cli_mac_filter.cpp +++ b/third_party/openthread/repo/src/cli/cli_mac_filter.cpp @@ -137,10 +137,49 @@ template <> otError MacFilter::Process(Arg aArgs[]) otError error = OT_ERROR_NONE; otExtAddress extAddr; + /** + * @cli macfilter addr + * @code + * macfilter addr + * Allowlist + * 0f6127e33af6b403 : rss -95 (lqi 1) + * 0f6127e33af6b402 + * Done + * @endcode + * @par + * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. + * @par + * Provides the following information: + * - Current mode of the MAC filter list: Either `AllowList`, `DenyList,` or `Disabled` + * - A list of all the extended addresses in the filter. The received signal strength (rss) and + * link quality indicator (lqi) are listed next to the address if these values have been set to be + * different from the default values. + * @sa otLinkFilterGetAddressMode + */ if (aArgs[0].IsEmpty()) { OutputFilter(kAddressFilter); } + /** + * @cli macfilter addr add + * @code + * macfilter addr add 0f6127e33af6b403 -95 + * Done + * @endcode + * @code + * macfilter addr add 0f6127e33af6b402 + * Done + * @endcode + * @cparam macfilter addr add @ca{extaddr} [@ca{rss}] + * @par + * Is available only when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. + * @par + * Adds an IEEE 802.15.4 Extended Address to the MAC filter list. + * If you specify the optional `rss` argument, this fixes the received signal strength for messages from the + * address. If you do not use the `rss` option, the address will use whatever default value you have set. + * If you have not set a default, the signal strength will be the over-air signal. + * @sa otLinkFilterAddAddress + */ else if (aArgs[0] == "add") { SuccessOrExit(error = aArgs[1].ParseAsHexString(extAddr.m8)); @@ -156,11 +195,39 @@ template <> otError MacFilter::Process(Arg aArgs[]) SuccessOrExit(error = otLinkFilterAddRssIn(GetInstancePtr(), &extAddr, rss)); } } + /** + * @cli macfilter addr remove + * @code + * macfilter addr remove 0f6127e33af6b402 + * Done + * @endcode + * @cparam macfilter addr remove @ca{extaddr} + * @par + * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. + * @par + * This command removes the specified extended address from the MAC filter list. + * @note No action is performed if the specified extended address does not match an entry in the MAC filter list. + * @sa otLinkFilterRemoveAddress + */ else if (aArgs[0] == "remove") { SuccessOrExit(error = aArgs[1].ParseAsHexString(extAddr.m8)); otLinkFilterRemoveAddress(GetInstancePtr(), &extAddr); } + /** + * @cli macfilter addr clear + * @code + * macfilter addr clear + * Done + * @endcode + * @par + * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. + * @par + * This command clears all the extended addresses from the MAC filter list. + * @note This command does not affect entries in the `RssIn` list. That list contains extended addresses where the + * `rss` has been set to a fixed value that differs from the default. + * @sa otLinkFilterClearAddresses + */ else if (aArgs[0] == "clear") { otLinkFilterClearAddresses(GetInstancePtr()); @@ -168,12 +235,43 @@ template <> otError MacFilter::Process(Arg aArgs[]) else { static const char *const kModeCommands[] = { - "disable", // (0) OT_MAC_FILTER_ADDRESS_MODE_DISABLED + /** + * @cli macfilter addr disable + * @code + * macfilter addr disable + * Done + * @endcode + * @par + * Disables MAC filter modes. + */ + "disable", // (0) OT_MAC_FILTER_ADDRESS_MODE_DISABLED + /** + * @cli macfilter addr allowlist + * @code + * macfilter addr allowlist + * Done + * @endcode + * @par + * Enables the `allowlist` MAC filter mode, which means that only the MAC addresses in the MAC filter list + * will be allowed access. + * @sa otLinkFilterSetAddressMode + */ "allowlist", // (1) OT_MAC_FILTER_ADDRESS_MODE_ALLOWLIST - "denylist", // (2) OT_MAC_FILTER_ADDRESS_MODE_DENYLIST + /** + * @cli macfilter addr denylist + * @code + * macfilter addr denylist + * Done + * @endcode + * @par + * Enables the `denylist` MAC filter mode, which means that all MAC addresses in the MAC filter list + * will be denied access. + * @sa otLinkFilterSetAddressMode + */ + "denylist", // (2) OT_MAC_FILTER_ADDRESS_MODE_DENYLIST }; - for (uint8_t index = 0; index < OT_ARRAY_LENGTH(kModeCommands); index++) + for (size_t index = 0; index < OT_ARRAY_LENGTH(kModeCommands); index++) { if (aArgs[0] == kModeCommands[index]) { @@ -190,6 +288,26 @@ template <> otError MacFilter::Process(Arg aArgs[]) return error; } +/** + * @cli macfilter rss + * @code + * macfilter rss + * 0f6127e33af6b403 : rss -95 (lqi 1) + * Default rss: -50 (lqi 3) + * Done + * @endcode + * @par + * Provides the following information: + * - Listing of all the extended addresses + * where the received signal strength (`rss`) has been set to be different from + * the default value. The link quality indicator (`lqi`) is also shown. The `rss` + * and `lqi` settings map to each other. If you set one, the value of the other + * gets set automatically. This list of addresses is called the `RssIn List`. + * Setting either the `rsi` or the `lqi` adds the corresponding extended address + * to the `RssIn` list. + * - `Default rss`: Shows the default values, if applicable, for the `rss` and `lqi` settings. + * @sa otLinkFilterGetNextRssIn + */ template <> otError MacFilter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; @@ -200,6 +318,32 @@ template <> otError MacFilter::Process(Arg aArgs[]) { OutputFilter(kRssFilter); } + /** + * @cli macfilter rss add-lqi + * @code + * macfilter rss add-lqi * 3 + * Done + * @endcode + * @code + * macfilter rss add-lqi 0f6127e33af6b404 2 + * Done + * @endcode + * @cparam macfilter rss add-lqi @ca{extaddr} @ca{lqi} + * To set a default value for the link quality indicator for all received messages, + * use the `*` for the `extaddr` argument. The allowed range is 0 to 3. + * @par + * Adds the specified Extended Address to the `RssIn` list (or modifies an existing address in the `RssIn` list) + * and sets the fixed link quality indicator for messages from that address. + * The Extended Address + * does not necessarily have to be in the `address allowlist/denylist` filter to set the `lqi`. + * @note The `RssIn` list contains Extended Addresses whose `lqi` or + * received signal strength (`rss`) values have been set to be different from the defaults. + * The `lqi` will automatically get converted to a corresponding `rss` value. + * @par + * This is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. + * @sa otLinkConvertLinkQualityToRss + * @sa otLinkFilterSetDefaultRssIn + */ else if (aArgs[0] == "add-lqi") { uint8_t linkQuality; @@ -218,6 +362,22 @@ template <> otError MacFilter::Process(Arg aArgs[]) error = otLinkFilterAddRssIn(GetInstancePtr(), &extAddr, rss); } } + /** + * @cli macfilter rss add + * @code + * macfilter rss add * -50 + * Done + * @endcode + * @code + * macfilter rss add 0f6127e33af6b404 -85 + * Done + * @endcode + * @cparam macfilter rss add @ca{extaddr} @ca{rss} + * To set a default value for the received signal strength for all received messages, + * use the `*` for the `extaddr` argument. + * @par api_copy + * #otLinkFilterAddRssIn + */ else if (aArgs[0] == "add") { SuccessOrExit(error = aArgs[2].ParseAsInt8(rss)); @@ -232,6 +392,23 @@ template <> otError MacFilter::Process(Arg aArgs[]) error = otLinkFilterAddRssIn(GetInstancePtr(), &extAddr, rss); } } + /** + * @cli macfilter rss remove + * @code + * macfilter rss remove * + * Done + * @endcode + * @code + * macfilter rss remove 0f6127e33af6b404 + * Done + * @endcode + * @cparam macfilter rss remove @ca{extaddr} + * If you wish to remove the default received signal strength and link quality indicator settings, + * use the `*` as the `extaddr`. This unsets the defaults but does not remove + * entries from the `RssIn` list. + * @par api_copy + * #otLinkFilterRemoveRssIn + */ else if (aArgs[0] == "remove") { if (aArgs[1] == "*") @@ -244,6 +421,15 @@ template <> otError MacFilter::Process(Arg aArgs[]) otLinkFilterRemoveRssIn(GetInstancePtr(), &extAddr); } } + /** + * @cli macfilter rss clear + * @code + * macfilter rss clear + * Done + * @endcode + * @par api_copy + * #otLinkFilterClearAllRssIn + */ else if (aArgs[0] == "clear") { otLinkFilterClearAllRssIn(GetInstancePtr()); @@ -276,6 +462,32 @@ otError MacFilter::Process(Arg aArgs[]) otError error = OT_ERROR_INVALID_COMMAND; const Command *command; + /** + * @cli macfilter + * @code + * macfilter + * Address Mode: Allowlist + * 0f6127e33af6b403 : rss -95 (lqi 1) + * 0f6127e33af6b402 + * RssIn List: + * 0f6127e33af6b403 : rss -95 (lqi 1) + * Default rss: -50 (lqi 3) + * Done + * @endcode + * @par + * Provides the following information: + * - `Address Mode`: Current mode of the MAC filter: Either `AllowList`, `DenyList,` or `Disabled` + * - A list of all the extended addresses in the MAC filter list. The received signal strength (rss) and + * link quality indicator (lqi) are listed next to the address if these values have been set to be + * different from the default values. + * - A separate list (`RssIn List`) that shows all the extended addresses where the `rss` has been set to + * be different from the default value. + * - `Default rss`: Shows the default values, if applicable, for the `rss` and `lqi` settings. + * @note An extended address can be in the `RssIn` list without being in the MAC filter list. + * @sa otLinkFilterSetAddressMode + * @sa otLinkFilterGetNextAddress + * @sa otLinkFilterGetNextRssIn + */ if (aArgs[0].IsEmpty()) { OutputFilter(kAddressFilter | kRssFilter); diff --git a/third_party/openthread/repo/src/cli/cli_network_data.cpp b/third_party/openthread/repo/src/cli/cli_network_data.cpp index 8c492e38..85c3e262 100644 --- a/third_party/openthread/repo/src/cli/cli_network_data.cpp +++ b/third_party/openthread/repo/src/cli/cli_network_data.cpp @@ -134,6 +134,11 @@ void NetworkData::RouteFlagsToString(const otExternalRouteConfig &aConfig, Flags *flagsPtr++ = 'n'; } + if (aConfig.mAdvPio) + { + *flagsPtr++ = 'a'; + } + *flagsPtr = '\0'; } @@ -657,6 +662,33 @@ void NetworkData::OutputLowpanContexts(bool aLocal) return; } +void NetworkData::OutputCommissioningDataset(bool aLocal) +{ + otCommissioningDataset dataset; + + VerifyOrExit(!aLocal); + + otNetDataGetCommissioningDataset(GetInstancePtr(), &dataset); + + OutputLine("Commissioning:"); + + dataset.mIsSessionIdSet ? OutputFormat("%u ", dataset.mSessionId) : OutputFormat("- "); + dataset.mIsLocatorSet ? OutputFormat("%04x ", dataset.mLocator) : OutputFormat("- "); + dataset.mIsJoinerUdpPortSet ? OutputFormat("%u ", dataset.mJoinerUdpPort) : OutputFormat("- "); + dataset.mIsSteeringDataSet ? OutputBytes(dataset.mSteeringData.m8, dataset.mSteeringData.mLength) + : OutputFormat("-"); + + if (dataset.mHasExtraTlv) + { + OutputFormat(" e"); + } + + OutputNewLine(); + +exit: + return; +} + otError NetworkData::OutputBinary(bool aLocal) { otError error; @@ -696,6 +728,8 @@ otError NetworkData::OutputBinary(bool aLocal) * 44970 01 9a04b000000e10 s 4000 * Contexts: * fd00:dead:beef:cafe::/64 1 c + * Commissioning: + * 1248 dc00 9988 00000000000120000000000000000000 e * Done * @endcode * @code @@ -746,6 +780,14 @@ otError NetworkData::OutputBinary(bool aLocal) * * Context ID * * Compress flag (`c` if marked or `-` otherwise). * @par + * Commissioning Dataset information is printed under `Commissioning` header: + * * Session ID if present in Dataset or `-` otherwise + * * Border Agent RLOC16 (in hex) if present in Dataset or `-` otherwise + * * Joiner UDP port number if present in Dataset or `-` otherwise + * * Steering Data (as hex bytes) if present in Dataset or `-` otherwise + * * Flags: + * * e: If Dataset contains any extra unknown TLV + * @par * @moreinfo{@netdata}. * @csa{br omrprefix} * @csa{br onlinkprefix} @@ -804,6 +846,7 @@ template <> otError NetworkData::Process(Arg aArgs[]) OutputRoutes(local); OutputServices(local); OutputLowpanContexts(local); + OutputCommissioningDataset(local); error = OT_ERROR_NONE; } diff --git a/third_party/openthread/repo/src/cli/cli_network_data.hpp b/third_party/openthread/repo/src/cli/cli_network_data.hpp index 635ff383..15af6508 100644 --- a/third_party/openthread/repo/src/cli/cli_network_data.hpp +++ b/third_party/openthread/repo/src/cli/cli_network_data.hpp @@ -143,6 +143,7 @@ class NetworkData : private Output void OutputRoutes(bool aLocal); void OutputServices(bool aLocal); void OutputLowpanContexts(bool aLocal); + void OutputCommissioningDataset(bool aLocal); #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL static void HandleNetdataFull(void *aContext) { static_cast(aContext)->HandleNetdataFull(); } diff --git a/third_party/openthread/repo/src/cli/cli_srp_server.cpp b/third_party/openthread/repo/src/cli/cli_srp_server.cpp index 50281ade..5a96d5fe 100644 --- a/third_party/openthread/repo/src/cli/cli_srp_server.cpp +++ b/third_party/openthread/repo/src/cli/cli_srp_server.cpp @@ -270,9 +270,6 @@ void SrpServer::OutputHostAddresses(const otSrpServerHost *aHost) template <> otError SrpServer::Process(Arg aArgs[]) { - static constexpr char *kAnyServiceName = nullptr; - static constexpr char *kAnyInstanceName = nullptr; - otError error = OT_ERROR_NONE; const otSrpServerHost *host = nullptr; @@ -282,18 +279,15 @@ template <> otError SrpServer::Process(Arg aArgs[]) { const otSrpServerService *service = nullptr; - while ((service = otSrpServerHostFindNextService(host, service, OT_SRP_SERVER_FLAGS_BASE_TYPE_SERVICE_ONLY, - kAnyServiceName, kAnyInstanceName)) != nullptr) + while ((service = otSrpServerHostGetNextService(host, service)) != nullptr) { - bool isDeleted = otSrpServerServiceIsDeleted(service); - const char *instanceName = otSrpServerServiceGetInstanceName(service); - const otSrpServerService *subService = nullptr; - const uint8_t *txtData; - uint16_t txtDataLength; - bool hasSubType = false; - otSrpServerLeaseInfo leaseInfo; - - OutputLine("%s", instanceName); + bool isDeleted = otSrpServerServiceIsDeleted(service); + const uint8_t *txtData; + uint16_t txtDataLength; + bool hasSubType = false; + otSrpServerLeaseInfo leaseInfo; + + OutputLine("%s", otSrpServerServiceGetInstanceName(service)); OutputLine(kIndentSize, "deleted: %s", isDeleted ? "true" : "false"); if (isDeleted) @@ -305,13 +299,17 @@ template <> otError SrpServer::Process(Arg aArgs[]) OutputFormat(kIndentSize, "subtypes: "); - while ((subService = otSrpServerHostFindNextService( - host, subService, (OT_SRP_SERVER_SERVICE_FLAG_SUB_TYPE | OT_SRP_SERVER_SERVICE_FLAG_ACTIVE), - kAnyServiceName, instanceName)) != nullptr) + for (uint16_t index = 0;; index++) { - char subLabel[OT_DNS_MAX_LABEL_SIZE]; + char subLabel[OT_DNS_MAX_LABEL_SIZE]; + const char *subTypeName = otSrpServerServiceGetSubTypeServiceNameAt(service, index); + + if (subTypeName == nullptr) + { + break; + } - IgnoreError(otSrpServerServiceGetServiceSubTypeLabel(subService, subLabel, sizeof(subLabel))); + IgnoreError(otSrpServerParseSubTypeServiceName(subTypeName, subLabel, sizeof(subLabel))); OutputFormat("%s%s", hasSubType ? "," : "", subLabel); hasSubType = true; } diff --git a/third_party/openthread/repo/src/cli/cli_tcp.cpp b/third_party/openthread/repo/src/cli/cli_tcp.cpp index f74f4333..67534f0b 100644 --- a/third_party/openthread/repo/src/cli/cli_tcp.cpp +++ b/third_party/openthread/repo/src/cli/cli_tcp.cpp @@ -64,6 +64,7 @@ TcpExample::TcpExample(otInstance *aInstance, OutputImplementer &aOutputImplemen : Output(aInstance, aOutputImplementer) , mInitialized(false) , mEndpointConnected(false) + , mEndpointConnectedFastOpen(false) , mSendBusy(false) , mUseCircularSendBuffer(true) , mUseTls(false) @@ -294,6 +295,7 @@ template <> otError TcpExample::Process(Arg aArgs[]) otError error; otSockAddr sockaddr; bool nat64SynthesizedAddress; + uint32_t flags; VerifyOrExit(mInitialized, error = OT_ERROR_INVALID_STATE); @@ -306,7 +308,26 @@ template <> otError TcpExample::Process(Arg aArgs[]) } SuccessOrExit(error = aArgs[1].ParseAsUint16(sockaddr.mPort)); - VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS); + if (aArgs[2].IsEmpty()) + { + flags = OT_TCP_CONNECT_NO_FAST_OPEN; + } + else + { + if (aArgs[2] == "slow") + { + flags = OT_TCP_CONNECT_NO_FAST_OPEN; + } + else if (aArgs[2] == "fast") + { + flags = 0; + } + else + { + ExitNow(error = OT_ERROR_INVALID_ARGS); + } + VerifyOrExit(aArgs[3].IsEmpty(), error = OT_ERROR_INVALID_ARGS); + } #if OPENTHREAD_CONFIG_TLS_ENABLE if (mUseTls) @@ -320,8 +341,17 @@ template <> otError TcpExample::Process(Arg aArgs[]) } #endif // OPENTHREAD_CONFIG_TLS_ENABLE - SuccessOrExit(error = otTcpConnect(&mEndpoint, &sockaddr, OT_TCP_CONNECT_NO_FAST_OPEN)); - mEndpointConnected = true; + SuccessOrExit(error = otTcpConnect(&mEndpoint, &sockaddr, flags)); + mEndpointConnected = true; + mEndpointConnectedFastOpen = ((flags & OT_TCP_CONNECT_NO_FAST_OPEN) == 0); + +#if OPENTHREAD_CONFIG_TLS_ENABLE + if (mUseTls && mEndpointConnectedFastOpen) + { + PrepareTlsHandshake(); + ContinueTlsHandshake(); + } +#endif exit: return error; @@ -472,7 +502,8 @@ template <> otError TcpExample::Process(Arg aArgs[]) VerifyOrExit(mInitialized, error = OT_ERROR_INVALID_STATE); SuccessOrExit(error = otTcpAbort(&mEndpoint)); - mEndpointConnected = false; + mEndpointConnected = false; + mEndpointConnectedFastOpen = false; exit: return error; @@ -591,24 +622,10 @@ void TcpExample::HandleTcpEstablished(otTcpEndpoint *aEndpoint) OT_UNUSED_VARIABLE(aEndpoint); OutputLine("TCP: Connection established"); #if OPENTHREAD_CONFIG_TLS_ENABLE - if (mUseTls) + if (mUseTls && !mEndpointConnectedFastOpen) { - int rv; - rv = mbedtls_ssl_set_hostname(&mSslContext, "localhost"); - if (rv != 0) - { - OutputLine("mbedtls_ssl_set_hostname returned %d", rv); - } - rv = mbedtls_ssl_set_hs_ecjpake_password( - &mSslContext, reinterpret_cast(sEcjpakePassword), sEcjpakePasswordLength); - if (rv != 0) - { - OutputLine("mbedtls_ssl_set_hs_ecjpake_password returned %d", rv); - } - mbedtls_ssl_set_bio(&mSslContext, &mEndpointAndCircularSendBuffer, otTcpMbedTlsSslSendCallback, - otTcpMbedTlsSslRecvCallback, nullptr); - mTlsHandshakeComplete = false; - ContinueTLSHandshake(); + PrepareTlsHandshake(); + ContinueTlsHandshake(); } #endif // OPENTHREAD_CONFIG_TLS_ENABLE } @@ -660,7 +677,7 @@ void TcpExample::HandleTcpForwardProgress(otTcpEndpoint *aEndpoint, size_t aInSe #if OPENTHREAD_CONFIG_TLS_ENABLE if (mUseTls) { - ContinueTLSHandshake(); + ContinueTlsHandshake(); } #endif @@ -688,8 +705,22 @@ void TcpExample::HandleTcpReceiveAvailable(otTcpEndpoint *aEndpoint, OT_UNUSED_VARIABLE(aBytesRemaining); OT_ASSERT(aEndpoint == &mEndpoint); + /* If we get data before the handshake completes, then this is a TFO connection. */ + if (!mEndpointConnected) + { + mEndpointConnected = true; + mEndpointConnectedFastOpen = true; + +#if OPENTHREAD_CONFIG_TLS_ENABLE + if (mUseTls) + { + PrepareTlsHandshake(); + } +#endif + } + #if OPENTHREAD_CONFIG_TLS_ENABLE - if (mUseTls && ContinueTLSHandshake()) + if (mUseTls && ContinueTlsHandshake()) { return; } @@ -773,8 +804,9 @@ void TcpExample::HandleTcpDisconnected(otTcpEndpoint *aEndpoint, otTcpDisconnect // We set this to false even for the TIME-WAIT state, so that we can reuse // the active socket if an incoming connection comes in instead of waiting // for the 2MSL timeout. - mEndpointConnected = false; - mSendBusy = false; + mEndpointConnected = false; + mEndpointConnectedFastOpen = false; + mSendBusy = false; // Mark the benchmark as inactive if the connection was disconnected. mBenchmarkBytesTotal = 0; @@ -803,20 +835,11 @@ otTcpIncomingConnectionAction TcpExample::HandleTcpAcceptReady(otTcpListener *aAcceptInto = &mEndpoint; action = OT_TCP_INCOMING_CONNECTION_ACTION_ACCEPT; -exit: - return action; -} - -void TcpExample::HandleTcpAcceptDone(otTcpListener *aListener, otTcpEndpoint *aEndpoint, const otSockAddr *aPeer) -{ - OT_UNUSED_VARIABLE(aListener); - OT_UNUSED_VARIABLE(aEndpoint); - - mEndpointConnected = true; - OutputFormat("Accepted connection from "); - OutputSockAddrLine(*aPeer); - #if OPENTHREAD_CONFIG_TLS_ENABLE + /* + * Natural to wait until the AcceptDone callback but with TFO we could get data before that + * so it doesn't make sense to wait until then. + */ if (mUseTls) { int rv; @@ -835,6 +858,19 @@ void TcpExample::HandleTcpAcceptDone(otTcpListener *aListener, otTcpEndpoint *aE } } #endif // OPENTHREAD_CONFIG_TLS_ENABLE + +exit: + return action; +} + +void TcpExample::HandleTcpAcceptDone(otTcpListener *aListener, otTcpEndpoint *aEndpoint, const otSockAddr *aPeer) +{ + OT_UNUSED_VARIABLE(aListener); + OT_UNUSED_VARIABLE(aEndpoint); + + mEndpointConnected = true; + OutputFormat("Accepted connection from "); + OutputSockAddrLine(*aPeer); } otError TcpExample::ContinueBenchmarkCircularSend(void) @@ -908,7 +944,26 @@ void TcpExample::CompleteBenchmark(void) } #if OPENTHREAD_CONFIG_TLS_ENABLE -bool TcpExample::ContinueTLSHandshake(void) +void TcpExample::PrepareTlsHandshake(void) +{ + int rv; + rv = mbedtls_ssl_set_hostname(&mSslContext, "localhost"); + if (rv != 0) + { + OutputLine("mbedtls_ssl_set_hostname returned %d", rv); + } + rv = mbedtls_ssl_set_hs_ecjpake_password(&mSslContext, reinterpret_cast(sEcjpakePassword), + sEcjpakePasswordLength); + if (rv != 0) + { + OutputLine("mbedtls_ssl_set_hs_ecjpake_password returned %d", rv); + } + mbedtls_ssl_set_bio(&mSslContext, &mEndpointAndCircularSendBuffer, otTcpMbedTlsSslSendCallback, + otTcpMbedTlsSslRecvCallback, nullptr); + mTlsHandshakeComplete = false; +} + +bool TcpExample::ContinueTlsHandshake(void) { bool wasNotAlreadyDone = false; int rv; diff --git a/third_party/openthread/repo/src/cli/cli_tcp.hpp b/third_party/openthread/repo/src/cli/cli_tcp.hpp index 24bb75fd..50e72802 100644 --- a/third_party/openthread/repo/src/cli/cli_tcp.hpp +++ b/third_party/openthread/repo/src/cli/cli_tcp.hpp @@ -96,7 +96,8 @@ class TcpExample : private Output void CompleteBenchmark(void); #if OPENTHREAD_CONFIG_TLS_ENABLE - bool ContinueTLSHandshake(void); + void PrepareTlsHandshake(void); + bool ContinueTlsHandshake(void); #endif static void HandleTcpEstablishedCallback(otTcpEndpoint *aEndpoint); @@ -138,6 +139,7 @@ class TcpExample : private Output bool mInitialized; bool mEndpointConnected; + bool mEndpointConnectedFastOpen; bool mSendBusy; bool mUseCircularSendBuffer; bool mUseTls; diff --git a/third_party/openthread/repo/src/cli/cli_udp.cpp b/third_party/openthread/repo/src/cli/cli_udp.cpp index d5f37928..0ec70cce 100644 --- a/third_party/openthread/repo/src/cli/cli_udp.cpp +++ b/third_party/openthread/repo/src/cli/cli_udp.cpp @@ -50,6 +50,36 @@ UdpExample::UdpExample(otInstance *aInstance, OutputImplementer &aOutputImplemen memset(&mSocket, 0, sizeof(mSocket)); } +/** + * @cli udp bind + * @code + * udp bind :: 1234 + * Done + * @endcode + * @code + * udp bind -u :: 1234 + * Done + * @endcode + * @code + * udp bind -b :: 1234 + * Done + * @endcode + * @cparam udp bind [@ca{netif}] @ca{ip} @ca{port} + * - `netif`: The binding network interface, which is determined as follows: + * - No value (leaving out this parameter from the command): Thread network interface is used. + * - `-u`: Unspecified network interface, which means that the UDP/IPv6 stack determines which + * network interface to bind the socket to. + * - `-b`: Backbone network interface is used. + * - `ip`: IPv6 address to bind to. If you wish to have the UDP/IPv6 stack assign the binding + * IPv6 address, then you can use the following value to use the unspecified + * IPv6 address: `::`. Each example uses the unspecified IPv6 address. + * - `port`: UDP port number to bind to. Each of the examples is using port number 1234. + * @par + * Assigns an IPv6 address and a port to an open socket, which binds the socket for communication. + * Assigning the IPv6 address and port is referred to as naming the socket. + * @sa otUdpBind + * @sa @udp + */ template <> otError UdpExample::Process(Arg aArgs[]) { otError error; @@ -77,6 +107,28 @@ template <> otError UdpExample::Process(Arg aArgs[]) return error; } +/** + * @cli udp connect + * @code + * udp connect fdde:ad00:beef:0:bb1:ebd6:ad10:f33 1234 + * Done + * @endcode + * @code + * udp connect 172.17.0.1 1234 + * Connecting to synthesized IPv6 address: fdde:ad00:beef:2:0:0:ac11:1 + * Done + * @endcode + * @cparam udp connect @ca{ip} @ca{port} + * The following parameters are required: + * - `ip`: IP address of the peer. + * - `port`: UDP port number of the peer. + * The address can be an IPv4 address, which gets synthesized to an IPv6 address + * using the preferred NAT64 prefix from the network data. The command returns + * `InvalidState` when the preferred NAT64 prefix is unavailable. + * @par api_copy + * #otUdpConnect + * @sa @udp + */ template <> otError UdpExample::Process(Arg aArgs[]) { otError error; @@ -100,6 +152,15 @@ template <> otError UdpExample::Process(Arg aArgs[]) return error; } +/** + * @cli udp close + * @code + * udp close + * Done + * @endcode + * @par api_copy + * #otUdpClose + */ template <> otError UdpExample::Process(Arg aArgs[]) { OT_UNUSED_VARIABLE(aArgs); @@ -107,6 +168,15 @@ template <> otError UdpExample::Process(Arg aArgs[]) return otUdpClose(GetInstancePtr(), &mSocket); } +/** + * @cli udp open + * @code + * udp open + * Done + * @endcode + * @par api_copy + * #otUdpOpen + */ template <> otError UdpExample::Process(Arg aArgs[]) { OT_UNUSED_VARIABLE(aArgs); @@ -120,6 +190,67 @@ template <> otError UdpExample::Process(Arg aArgs[]) return error; } +/** + * @cli udp send + * @code + * udp send hello + * Done + * @endcode + * @code + * udp send -t hello + * Done + * @endcode + * @code + * udp send -x 68656c6c6f + * Done + * @endcode + * @code + * udp send -s 800 + * Done + * @endcode + * @code + * udp send fdde:ad00:beef:0:bb1:ebd6:ad10:f33 1234 hello + * Done + * @endcode + * @code + * udp send 172.17.0.1 1234 hello + * Sending to synthesized IPv6 address: fdde:ad00:beef:2:0:0:ac11:1 + * Done + * @endcode + * @code + * udp send fdde:ad00:beef:0:bb1:ebd6:ad10:f33 1234 -t hello + * Done + * @endcode + * @code + * udp send fdde:ad00:beef:0:bb1:ebd6:ad10:f33 1234 -x 68656c6c6f + * Done + * @endcode + * @code + * udp send fdde:ad00:beef:0:bb1:ebd6:ad10:f33 1234 -s 800 + * Done + * @endcode + * @cparam udp send [@ca{ip} @ca{port}] [@ca{type}] @ca{value} + * The `ip` and `port` are optional as a pair, but if you specify one you must + * specify the other. If `ip` and `port` are not specified, the socket peer address + * is used from `udp connect`. + * - `ip`: Destination address. This address can be either an IPv4 or IPv6 address, + * An IPv4 address gets synthesized to an IPv6 address with the preferred + * NAT64 prefix from the network data. (If the preferred NAT64 prefix + * is unavailable, the command returns `InvalidState`). + * - `port`: UDP destination port. + * - `type`/`value` combinations: + * - `-t`: The payload in the `value` parameter is treated as text. If no `type` value + * is entered, the payload in the `value` parameter is also treated as text. + * - `-s`: Auto-generated payload with the specified length given in the `value` parameter. + * - `-x`: Binary data in hexadecimal representation given in the `value` parameter. + * @par + * Sends a UDP message using the socket. + * @csa{udp open} + * @csa{udp bind} + * @csa{udp connect} + * @sa otUdpSend + * @sa @udp + */ template <> otError UdpExample::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; @@ -201,10 +332,33 @@ template <> otError UdpExample::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; + /** + * @cli udp linksecurity + * @code + * udp linksecurity + * Enabled + * Done + * @endcode + * @par + * Indicates whether link security is enabled or disabled. + */ if (aArgs[0].IsEmpty()) { OutputEnabledDisabledStatus(mLinkSecurityEnabled); } + /** + * @cli udp linksecurity (enable,disable) + * @code + * udp linksecurity enable + * Done + * @endcode + * @code + * udp linksecurity disable + * Done + * @endcode + * @par + * Enables or disables link security. + */ else { error = Interpreter::ParseEnableOrDisable(aArgs[0], mLinkSecurityEnabled); diff --git a/third_party/openthread/repo/src/core/BUILD.gn b/third_party/openthread/repo/src/core/BUILD.gn index 1b329707..abb606ed 100644 --- a/third_party/openthread/repo/src/core/BUILD.gn +++ b/third_party/openthread/repo/src/core/BUILD.gn @@ -396,7 +396,6 @@ openthread_core_files = [ "common/equatable.hpp", "common/error.cpp", "common/error.hpp", - "common/extension.hpp", "common/frame_builder.cpp", "common/frame_builder.hpp", "common/frame_data.cpp", @@ -409,8 +408,6 @@ openthread_core_files = [ "common/heap_data.hpp", "common/heap_string.cpp", "common/heap_string.hpp", - "common/instance.cpp", - "common/instance.hpp", "common/iterator_utils.hpp", "common/linked_list.hpp", "common/locator.hpp", @@ -474,6 +471,9 @@ openthread_core_files = [ "crypto/storage.hpp", "diags/factory_diags.cpp", "diags/factory_diags.hpp", + "instance/extension.hpp", + "instance/instance.cpp", + "instance/instance.hpp", "mac/channel_mask.cpp", "mac/channel_mask.hpp", "mac/data_poll_handler.cpp", @@ -604,6 +604,8 @@ openthread_core_files = [ "thread/announce_sender.hpp", "thread/anycast_locator.cpp", "thread/anycast_locator.hpp", + "thread/child.cpp", + "thread/child.hpp", "thread/child_mask.hpp", "thread/child_supervision.cpp", "thread/child_supervision.hpp", @@ -646,6 +648,8 @@ openthread_core_files = [ "thread/mlr_manager.cpp", "thread/mlr_manager.hpp", "thread/mlr_types.hpp", + "thread/neighbor.cpp", + "thread/neighbor.hpp", "thread/neighbor_table.cpp", "thread/neighbor_table.hpp", "thread/network_data.cpp", @@ -674,6 +678,8 @@ openthread_core_files = [ "thread/panid_query_server.hpp", "thread/radio_selector.cpp", "thread/radio_selector.hpp", + "thread/router.cpp", + "thread/router.hpp", "thread/router_table.cpp", "thread/router_table.hpp", "thread/src_match_controller.cpp", @@ -685,8 +691,6 @@ openthread_core_files = [ "thread/time_sync_service.hpp", "thread/tmf.cpp", "thread/tmf.hpp", - "thread/topology.cpp", - "thread/topology.hpp", "thread/uri_paths.cpp", "thread/uri_paths.hpp", "thread/version.hpp", @@ -702,6 +706,8 @@ openthread_core_files = [ "utils/history_tracker.hpp", "utils/jam_detector.cpp", "utils/jam_detector.hpp", + "utils/link_metrics_manager.cpp", + "utils/link_metrics_manager.hpp", "utils/mesh_diag.cpp", "utils/mesh_diag.hpp", "utils/otns.cpp", @@ -731,7 +737,6 @@ openthread_radio_sources = [ "common/error.hpp", "common/frame_builder.cpp", "common/frame_builder.hpp", - "common/instance.cpp", "common/log.cpp", "common/random.cpp", "common/string.cpp", @@ -743,6 +748,7 @@ openthread_radio_sources = [ "crypto/crypto_platform.cpp", "crypto/storage.cpp", "diags/factory_diags.cpp", + "instance/instance.cpp", "mac/link_raw.cpp", "mac/mac_frame.cpp", "mac/mac_types.cpp", @@ -788,6 +794,7 @@ source_set("libopenthread_core_config") { "config/history_tracker.h", "config/ip6.h", "config/joiner.h", + "config/link_metrics_manager.h", "config/link_quality.h", "config/link_raw.h", "config/logging.h", diff --git a/third_party/openthread/repo/src/core/CMakeLists.txt b/third_party/openthread/repo/src/core/CMakeLists.txt index e77b576e..813979ad 100644 --- a/third_party/openthread/repo/src/core/CMakeLists.txt +++ b/third_party/openthread/repo/src/core/CMakeLists.txt @@ -106,7 +106,6 @@ set(COMMON_SOURCES common/heap.cpp common/heap_data.cpp common/heap_string.cpp - common/instance.cpp common/log.cpp common/message.cpp common/notifier.cpp @@ -129,6 +128,7 @@ set(COMMON_SOURCES crypto/sha256.cpp crypto/storage.cpp diags/factory_diags.cpp + instance/instance.cpp mac/channel_mask.cpp mac/data_poll_handler.cpp mac/data_poll_sender.cpp @@ -195,6 +195,7 @@ set(COMMON_SOURCES thread/announce_begin_server.cpp thread/announce_sender.cpp thread/anycast_locator.cpp + thread/child.cpp thread/child_supervision.cpp thread/child_table.cpp thread/csl_tx_scheduler.cpp @@ -215,6 +216,7 @@ set(COMMON_SOURCES thread/mle_tlvs.cpp thread/mle_types.cpp thread/mlr_manager.cpp + thread/neighbor.cpp thread/neighbor_table.cpp thread/network_data.cpp thread/network_data_leader.cpp @@ -229,12 +231,12 @@ set(COMMON_SOURCES thread/network_diagnostic_tlvs.cpp thread/panid_query_server.cpp thread/radio_selector.cpp + thread/router.cpp thread/router_table.cpp thread/src_match_controller.cpp thread/thread_netif.cpp thread/time_sync_service.cpp thread/tmf.cpp - thread/topology.cpp thread/uri_paths.cpp utils/channel_manager.cpp utils/channel_monitor.cpp @@ -242,6 +244,7 @@ set(COMMON_SOURCES utils/heap.cpp utils/history_tracker.cpp utils/jam_detector.cpp + utils/link_metrics_manager.cpp utils/mesh_diag.cpp utils/otns.cpp utils/parse_cmdline.cpp @@ -262,7 +265,6 @@ set(RADIO_COMMON_SOURCES common/binary_search.cpp common/error.cpp common/frame_builder.cpp - common/instance.cpp common/log.cpp common/random.cpp common/string.cpp @@ -274,6 +276,7 @@ set(RADIO_COMMON_SOURCES crypto/crypto_platform.cpp crypto/storage.cpp diags/factory_diags.cpp + instance/instance.cpp mac/link_raw.cpp mac/mac_frame.cpp mac/mac_types.cpp diff --git a/third_party/openthread/repo/src/core/api/backbone_router_ftd_api.cpp b/third_party/openthread/repo/src/core/api/backbone_router_ftd_api.cpp index e24c642e..bd3a3c35 100644 --- a/third_party/openthread/repo/src/core/api/backbone_router_ftd_api.cpp +++ b/third_party/openthread/repo/src/core/api/backbone_router_ftd_api.cpp @@ -69,7 +69,7 @@ otError otBackboneRouterSetConfig(otInstance *aInstance, const otBackboneRouterC otError otBackboneRouterRegister(otInstance *aInstance) { - return AsCoreType(aInstance).Get().AddService(true /* Force registration */); + return AsCoreType(aInstance).Get().AddService(BackboneRouter::Local::kForceRegistration); } uint8_t otBackboneRouterGetRegistrationJitter(otInstance *aInstance) diff --git a/third_party/openthread/repo/src/core/api/border_router_api.cpp b/third_party/openthread/repo/src/core/api/border_router_api.cpp index 5694768e..dcccf5bb 100644 --- a/third_party/openthread/repo/src/core/api/border_router_api.cpp +++ b/third_party/openthread/repo/src/core/api/border_router_api.cpp @@ -39,7 +39,7 @@ #include "border_router/routing_manager.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" using namespace ot; diff --git a/third_party/openthread/repo/src/core/api/border_routing_api.cpp b/third_party/openthread/repo/src/core/api/border_routing_api.cpp index 1ed017c5..3a76fa66 100644 --- a/third_party/openthread/repo/src/core/api/border_routing_api.cpp +++ b/third_party/openthread/repo/src/core/api/border_routing_api.cpp @@ -39,7 +39,7 @@ #include #include "border_router/routing_manager.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" using namespace ot; diff --git a/third_party/openthread/repo/src/core/api/coap_api.cpp b/third_party/openthread/repo/src/core/api/coap_api.cpp index 6c52cd2e..25f3208e 100644 --- a/third_party/openthread/repo/src/core/api/coap_api.cpp +++ b/third_party/openthread/repo/src/core/api/coap_api.cpp @@ -211,6 +211,8 @@ otError otCoapSendRequestBlockWiseWithParameters(otInstance *aIn Error error; const Coap::TxParameters &txParameters = Coap::TxParameters::From(aTxParameters); + VerifyOrExit(!AsCoreType(aMessage).IsOriginThreadNetif(), error = kErrorInvalidArgs); + if (aTxParameters != nullptr) { VerifyOrExit(txParameters.IsValid(), error = kErrorInvalidArgs); @@ -236,6 +238,8 @@ otError otCoapSendRequestWithParameters(otInstance *aInstance, const Coap::TxParameters &txParameters = Coap::TxParameters::From(aTxParameters); + VerifyOrExit(!AsCoreType(aMessage).IsOriginThreadNetif(), error = kErrorInvalidArgs); + if (aTxParameters != nullptr) { VerifyOrExit(txParameters.IsValid(), error = kErrorInvalidArgs); @@ -290,9 +294,15 @@ otError otCoapSendResponseBlockWiseWithParameters(otInstance *aI void *aContext, otCoapBlockwiseTransmitHook aTransmitHook) { - return AsCoreType(aInstance).GetApplicationCoap().SendMessage(AsCoapMessage(aMessage), AsCoreType(aMessageInfo), - Coap::TxParameters::From(aTxParameters), nullptr, - aContext, aTransmitHook, nullptr); + otError error; + + VerifyOrExit(!AsCoreType(aMessage).IsOriginThreadNetif(), error = kErrorInvalidArgs); + + error = AsCoreType(aInstance).GetApplicationCoap().SendMessage(AsCoapMessage(aMessage), AsCoreType(aMessageInfo), + Coap::TxParameters::From(aTxParameters), nullptr, + aContext, aTransmitHook, nullptr); +exit: + return error; } #endif @@ -301,8 +311,15 @@ otError otCoapSendResponseWithParameters(otInstance *aInstance, const otMessageInfo *aMessageInfo, const otCoapTxParameters *aTxParameters) { - return AsCoreType(aInstance).GetApplicationCoap().SendMessage( + otError error; + + VerifyOrExit(!AsCoreType(aMessage).IsOriginThreadNetif(), error = kErrorInvalidArgs); + + error = AsCoreType(aInstance).GetApplicationCoap().SendMessage( AsCoapMessage(aMessage), AsCoreType(aMessageInfo), Coap::TxParameters::From(aTxParameters), nullptr, nullptr); + +exit: + return error; } #endif // OPENTHREAD_CONFIG_COAP_API_ENABLE diff --git a/third_party/openthread/repo/src/core/api/dns_api.cpp b/third_party/openthread/repo/src/core/api/dns_api.cpp index 41be0c4f..fe064b66 100644 --- a/third_party/openthread/repo/src/core/api/dns_api.cpp +++ b/third_party/openthread/repo/src/core/api/dns_api.cpp @@ -35,7 +35,7 @@ #include -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "net/dns_types.hpp" using namespace ot; diff --git a/third_party/openthread/repo/src/core/api/dns_server_api.cpp b/third_party/openthread/repo/src/core/api/dns_server_api.cpp index 62e69fc1..80e88e43 100644 --- a/third_party/openthread/repo/src/core/api/dns_server_api.cpp +++ b/third_party/openthread/repo/src/core/api/dns_server_api.cpp @@ -33,7 +33,7 @@ #include "openthread-core-config.h" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "net/dns_types.hpp" #include "net/dnssd_server.hpp" diff --git a/third_party/openthread/repo/src/core/api/instance_api.cpp b/third_party/openthread/repo/src/core/api/instance_api.cpp index ad2a89e1..6d51d3c3 100644 --- a/third_party/openthread/repo/src/core/api/instance_api.cpp +++ b/third_party/openthread/repo/src/core/api/instance_api.cpp @@ -86,6 +86,10 @@ void otInstanceFinalize(otInstance *aInstance) { AsCoreType(aInstance).Finalize( void otInstanceReset(otInstance *aInstance) { AsCoreType(aInstance).Reset(); } +#if OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE +otError otInstanceResetToBootloader(otInstance *aInstance) { return AsCoreType(aInstance).ResetToBootloader(); } +#endif + #if OPENTHREAD_CONFIG_UPTIME_ENABLE uint64_t otInstanceGetUptime(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetUptime(); } diff --git a/third_party/openthread/repo/src/core/api/ip6_api.cpp b/third_party/openthread/repo/src/core/api/ip6_api.cpp index 4ff7d229..d7055706 100644 --- a/third_party/openthread/repo/src/core/api/ip6_api.cpp +++ b/third_party/openthread/repo/src/core/api/ip6_api.cpp @@ -75,6 +75,11 @@ const otNetifAddress *otIp6GetUnicastAddresses(otInstance *aInstance) return AsCoreType(aInstance).Get().GetUnicastAddresses().GetHead(); } +bool otIp6HasUnicastAddress(otInstance *aInstance, const otIp6Address *aAddress) +{ + return AsCoreType(aInstance).Get().HasUnicastAddress(AsCoreType(aAddress)); +} + otError otIp6AddUnicastAddress(otInstance *aInstance, const otNetifAddress *aAddress) { return AsCoreType(aInstance).Get().AddExternalUnicastAddress(AsCoreType(aAddress)); @@ -132,8 +137,14 @@ void otIp6SetReceiveFilterEnabled(otInstance *aInstance, bool aEnabled) otError otIp6Send(otInstance *aInstance, otMessage *aMessage) { - return AsCoreType(aInstance).Get().SendRaw(AsCoreType(aMessage), - OPENTHREAD_CONFIG_IP6_ALLOW_LOOP_BACK_HOST_DATAGRAMS); + otError error; + + VerifyOrExit(!AsCoreType(aMessage).IsOriginThreadNetif(), error = kErrorInvalidArgs); + + error = AsCoreType(aInstance).Get().SendRaw(OwnedPtr(AsCoreTypePtr(aMessage))); + +exit: + return error; } otMessage *otIp6NewMessage(otInstance *aInstance, const otMessageSettings *aSettings) diff --git a/third_party/openthread/repo/src/core/api/link_api.cpp b/third_party/openthread/repo/src/core/api/link_api.cpp index 7a97d4ce..95ec35c4 100644 --- a/third_party/openthread/repo/src/core/api/link_api.cpp +++ b/third_party/openthread/repo/src/core/api/link_api.cpp @@ -395,9 +395,9 @@ bool otLinkIsCslEnabled(otInstance *aInstance) { return AsCoreType(aInstance).Ge bool otLinkIsCslSupported(otInstance *aInstance) { return AsCoreType(aInstance).Get().IsCslSupported(); } -uint8_t otLinkCslGetChannel(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetCslChannel(); } +uint8_t otLinkGetCslChannel(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetCslChannel(); } -otError otLinkCslSetChannel(otInstance *aInstance, uint8_t aChannel) +otError otLinkSetCslChannel(otInstance *aInstance, uint8_t aChannel) { Error error = kErrorNone; @@ -409,25 +409,39 @@ otError otLinkCslSetChannel(otInstance *aInstance, uint8_t aChannel) return error; } -uint16_t otLinkCslGetPeriod(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetCslPeriod(); } +uint32_t otLinkGetCslPeriod(otInstance *aInstance) +{ + return Mac::Mac::CslPeriodToUsec(AsCoreType(aInstance).Get().GetCslPeriod()); +} -otError otLinkCslSetPeriod(otInstance *aInstance, uint16_t aPeriod) +otError otLinkSetCslPeriod(otInstance *aInstance, uint32_t aPeriod) { - Error error = kErrorNone; + Error error = kErrorNone; + uint16_t periodInTenSymbolsUnit; + + if (aPeriod == 0) + { + periodInTenSymbolsUnit = 0; + } + else + { + VerifyOrExit((aPeriod % kUsPerTenSymbols) == 0, error = kErrorInvalidArgs); + periodInTenSymbolsUnit = ClampToUint16(aPeriod / kUsPerTenSymbols); + VerifyOrExit(periodInTenSymbolsUnit >= kMinCslPeriod, error = kErrorInvalidArgs); + } - VerifyOrExit((aPeriod == 0 || kMinCslPeriod <= aPeriod), error = kErrorInvalidArgs); - AsCoreType(aInstance).Get().SetCslPeriod(aPeriod); + AsCoreType(aInstance).Get().SetCslPeriod(periodInTenSymbolsUnit); exit: return error; } -uint32_t otLinkCslGetTimeout(otInstance *aInstance) +uint32_t otLinkGetCslTimeout(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetCslTimeout(); } -otError otLinkCslSetTimeout(otInstance *aInstance, uint32_t aTimeout) +otError otLinkSetCslTimeout(otInstance *aInstance, uint32_t aTimeout) { Error error = kErrorNone; @@ -446,3 +460,24 @@ otError otLinkSendEmptyData(otInstance *aInstance) return AsCoreType(aInstance).Get().SendEmptyMessage(); } #endif + +otError otLinkSetRegion(otInstance *aInstance, uint16_t aRegionCode) +{ + return AsCoreType(aInstance).Get().SetRegion(aRegionCode); +} + +otError otLinkGetRegion(otInstance *aInstance, uint16_t *aRegionCode) +{ + Error error; + + if (aRegionCode == nullptr) + { + error = kErrorInvalidArgs; + } + else + { + error = AsCoreType(aInstance).Get().GetRegion(*aRegionCode); + } + + return error; +} diff --git a/third_party/openthread/repo/src/core/api/link_metrics_api.cpp b/third_party/openthread/repo/src/core/api/link_metrics_api.cpp index 548876d2..8e678d92 100644 --- a/third_party/openthread/repo/src/core/api/link_metrics_api.cpp +++ b/third_party/openthread/repo/src/core/api/link_metrics_api.cpp @@ -54,7 +54,6 @@ otError otLinkMetricsQuery(otInstance *aInstance, AsCoreTypePtr(aLinkMetricsFlags)); } -#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE otError otLinkMetricsConfigForwardTrackingSeries(otInstance *aInstance, const otIp6Address *aDestination, uint8_t aSeriesId, @@ -98,6 +97,26 @@ otError otLinkMetricsSendLinkProbe(otInstance *aInstance, return initiator.SendLinkProbe(AsCoreType(aDestination), aSeriesId, aLength); } + +#if OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE +void otLinkMetricsManagerSetEnabled(otInstance *aInstance, bool aEnable) +{ + AsCoreType(aInstance).Get().SetEnabled(aEnable); +} + +otError otLinkMetricsManagerGetMetricsValueByExtAddr(otInstance *aInstance, + const otExtAddress *aExtAddress, + otLinkMetricsValues *aLinkMetricsValues) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(aExtAddress != nullptr && aLinkMetricsValues != nullptr, error = OT_ERROR_INVALID_ARGS); + + error = AsCoreType(aInstance).Get().GetLinkMetricsValueByExtAddr( + AsCoreType(aExtAddress), AsCoreType(aLinkMetricsValues)); +exit: + return error; +} #endif #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE diff --git a/third_party/openthread/repo/src/core/api/logging_api.cpp b/third_party/openthread/repo/src/core/api/logging_api.cpp index edce6b92..6abbb324 100644 --- a/third_party/openthread/repo/src/core/api/logging_api.cpp +++ b/third_party/openthread/repo/src/core/api/logging_api.cpp @@ -35,9 +35,10 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "common/string.hpp" +#include "instance/instance.hpp" using namespace ot; @@ -179,6 +180,38 @@ void otDumpDebgPlat(const char *aText, const void *aData, uint16_t aDataLength) #endif } +void otLogPlat(otLogLevel aLogLevel, const char *aPlatModuleName, const char *aFormat, ...) +{ +#if OPENTHREAD_CONFIG_LOG_PLATFORM + va_list args; + + va_start(args, aFormat); + otLogPlatArgs(aLogLevel, aPlatModuleName, aFormat, args); + va_end(args); +#else + OT_UNUSED_VARIABLE(aLogLevel); + OT_UNUSED_VARIABLE(aPlatModuleName); + OT_UNUSED_VARIABLE(aFormat); +#endif +} + +void otLogPlatArgs(otLogLevel aLogLevel, const char *aPlatModuleName, const char *aFormat, va_list aArgs) +{ +#if OT_SHOULD_LOG && OPENTHREAD_CONFIG_LOG_PLATFORM + String moduleName; + + OT_ASSERT(aLogLevel >= kLogLevelNone && aLogLevel <= kLogLevelDebg); + + moduleName.Append("P-%s", aPlatModuleName); + Logger::LogVarArgs(moduleName.AsCString(), static_cast(aLogLevel), aFormat, aArgs); +#else + OT_UNUSED_VARIABLE(aLogLevel); + OT_UNUSED_VARIABLE(aPlatModuleName); + OT_UNUSED_VARIABLE(aFormat); + OT_UNUSED_VARIABLE(aArgs); +#endif +} + void otLogCli(otLogLevel aLogLevel, const char *aFormat, ...) { #if OT_SHOULD_LOG && OPENTHREAD_CONFIG_LOG_CLI @@ -199,3 +232,10 @@ void otLogCli(otLogLevel aLogLevel, const char *aFormat, ...) #endif return; } + +otError otLogGenerateNextHexDumpLine(otLogHexDumpInfo *aInfo) +{ + AssertPointerIsNotNull(aInfo); + + return GenerateNextHexDumpLine(*aInfo); +} diff --git a/third_party/openthread/repo/src/core/api/message_api.cpp b/third_party/openthread/repo/src/core/api/message_api.cpp index eafc1d2c..f564e3ab 100644 --- a/third_party/openthread/repo/src/core/api/message_api.cpp +++ b/third_party/openthread/repo/src/core/api/message_api.cpp @@ -52,6 +52,23 @@ void otMessageSetOffset(otMessage *aMessage, uint16_t aOffset) { AsCoreType(aMes bool otMessageIsLinkSecurityEnabled(const otMessage *aMessage) { return AsCoreType(aMessage).IsLinkSecurityEnabled(); } +bool otMessageIsLoopbackToHostAllowed(const otMessage *aMessage) +{ + return AsCoreType(aMessage).IsLoopbackToHostAllowed(); +} + +void otMessageSetLoopbackToHostAllowed(otMessage *aMessage, bool aAllowLoopbackToHost) +{ + return AsCoreType(aMessage).SetLoopbackToHostAllowed(aAllowLoopbackToHost); +} + +otMessageOrigin otMessageGetOrigin(const otMessage *aMessage) { return MapEnum(AsCoreType(aMessage).GetOrigin()); } + +void otMessageSetOrigin(otMessage *aMessage, otMessageOrigin aOrigin) +{ + AsCoreType(aMessage).SetOrigin(MapEnum(aOrigin)); +} + void otMessageSetDirectTransmission(otMessage *aMessage, bool aEnabled) { if (aEnabled) diff --git a/third_party/openthread/repo/src/core/api/nat64_api.cpp b/third_party/openthread/repo/src/core/api/nat64_api.cpp index 7405b9d6..02aa785b 100644 --- a/third_party/openthread/repo/src/core/api/nat64_api.cpp +++ b/third_party/openthread/repo/src/core/api/nat64_api.cpp @@ -39,7 +39,7 @@ #include "border_router/routing_manager.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "net/ip4_types.hpp" #include "net/ip6_headers.hpp" #include "net/nat64_translator.hpp" diff --git a/third_party/openthread/repo/src/core/api/netdata_api.cpp b/third_party/openthread/repo/src/core/api/netdata_api.cpp index 28e06c7f..50fcd0ce 100644 --- a/third_party/openthread/repo/src/core/api/netdata_api.cpp +++ b/third_party/openthread/repo/src/core/api/netdata_api.cpp @@ -104,6 +104,11 @@ otError otNetDataGetNextLowpanContextInfo(otInstance *aInstance, AsCoreType(aContextInfo)); } +void otNetDataGetCommissioningDataset(otInstance *aInstance, otCommissioningDataset *aDataset) +{ + return AsCoreType(aInstance).Get().GetCommissioningDataset(AsCoreType(aDataset)); +} + uint8_t otNetDataGetVersion(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetLeaderData().GetDataVersion(NetworkData::kFullSet); diff --git a/third_party/openthread/repo/src/core/api/srp_server_api.cpp b/third_party/openthread/repo/src/core/api/srp_server_api.cpp index a6a3ca7c..4a0044b8 100644 --- a/third_party/openthread/repo/src/core/api/srp_server_api.cpp +++ b/third_party/openthread/repo/src/core/api/srp_server_api.cpp @@ -139,6 +139,11 @@ bool otSrpServerHostIsDeleted(const otSrpServerHost *aHost) { return AsCoreType( const char *otSrpServerHostGetFullName(const otSrpServerHost *aHost) { return AsCoreType(aHost).GetFullName(); } +bool otSrpServerHostMatchesFullName(const otSrpServerHost *aHost, const char *aFullName) +{ + return AsCoreType(aHost).Matches(aFullName); +} + const otIp6Address *otSrpServerHostGetAddresses(const otSrpServerHost *aHost, uint8_t *aAddressesNum) { return AsCoreType(aHost).GetAddresses(*aAddressesNum); @@ -154,30 +159,24 @@ uint32_t otSrpServerHostGetKeyLease(const otSrpServerHost *aHost) { return AsCor const otSrpServerService *otSrpServerHostGetNextService(const otSrpServerHost *aHost, const otSrpServerService *aService) { - return AsCoreType(aHost).FindNextService(AsCoreTypePtr(aService), Srp::Server::kFlagsBaseTypeServiceOnly); -} - -const otSrpServerService *otSrpServerHostFindNextService(const otSrpServerHost *aHost, - const otSrpServerService *aPrevService, - otSrpServerServiceFlags aFlags, - const char *aServiceName, - const char *aInstanceName) -{ - return AsCoreType(aHost).FindNextService(AsCoreTypePtr(aPrevService), aFlags, aServiceName, aInstanceName); + return AsCoreType(aHost).GetNextService(AsCoreTypePtr(aService)); } bool otSrpServerServiceIsDeleted(const otSrpServerService *aService) { return AsCoreType(aService).IsDeleted(); } -bool otSrpServerServiceIsSubType(const otSrpServerService *aService) { return AsCoreType(aService).IsSubType(); } - -const char *otSrpServerServiceGetFullName(const otSrpServerService *aService) +const char *otSrpServerServiceGetInstanceName(const otSrpServerService *aService) { return AsCoreType(aService).GetInstanceName(); } -const char *otSrpServerServiceGetInstanceName(const otSrpServerService *aService) +bool otSrpServerServiceMatchesInstanceName(const otSrpServerService *aService, const char *aInstanceName) { - return AsCoreType(aService).GetInstanceName(); + return AsCoreType(aService).MatchesInstanceName(aInstanceName); +} + +const char *otSrpServerServiceGetInstanceLabel(const otSrpServerService *aService) +{ + return AsCoreType(aService).GetInstanceLabel(); } const char *otSrpServerServiceGetServiceName(const otSrpServerService *aService) @@ -185,9 +184,29 @@ const char *otSrpServerServiceGetServiceName(const otSrpServerService *aService) return AsCoreType(aService).GetServiceName(); } -otError otSrpServerServiceGetServiceSubTypeLabel(const otSrpServerService *aService, char *aLabel, uint8_t aMaxSize) +bool otSrpServerServiceMatchesServiceName(const otSrpServerService *aService, const char *aServiceName) +{ + return AsCoreType(aService).MatchesServiceName(aServiceName); +} + +uint16_t otSrpServerServiceGetNumberOfSubTypes(const otSrpServerService *aService) +{ + return AsCoreType(aService).GetNumberOfSubTypes(); +} + +const char *otSrpServerServiceGetSubTypeServiceNameAt(const otSrpServerService *aService, uint16_t aIndex) +{ + return AsCoreType(aService).GetSubTypeServiceNameAt(aIndex); +} + +bool otSrpServerServiceHasSubTypeServiceName(const otSrpServerService *aService, const char *aSubTypeServiceName) +{ + return AsCoreType(aService).HasSubTypeServiceName(aSubTypeServiceName); +} + +otError otSrpServerParseSubTypeServiceName(const char *aSubTypeServiceName, char *aLabel, uint8_t aLabelSize) { - return AsCoreType(aService).GetServiceSubTypeLabel(aLabel, aMaxSize); + return Srp::Server::Service::ParseSubTypeServiceName(aSubTypeServiceName, aLabel, aLabelSize); } uint16_t otSrpServerServiceGetPort(const otSrpServerService *aService) { return AsCoreType(aService).GetPort(); } diff --git a/third_party/openthread/repo/src/core/api/thread_ftd_api.cpp b/third_party/openthread/repo/src/core/api/thread_ftd_api.cpp index 8b8504bb..1b19693c 100644 --- a/third_party/openthread/repo/src/core/api/thread_ftd_api.cpp +++ b/third_party/openthread/repo/src/core/api/thread_ftd_api.cpp @@ -79,7 +79,7 @@ otError otThreadSetPreferredRouterId(otInstance *aInstance, uint8_t aRouterId) return AsCoreType(aInstance).Get().SetPreferredRouterId(aRouterId); } -#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_3_1) +#if OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE const otDeviceProperties *otThreadGetDeviceProperties(otInstance *aInstance) { return &AsCoreType(aInstance).Get().GetDeviceProperties(); @@ -222,7 +222,7 @@ uint8_t otThreadGetRouterSelectionJitter(otInstance *aInstance) void otThreadSetRouterSelectionJitter(otInstance *aInstance, uint8_t aRouterJitter) { - IgnoreError(AsCoreType(aInstance).Get().SetRouterSelectionJitter(aRouterJitter)); + AsCoreType(aInstance).Get().SetRouterSelectionJitter(aRouterJitter); } otError otThreadGetChildInfoById(otInstance *aInstance, uint16_t aChildId, otChildInfo *aChildInfo) @@ -357,6 +357,7 @@ void otThreadSetDiscoveryRequestCallback(otInstance *aInsta } #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + void otThreadSendAddressNotification(otInstance *aInstance, otIp6Address *aDestination, otIp6Address *aTarget, @@ -386,9 +387,7 @@ void otThreadSetThreadVersionCheckEnabled(otInstance *aInstance, bool aEnabled) { AsCoreType(aInstance).Get().SetThreadVersionCheckEnabled(aEnabled); } -#endif -#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE void otThreadGetRouterIdRange(otInstance *aInstance, uint8_t *aMinRouterId, uint8_t *aMaxRouterId) { AssertPointerIsNotNull(aMinRouterId); @@ -401,7 +400,13 @@ otError otThreadSetRouterIdRange(otInstance *aInstance, uint8_t aMinRouterId, ui { return AsCoreType(aInstance).Get().SetRouterIdRange(aMinRouterId, aMaxRouterId); } -#endif + +uint32_t otThreadGetAdvertisementTrickleIntervalMax(otInstance *aInstance) +{ + return AsCoreType(aInstance).Get().GetAdvertisementTrickleIntervalMax(); +} + +#endif // OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE bool otThreadIsRouterIdAllocated(otInstance *aInstance, uint8_t aRouterId) { diff --git a/third_party/openthread/repo/src/core/api/trel_api.cpp b/third_party/openthread/repo/src/core/api/trel_api.cpp index 29c1563a..687c1169 100644 --- a/third_party/openthread/repo/src/core/api/trel_api.cpp +++ b/third_party/openthread/repo/src/core/api/trel_api.cpp @@ -39,7 +39,7 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" using namespace ot; diff --git a/third_party/openthread/repo/src/core/api/udp_api.cpp b/third_party/openthread/repo/src/core/api/udp_api.cpp index 16817b62..5141a50b 100644 --- a/third_party/openthread/repo/src/core/api/udp_api.cpp +++ b/third_party/openthread/repo/src/core/api/udp_api.cpp @@ -72,8 +72,14 @@ otError otUdpConnect(otInstance *aInstance, otUdpSocket *aSocket, const otSockAd otError otUdpSend(otInstance *aInstance, otUdpSocket *aSocket, otMessage *aMessage, const otMessageInfo *aMessageInfo) { - return AsCoreType(aInstance).Get().SendTo(AsCoreType(aSocket), AsCoreType(aMessage), - AsCoreType(aMessageInfo)); + otError error; + + VerifyOrExit(!AsCoreType(aMessage).IsOriginThreadNetif(), error = kErrorInvalidArgs); + + error = AsCoreType(aInstance).Get().SendTo(AsCoreType(aSocket), AsCoreType(aMessage), + AsCoreType(aMessageInfo)); +exit: + return error; } otUdpSocket *otUdpGetSockets(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetUdpSockets(); } @@ -116,8 +122,13 @@ otError otUdpRemoveReceiver(otInstance *aInstance, otUdpReceiver *aUdpReceiver) otError otUdpSendDatagram(otInstance *aInstance, otMessage *aMessage, otMessageInfo *aMessageInfo) { - return AsCoreType(aInstance).Get().SendDatagram(AsCoreType(aMessage), AsCoreType(aMessageInfo), - Ip6::kProtoUdp); + otError error; + + VerifyOrExit(!AsCoreType(aMessage).IsOriginThreadNetif(), error = kErrorInvalidArgs); + + return AsCoreType(aInstance).Get().SendDatagram(AsCoreType(aMessage), AsCoreType(aMessageInfo)); +exit: + return error; } bool otUdpIsPortInUse(otInstance *aInstance, uint16_t port) diff --git a/third_party/openthread/repo/src/core/backbone_router/bbr_leader.cpp b/third_party/openthread/repo/src/core/backbone_router/bbr_leader.cpp index efced1bb..5b605ac5 100644 --- a/third_party/openthread/repo/src/core/backbone_router/bbr_leader.cpp +++ b/third_party/openthread/repo/src/core/backbone_router/bbr_leader.cpp @@ -35,8 +35,8 @@ #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) -#include "common/instance.hpp" #include "common/locator_getters.hpp" +#include "instance/instance.hpp" namespace ot { namespace BackboneRouter { diff --git a/third_party/openthread/repo/src/core/backbone_router/bbr_local.cpp b/third_party/openthread/repo/src/core/backbone_router/bbr_local.cpp index 430ac906..ffdc4757 100644 --- a/third_party/openthread/repo/src/core/backbone_router/bbr_local.cpp +++ b/third_party/openthread/repo/src/core/backbone_router/bbr_local.cpp @@ -36,10 +36,10 @@ #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "thread/mle_types.hpp" #include "thread/thread_netif.hpp" @@ -54,6 +54,7 @@ Local::Local(Instance &aInstance) , mState(kStateDisabled) , mMlrTimeout(kDefaultMlrTimeout) , mReregistrationDelay(kDefaultRegistrationDelay) + , mRegistrationTimeout(0) , mSequenceNumber(Random::NonCrypto::GetUint8() % 127) , mRegistrationJitter(kDefaultRegistrationJitter) , mIsServiceAdded(false) @@ -61,7 +62,7 @@ Local::Local(Instance &aInstance) mDomainPrefixConfig.GetPrefix().SetLength(0); // Primary Backbone Router Aloc - mBackboneRouterPrimaryAloc.InitAsThreadOriginRealmLocalScope(); + mBackboneRouterPrimaryAloc.InitAsThreadOriginMeshLocal(); mBackboneRouterPrimaryAloc.GetAddress().GetIid().SetToLocator(Mle::kAloc16BackboneRouterPrimary); // All Network Backbone Routers Multicast Address. @@ -87,7 +88,7 @@ void Local::SetEnabled(bool aEnable) { SetState(kStateSecondary); AddDomainPrefixToNetworkData(); - IgnoreError(AddService()); + IgnoreError(AddService(kDecideBasedOnState)); } else { @@ -163,7 +164,7 @@ Error Local::SetConfig(const Config &aConfig) { Get().Signal(kEventThreadBackboneRouterLocalChanged); - IgnoreError(AddService()); + IgnoreError(AddService(kDecideBasedOnState)); } exit: @@ -171,18 +172,22 @@ Error Local::SetConfig(const Config &aConfig) return error; } -Error Local::AddService(bool aForce) +Error Local::AddService(RegisterMode aMode) { Error error = kErrorInvalidState; NetworkData::Service::BackboneRouter::ServerData serverData; VerifyOrExit(mState != kStateDisabled && Get().IsAttached()); - VerifyOrExit(aForce /* if register by force */ || - !Get().HasPrimary() /* if no available Backbone Router service */ || - Get().GetServer16() == Get().GetRloc16() - /* If the device itself should be BBR. */ - ); + switch (aMode) + { + case kDecideBasedOnState: + VerifyOrExit(!Get().HasPrimary() || + Get().GetServer16() == Get().GetRloc16()); + break; + case kForceRegistration: + break; + } serverData.SetSequenceNumber(mSequenceNumber); serverData.SetReregistrationDelay(mReregistrationDelay); @@ -248,16 +253,15 @@ void Local::HandleBackboneRouterPrimaryUpdate(Leader::State aState, const Config // Wait some jitter before trying to Register. if (aConfig.mServer16 == Mac::kShortAddrInvalid) { - uint8_t delay = 1; + mRegistrationTimeout = 1; if (!Get().IsLeader()) { - delay += Random::NonCrypto::GetUint8InRange(0, mRegistrationJitter < 255 ? mRegistrationJitter + 1 - : mRegistrationJitter); + mRegistrationTimeout += + Random::NonCrypto::GetUint16InRange(0, static_cast(mRegistrationJitter) + 1); } - // Here uses the timer resource in Mle. - Get().SetBackboneRouterRegistrationDelay(delay); + Get().RegisterReceiver(TimeTicker::kBbrLocal); } else if (aConfig.mServer16 != Get().GetRloc16()) { @@ -272,10 +276,7 @@ void Local::HandleBackboneRouterPrimaryUpdate(Leader::State aState, const Config mMlrTimeout = aConfig.mMlrTimeout; SequenceNumberIncrease(); Get().Signal(kEventThreadBackboneRouterLocalChanged); - if (AddService(true /* Force registration to refresh and restore Primary state */) == kErrorNone) - { - Get().HandleServerDataUpdated(); - } + IgnoreError(AddService(kForceRegistration)); } else { @@ -286,6 +287,30 @@ void Local::HandleBackboneRouterPrimaryUpdate(Leader::State aState, const Config return; } +void Local::HandleTimeTick(void) +{ + // Delay registration while router role transition is pending + // (i.e., device may soon switch from REED to router role). + + VerifyOrExit(!Get().IsRouterRoleTransitionPending()); + + if (mRegistrationTimeout > 0) + { + mRegistrationTimeout--; + + if (mRegistrationTimeout == 0) + { + IgnoreError(AddService(kDecideBasedOnState)); + } + } + +exit: + if (mRegistrationTimeout == 0) + { + Get().UnregisterReceiver(TimeTicker::kBbrLocal); + } +} + Error Local::GetDomainPrefix(NetworkData::OnMeshPrefixConfig &aConfig) { Error error = kErrorNone; @@ -339,7 +364,7 @@ Error Local::SetDomainPrefix(const NetworkData::OnMeshPrefixConfig &aConfig) return error; } -void Local::ApplyMeshLocalPrefix(void) +void Local::ApplyNewMeshLocalPrefix(void) { VerifyOrExit(IsEnabled()); @@ -347,13 +372,6 @@ void Local::ApplyMeshLocalPrefix(void) mAllNetworkBackboneRouters.SetMulticastNetworkPrefix(Get().GetMeshLocalPrefix()); Get().SubscribeMulticast(mAllNetworkBackboneRouters); - if (IsPrimary()) - { - Get().RemoveUnicastAddress(mBackboneRouterPrimaryAloc); - mBackboneRouterPrimaryAloc.GetAddress().SetPrefix(Get().GetMeshLocalPrefix()); - Get().AddUnicastAddress(mBackboneRouterPrimaryAloc); - } - exit: return; } diff --git a/third_party/openthread/repo/src/core/backbone_router/bbr_local.hpp b/third_party/openthread/repo/src/core/backbone_router/bbr_local.hpp index b2ba94e3..90b2d894 100644 --- a/third_party/openthread/repo/src/core/backbone_router/bbr_local.hpp +++ b/third_party/openthread/repo/src/core/backbone_router/bbr_local.hpp @@ -59,6 +59,7 @@ #include "common/locator.hpp" #include "common/log.hpp" #include "common/non_copyable.hpp" +#include "common/time_ticker.hpp" #include "net/netif.hpp" #include "thread/network_data.hpp" @@ -72,6 +73,8 @@ namespace BackboneRouter { */ class Local : public InstanceLocator, private NonCopyable { + friend class ot::TimeTicker; + public: /** * Represents Backbone Router state. @@ -84,6 +87,16 @@ class Local : public InstanceLocator, private NonCopyable kStatePrimary = OT_BACKBONE_ROUTER_STATE_PRIMARY, ///< The Primary Backbone Router. }; + /** + * Represents registration mode used as input to `AddService()` method. + * + */ + enum RegisterMode : uint8_t + { + kDecideBasedOnState, ///< Decide based on current state. + kForceRegistration, ///< Force registration regardless of current state. + }; + /** * Initializes the local Backbone Router. * @@ -137,16 +150,14 @@ class Local : public InstanceLocator, private NonCopyable /** * Registers Backbone Router Dataset to Leader. * - * @param[in] aForce True to force registration regardless of current state. - * False to decide based on current state. - * + * @param[in] aMode The registration mode to use (decide based on current state or force registration). * * @retval kErrorNone Successfully added the Service entry. * @retval kErrorInvalidState Not in the ready state to register. * @retval kErrorNoBufs Insufficient space to add the Service entry. * */ - Error AddService(bool aForce = false); + Error AddService(RegisterMode aMode); /** * Indicates whether or not the Backbone Router is Primary. @@ -245,7 +256,7 @@ class Local : public InstanceLocator, private NonCopyable * Applies the Mesh Local Prefix. * */ - void ApplyMeshLocalPrefix(void); + void ApplyNewMeshLocalPrefix(void); /** * Updates the subscription of All Domain Backbone Routers Multicast Address. @@ -270,6 +281,7 @@ class Local : public InstanceLocator, private NonCopyable private: void SetState(State aState); void RemoveService(void); + void HandleTimeTick(void); void AddDomainPrefixToNetworkData(void); void RemoveDomainPrefixFromNetworkData(void); void SequenceNumberIncrease(void); @@ -284,6 +296,7 @@ class Local : public InstanceLocator, private NonCopyable State mState; uint32_t mMlrTimeout; uint16_t mReregistrationDelay; + uint16_t mRegistrationTimeout; uint8_t mSequenceNumber; uint8_t mRegistrationJitter; diff --git a/third_party/openthread/repo/src/core/backbone_router/bbr_manager.cpp b/third_party/openthread/repo/src/core/backbone_router/bbr_manager.cpp index 09c1c765..551cfa22 100644 --- a/third_party/openthread/repo/src/core/backbone_router/bbr_manager.cpp +++ b/third_party/openthread/repo/src/core/backbone_router/bbr_manager.cpp @@ -37,11 +37,11 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/num_utils.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "thread/mle_types.hpp" #include "thread/thread_netif.hpp" #include "thread/thread_tlvs.hpp" @@ -176,11 +176,10 @@ void Manager::HandleMulticastListenerRegistration(const Coap::Message &aMessage, if (Tlv::Find(aMessage, commissionerSessionId) == kErrorNone) { - const MeshCoP::CommissionerSessionIdTlv *commissionerSessionIdTlv = As( - Get().GetCommissioningDataSubTlv(MeshCoP::Tlv::kCommissionerSessionId)); + uint16_t localSessionId; - VerifyOrExit(commissionerSessionIdTlv != nullptr && - commissionerSessionIdTlv->GetCommissionerSessionId() == commissionerSessionId, + VerifyOrExit((Get().FindCommissioningSessionId(localSessionId) == kErrorNone) && + (localSessionId == commissionerSessionId), status = ThreadStatusTlv::kMlrGeneralFailure); hasCommissionerSessionIdTlv = true; diff --git a/third_party/openthread/repo/src/core/backbone_router/multicast_listeners_table.cpp b/third_party/openthread/repo/src/core/backbone_router/multicast_listeners_table.cpp index 4f477cde..22e4e320 100644 --- a/third_party/openthread/repo/src/core/backbone_router/multicast_listeners_table.cpp +++ b/third_party/openthread/repo/src/core/backbone_router/multicast_listeners_table.cpp @@ -37,10 +37,10 @@ #include "common/array.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "thread/mle_types.hpp" #include "thread/thread_netif.hpp" #include "thread/uri_paths.hpp" diff --git a/third_party/openthread/repo/src/core/border_router/infra_if.cpp b/third_party/openthread/repo/src/core/border_router/infra_if.cpp index acc3049a..07b5dc50 100644 --- a/third_party/openthread/repo/src/core/border_router/infra_if.cpp +++ b/third_party/openthread/repo/src/core/border_router/infra_if.cpp @@ -37,9 +37,9 @@ #include "border_router/routing_manager.hpp" #include "common/as_core_type.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/logging.hpp" +#include "instance/instance.hpp" #include "net/icmp6.hpp" namespace ot { @@ -60,7 +60,6 @@ Error InfraIf::Init(uint32_t aIfIndex) Error error = kErrorNone; VerifyOrExit(!mInitialized, error = kErrorInvalidState); - VerifyOrExit(aIfIndex > 0, error = kErrorInvalidArgs); mIfIndex = aIfIndex; mInitialized = true; @@ -194,4 +193,17 @@ extern "C" void otPlatInfraIfDiscoverNat64PrefixDone(otInstance *aInstanc } // namespace BorderRouter } // namespace ot +//--------------------------------------------------------------------------------------------------------------------- + +#if OPENTHREAD_CONFIG_BORDER_ROUTING_MOCK_PLAT_APIS_ENABLE +OT_TOOL_WEAK bool otPlatInfraIfHasAddress(uint32_t, const otIp6Address *) { return false; } + +OT_TOOL_WEAK otError otPlatInfraIfSendIcmp6Nd(uint32_t, const otIp6Address *, const uint8_t *, uint16_t) +{ + return OT_ERROR_FAILED; +} + +OT_TOOL_WEAK otError otPlatInfraIfDiscoverNat64Prefix(uint32_t) { return OT_ERROR_FAILED; } +#endif + #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE diff --git a/third_party/openthread/repo/src/core/border_router/infra_if.hpp b/third_party/openthread/repo/src/core/border_router/infra_if.hpp index b23bb26d..872d897e 100644 --- a/third_party/openthread/repo/src/core/border_router/infra_if.hpp +++ b/third_party/openthread/repo/src/core/border_router/infra_if.hpp @@ -114,6 +114,14 @@ class InfraIf : public InstanceLocator */ uint32_t GetIfIndex(void) const { return mIfIndex; } + /** + * Sets the infrastructure interface index. + * + * @param[in] aIfIndex The infrastructure interface index. + * + */ + void SetIfIndex(uint32_t aIfIndex) { mIfIndex = aIfIndex; } + /** * Indicates whether or not the infra interface has the given IPv6 address assigned. * diff --git a/third_party/openthread/repo/src/core/border_router/routing_manager.cpp b/third_party/openthread/repo/src/core/border_router/routing_manager.cpp index 599fb58e..2b073b4b 100644 --- a/third_party/openthread/repo/src/core/border_router/routing_manager.cpp +++ b/third_party/openthread/repo/src/core/border_router/routing_manager.cpp @@ -44,13 +44,13 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/num_utils.hpp" #include "common/numeric_limits.hpp" #include "common/random.hpp" #include "common/settings.hpp" +#include "instance/instance.hpp" #include "meshcop/extended_panid.hpp" #include "net/ip6.hpp" #include "net/nat64_translator.hpp" @@ -94,16 +94,24 @@ Error RoutingManager::Init(uint32_t aInfraIfIndex, bool aInfraIfIsRunning) { Error error; - LogInfo("Initializing - InfraIfIndex:%lu", ToUlong(aInfraIfIndex)); + VerifyOrExit(GetState() == kStateUninitialized || GetState() == kStateDisabled, error = kErrorInvalidState); - SuccessOrExit(error = mInfraIf.Init(aInfraIfIndex)); - - SuccessOrExit(error = LoadOrGenerateRandomBrUlaPrefix()); - mOmrPrefixManager.Init(mBrUlaPrefix); + if (!mInfraIf.IsInitialized()) + { + LogInfo("Initializing - InfraIfIndex:%lu", ToUlong(aInfraIfIndex)); + SuccessOrExit(error = mInfraIf.Init(aInfraIfIndex)); + SuccessOrExit(error = LoadOrGenerateRandomBrUlaPrefix()); + mOmrPrefixManager.Init(mBrUlaPrefix); #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE - mNat64PrefixManager.GenerateLocalPrefix(mBrUlaPrefix); + mNat64PrefixManager.GenerateLocalPrefix(mBrUlaPrefix); #endif - mOnLinkPrefixManager.Init(); + mOnLinkPrefixManager.Init(); + } + else if (aInfraIfIndex != mInfraIf.GetIfIndex()) + { + LogInfo("Reinitializing - InfraIfIndex:%lu -> %lu", ToUlong(mInfraIf.GetIfIndex()), ToUlong(aInfraIfIndex)); + mInfraIf.SetIfIndex(aInfraIfIndex); + } error = mInfraIf.HandleStateChanged(mInfraIf.GetIfIndex(), aInfraIfIsRunning); @@ -585,6 +593,7 @@ void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode) // RA message max length is derived to accommodate: // // - The RA header. + // - One RA Flags Extensions Option (with stub router flag). // - One PIO for current local on-link prefix. // - At most `kMaxOldPrefixes` for old deprecating on-link prefixes. // - At most twice `kMaxOnMeshPrefixes` RIO for on-mesh prefixes. @@ -592,8 +601,8 @@ void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode) // previous prefixes while adding new ones. static constexpr uint16_t kMaxRaLength = - sizeof(Ip6::Nd::RouterAdvertMessage::Header) + sizeof(Ip6::Nd::PrefixInfoOption) + - sizeof(Ip6::Nd::PrefixInfoOption) * OnLinkPrefixManager::kMaxOldPrefixes + + sizeof(Ip6::Nd::RouterAdvertMessage::Header) + sizeof(Ip6::Nd::RaFlagsExtOption) + + sizeof(Ip6::Nd::PrefixInfoOption) + sizeof(Ip6::Nd::PrefixInfoOption) * OnLinkPrefixManager::kMaxOldPrefixes + 2 * kMaxOnMeshPrefixes * (sizeof(Ip6::Nd::RouteInfoOption) + sizeof(Ip6::Prefix)); uint8_t buffer[kMaxRaLength]; @@ -603,6 +612,11 @@ void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode) LogInfo("Preparing RA"); +#if OPENTHREAD_CONFIG_BORDER_ROUTING_STUB_ROUTER_FLAG_IN_EMITTED_RA_ENABLE + SuccessOrAssert(raMsg.AppendFlagsExtensionOption(/* aStubRouterFlag */ true)); + LogInfo("- FlagsExt - StubRouter:1"); +#endif + // Append PIO for local on-link prefix if is either being // advertised or deprecated and for old prefix if is being // deprecated. @@ -1175,7 +1189,7 @@ void RoutingManager::DiscoveredPrefixTable::ProcessRouterAdvertMessage(const Ip6 if (router == nullptr) { - router = mRouters.PushBack(); + router = AllocateRouter(); if (router == nullptr) { @@ -1183,8 +1197,10 @@ void RoutingManager::DiscoveredPrefixTable::ProcessRouterAdvertMessage(const Ip6 ExitNow(); } + router->Clear(); router->mAddress = aSrcAddress; - router->mEntries.Clear(); + + mRouters.Push(*router); } // RA message can indicate router provides default route in the RA @@ -1193,7 +1209,7 @@ void RoutingManager::DiscoveredPrefixTable::ProcessRouterAdvertMessage(const Ip6 // in a `::/0` RIO override the preference and lifetime values in // the RA header (per RFC 4191 section 3.1). - ProcessDefaultRoute(aRaMessage.GetHeader(), *router); + ProcessRaHeader(aRaMessage.GetHeader(), *router); for (const Ip6::Nd::Option &option : aRaMessage) { @@ -1207,6 +1223,10 @@ void RoutingManager::DiscoveredPrefixTable::ProcessRouterAdvertMessage(const Ip6 ProcessRouteInfoOption(static_cast(option), *router); break; + case Ip6::Nd::Option::kTypeRaFlagsExtension: + ProcessRaFlagsExtOption(static_cast(option), *router); + break; + default: break; } @@ -1220,12 +1240,16 @@ void RoutingManager::DiscoveredPrefixTable::ProcessRouterAdvertMessage(const Ip6 return; } -void RoutingManager::DiscoveredPrefixTable::ProcessDefaultRoute(const Ip6::Nd::RouterAdvertMessage::Header &aRaHeader, - Router &aRouter) +void RoutingManager::DiscoveredPrefixTable::ProcessRaHeader(const Ip6::Nd::RouterAdvertMessage::Header &aRaHeader, + Router &aRouter) { Entry *entry; Ip6::Prefix prefix; + aRouter.mManagedAddressConfigFlag = aRaHeader.IsManagedAddressConfigFlagSet(); + aRouter.mOtherConfigFlag = aRaHeader.IsOtherConfigFlagSet(); + LogInfo("- RA Header - flags - M:%u O:%u", aRouter.mManagedAddressConfigFlag, aRouter.mOtherConfigFlag); + prefix.Clear(); entry = aRouter.mEntries.FindMatching(Entry::Matcher(prefix, Entry::kTypeRoute)); @@ -1348,6 +1372,18 @@ void RoutingManager::DiscoveredPrefixTable::ProcessRouteInfoOption(const Ip6::Nd return; } +void RoutingManager::DiscoveredPrefixTable::ProcessRaFlagsExtOption(const Ip6::Nd::RaFlagsExtOption &aRaFlagsOption, + Router &aRouter) +{ + VerifyOrExit(aRaFlagsOption.IsValid()); + aRouter.mStubRouterFlag = aRaFlagsOption.IsStubRouterFlagSet(); + + LogInfo("- FlagsExt - StubRouter:%u", aRouter.mStubRouterFlag); + +exit: + return; +} + bool RoutingManager::DiscoveredPrefixTable::Contains(const Entry::Checker &aChecker) const { bool contains = false; @@ -1443,13 +1479,12 @@ void RoutingManager::DiscoveredPrefixTable::RemoveAllEntries(void) for (Router &router : mRouters) { - Entry *entry; - - while ((entry = router.mEntries.Pop()) != nullptr) + if (!router.mEntries.IsEmpty()) { - FreeEntry(*entry); SignalTableChanged(); } + + FreeEntries(router.mEntries); } RemoveRoutersWithNoEntries(); @@ -1551,13 +1586,27 @@ TimeMilli RoutingManager::DiscoveredPrefixTable::CalculateNextStaleTime(TimeMill void RoutingManager::DiscoveredPrefixTable::RemoveRoutersWithNoEntries(void) { - mRouters.RemoveAllMatching(Router::kContainsNoEntries); + LinkedList routersToFree; + + mRouters.RemoveAllMatching(Router::kContainsNoEntries, routersToFree); + FreeRouters(routersToFree); +} + +void RoutingManager::DiscoveredPrefixTable::FreeRouters(LinkedList &aRouters) +{ + // Frees all routers in the given list `aRouters` + + Router *router; + + while ((router = aRouters.Pop()) != nullptr) + { + FreeRouter(*router); + } } void RoutingManager::DiscoveredPrefixTable::FreeEntries(LinkedList &aEntries) { - // Frees all entries in the given list `aEntries` (put them back - // in the entry pool). + // Frees all entries in the given list `aEntries`. Entry *entry; @@ -1740,8 +1789,8 @@ void RoutingManager::DiscoveredPrefixTable::InitIterator(PrefixTableIterator &aI Iterator &iterator = static_cast(aIterator); iterator.SetInitTime(); - iterator.SetRouter(mRouters.Front()); - iterator.SetEntry(mRouters.IsEmpty() ? nullptr : mRouters[0].mEntries.GetHead()); + iterator.SetRouter(mRouters.GetHead()); + iterator.SetEntry(mRouters.IsEmpty() ? nullptr : mRouters.GetHead()->mEntries.GetHead()); } Error RoutingManager::DiscoveredPrefixTable::GetNextEntry(PrefixTableIterator &aIterator, @@ -1767,15 +1816,12 @@ Error RoutingManager::DiscoveredPrefixTable::GetNextEntry(PrefixTableIterator &a if (iterator.GetEntry() == nullptr) { - if (iterator.GetRouter() != mRouters.Back()) + iterator.SetRouter(iterator.GetRouter()->GetNext()); + + if (iterator.GetRouter() != nullptr) { - iterator.SetRouter(iterator.GetRouter() + 1); iterator.SetEntry(iterator.GetRouter()->mEntries.GetHead()); } - else - { - iterator.SetRouter(nullptr); - } } exit: @@ -2166,6 +2212,24 @@ RoutingManager::OnLinkPrefixManager::OnLinkPrefixManager(Instance &aInstance) mOldLocalPrefixes.Clear(); } +void RoutingManager::OnLinkPrefixManager::SetState(State aState) +{ + VerifyOrExit(mState != aState); + + LogInfo("Local on-link prefix state: %s -> %s (%s)", StateToString(mState), StateToString(aState), + mLocalPrefix.ToString().AsCString()); + mState = aState; + + // Mark the Advertising PIO (AP) flag in the published route, when + // the local on-link prefix is being published, advertised, or + // deprecated. + + Get().mRoutePublisher.UpdateAdvPioFlags(aState != kIdle); + +exit: + return; +} + void RoutingManager::OnLinkPrefixManager::Init(void) { TimeMilli now = TimerMilli::GetNow(); @@ -2249,19 +2313,19 @@ void RoutingManager::OnLinkPrefixManager::GenerateLocalPrefix(void) LogNote("Local on-link prefix: %s", mLocalPrefix.ToString().AsCString()); // Check if the new local prefix happens to be in `mOldLocalPrefixes` array. - // If so, we remove it from the array and set `mState` accordingly. + // If so, we remove it from the array and update the state accordingly. entry = mOldLocalPrefixes.FindMatching(mLocalPrefix); if (entry != nullptr) { - mState = kDeprecating; + SetState(kDeprecating); mExpireTime = entry->mExpireTime; mOldLocalPrefixes.Remove(*entry); } else { - mState = kIdle; + SetState(kIdle); } exit: @@ -2274,7 +2338,7 @@ void RoutingManager::OnLinkPrefixManager::Stop(void) { mFavoredDiscoveredPrefix.Clear(); - switch (mState) + switch (GetState()) { case kIdle: break; @@ -2282,7 +2346,7 @@ void RoutingManager::OnLinkPrefixManager::Stop(void) case kPublishing: case kAdvertising: case kDeprecating: - mState = kDeprecating; + SetState(kDeprecating); break; } } @@ -2372,7 +2436,7 @@ void RoutingManager::OnLinkPrefixManager::PublishAndAdvertise(void) // Start publishing and advertising the local on-link prefix if // not already. - switch (mState) + switch (GetState()) { case kIdle: case kDeprecating: @@ -2383,11 +2447,9 @@ void RoutingManager::OnLinkPrefixManager::PublishAndAdvertise(void) ExitNow(); } - mState = kPublishing; + SetState(kPublishing); ResetExpireTime(TimerMilli::GetNow()); - LogInfo("Publishing route for local on-link prefix %s", mLocalPrefix.ToString().AsCString()); - // We wait for the ULA `fc00::/7` route or a sub-prefix of it (e.g., // default route) to be added in Network Data before // starting to advertise the local on-link prefix in RAs. @@ -2397,7 +2459,7 @@ void RoutingManager::OnLinkPrefixManager::PublishAndAdvertise(void) if (Get().NetworkDataContainsUlaRoute()) { - EnterAdvertisingState(); + SetState(kAdvertising); } exit: @@ -2413,12 +2475,11 @@ void RoutingManager::OnLinkPrefixManager::Deprecate(void) // with zero preferred lifetime and the remaining valid lifetime // until the timer expires. - switch (mState) + switch (GetState()) { case kPublishing: case kAdvertising: - mState = kDeprecating; - LogInfo("Deprecating local on-link prefix %s", mLocalPrefix.ToString().AsCString()); + SetState(kDeprecating); break; case kIdle: @@ -2434,7 +2495,7 @@ bool RoutingManager::OnLinkPrefixManager::ShouldPublishUlaRoute(void) const // or `kDeprecating` states, or if there is at least one old local // prefix being deprecated. - return (mState != kIdle) || !mOldLocalPrefixes.IsEmpty(); + return (GetState() != kIdle) || !mOldLocalPrefixes.IsEmpty(); } void RoutingManager::OnLinkPrefixManager::ResetExpireTime(TimeMilli aNow) @@ -2444,15 +2505,9 @@ void RoutingManager::OnLinkPrefixManager::ResetExpireTime(TimeMilli aNow) SavePrefix(mLocalPrefix, mExpireTime); } -void RoutingManager::OnLinkPrefixManager::EnterAdvertisingState(void) -{ - mState = kAdvertising; - LogInfo("Advertising local on-link prefix %s", mLocalPrefix.ToString().AsCString()); -} - bool RoutingManager::OnLinkPrefixManager::IsPublishingOrAdvertising(void) const { - return (mState == kPublishing) || (mState == kAdvertising); + return (GetState() == kPublishing) || (GetState() == kAdvertising); } void RoutingManager::OnLinkPrefixManager::AppendAsPiosTo(Ip6::Nd::RouterAdvertMessage &aRaMessage) @@ -2474,7 +2529,7 @@ void RoutingManager::OnLinkPrefixManager::AppendCurPrefix(Ip6::Nd::RouterAdvertM uint32_t preferredLifetime = kDefaultOnLinkPrefixLifetime; TimeMilli now = TimerMilli::GetNow(); - switch (mState) + switch (GetState()) { case kAdvertising: ResetExpireTime(now); @@ -2520,11 +2575,11 @@ void RoutingManager::OnLinkPrefixManager::AppendOldPrefixes(Ip6::Nd::RouterAdver void RoutingManager::OnLinkPrefixManager::HandleNetDataChange(void) { - VerifyOrExit(mState == kPublishing); + VerifyOrExit(GetState() == kPublishing); if (Get().NetworkDataContainsUlaRoute()) { - EnterAdvertisingState(); + SetState(kAdvertising); Get().ScheduleRoutingPolicyEvaluation(kAfterRandomDelay); } @@ -2541,7 +2596,7 @@ void RoutingManager::OnLinkPrefixManager::HandleExtPanIdChange(void) // so to allow Thread nodes to continue to communicate with `InfraIf` // device using addresses based on this prefix. - uint16_t oldState = mState; + uint16_t oldState = GetState(); Ip6::Prefix oldPrefix = mLocalPrefix; GenerateLocalPrefix(); @@ -2630,7 +2685,7 @@ void RoutingManager::OnLinkPrefixManager::HandleTimer(void) TimeMilli nextExpireTime = now.GetDistantFuture(); Array expiredPrefixes; - switch (mState) + switch (GetState()) { case kIdle: break; @@ -2639,9 +2694,8 @@ void RoutingManager::OnLinkPrefixManager::HandleTimer(void) case kDeprecating: if (now >= mExpireTime) { - LogInfo("Removing expired local on-link prefix %s", mLocalPrefix.ToString().AsCString()); IgnoreError(Get().RemoveBrOnLinkPrefix(mLocalPrefix)); - mState = kIdle; + SetState(kIdle); } else { @@ -2677,6 +2731,23 @@ void RoutingManager::OnLinkPrefixManager::HandleTimer(void) Get().mRoutePublisher.Evaluate(); } +const char *RoutingManager::OnLinkPrefixManager::StateToString(State aState) +{ + static const char *const kStateStrings[] = { + "Removed", // (0) kIdle + "Publishing", // (1) kPublishing + "Advertising", // (2) kAdvertising + "Deprecating", // (3) kDeprecating + }; + + static_assert(0 == kIdle, "kIdle value is incorrect"); + static_assert(1 == kPublishing, "kPublishing value is incorrect"); + static_assert(2 == kAdvertising, "kAdvertising value is incorrect"); + static_assert(3 == kDeprecating, "kDeprecating value is incorrect"); + + return kStateStrings[aState]; +} + //--------------------------------------------------------------------------------------------------------------------- // OnMeshPrefixArray @@ -2726,6 +2797,7 @@ RoutingManager::RoutePublisher::RoutePublisher(Instance &aInstance) , mState(kDoNotPublish) , mPreference(NetworkData::kRoutePreferenceMedium) , mUserSetPreference(false) + , mAdvPioFlag(false) , mTimer(aInstance) { } @@ -2780,7 +2852,8 @@ void RoutingManager::RoutePublisher::UpdatePublishedRoute(State aNewState) { // Updates the published route entry in Network Data, transitioning // from current `mState` to new `aNewState`. This method can be used - // when there is no change to `mState` but a change to `mPreference`. + // when there is no change to `mState` but a change to `mPreference` + // or `mAdvPioFlag`. Ip6::Prefix oldPrefix; NetworkData::ExternalRouteConfig routeConfig; @@ -2796,6 +2869,7 @@ void RoutingManager::RoutePublisher::UpdatePublishedRoute(State aNewState) routeConfig.Clear(); routeConfig.mPreference = mPreference; + routeConfig.mAdvPio = mAdvPioFlag; routeConfig.mStable = true; DeterminePrefixFor(aNewState, routeConfig.GetPrefix()); @@ -2836,6 +2910,16 @@ void RoutingManager::RoutePublisher::Unpublish(void) return; } +void RoutingManager::RoutePublisher::UpdateAdvPioFlags(bool aAdvPioFlag) +{ + VerifyOrExit(mAdvPioFlag != aAdvPioFlag); + mAdvPioFlag = aAdvPioFlag; + UpdatePublishedRoute(mState); + +exit: + return; +} + void RoutingManager::RoutePublisher::SetPreference(RoutePreference aPreference) { LogInfo("User explicitly set published route preference to %s", RoutePreferenceToString(aPreference)); diff --git a/third_party/openthread/repo/src/core/border_router/routing_manager.hpp b/third_party/openthread/repo/src/core/border_router/routing_manager.hpp index f8eab50f..c7886293 100644 --- a/third_party/openthread/repo/src/core/border_router/routing_manager.hpp +++ b/third_party/openthread/repo/src/core/border_router/routing_manager.hpp @@ -53,6 +53,7 @@ #include "border_router/infra_if.hpp" #include "common/array.hpp" #include "common/error.hpp" +#include "common/heap_allocatable.hpp" #include "common/linked_list.hpp" #include "common/locator.hpp" #include "common/message.hpp" @@ -374,8 +375,8 @@ class RoutingManager : public InstanceLocator * * The favored NAT64 prefix can be discovered from infrastructure link or can be the local NAT64 prefix. * - * @param[out] aPrefix A reference to output the favored prefix. - * @param[out] aPreference A reference to output the preference associated with the favored prefix. + * @param[out] aPrefix A reference to output the favored prefix. + * @param[out] aRoutePreference A reference to output the preference associated with the favored prefix. * * @retval kErrorInvalidState The Border Routing Manager is not initialized yet. * @retval kErrorNone Successfully retrieved the NAT64 prefix. @@ -624,10 +625,17 @@ class RoutingManager : public InstanceLocator void HandleRouterTimer(void); private: +#if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE static constexpr uint16_t kMaxRouters = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_ROUTERS; static constexpr uint16_t kMaxEntries = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES; +#endif - class Entry : public LinkedListEntry, public Unequatable, private Clearable + class Entry : public LinkedListEntry, + public Unequatable, +#if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE + public Heap::Allocatable, +#endif + private Clearable { friend class LinkedListEntry; friend class Clearable; @@ -725,7 +733,11 @@ class RoutingManager : public InstanceLocator } mShared; }; - struct Router + struct Router : public LinkedListEntry, +#if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE + public Heap::Allocatable, +#endif + public Clearable { // The timeout (in msec) for router staying in active state // before starting the Neighbor Solicitation (NS) probes. @@ -746,10 +758,14 @@ class RoutingManager : public InstanceLocator bool Matches(const Ip6::Address &aAddress) const { return aAddress == mAddress; } bool Matches(EmptyChecker) const { return mEntries.IsEmpty(); } + Router *mNext; Ip6::Address mAddress; LinkedList mEntries; TimeMilli mTimeout; uint8_t mNsProbeCount; + bool mManagedAddressConfigFlag : 1; + bool mOtherConfigFlag : 1; + bool mStubRouterFlag : 1; }; class Iterator : public PrefixTableIterator @@ -763,15 +779,15 @@ class RoutingManager : public InstanceLocator void SetInitTime(void) { mData32 = TimerMilli::GetNow().GetValue(); } }; - void ProcessDefaultRoute(const Ip6::Nd::RouterAdvertMessage::Header &aRaHeader, Router &aRouter); + void ProcessRaHeader(const Ip6::Nd::RouterAdvertMessage::Header &aRaHeader, Router &aRouter); void ProcessPrefixInfoOption(const Ip6::Nd::PrefixInfoOption &aPio, Router &aRouter); void ProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption &aRio, Router &aRouter); + void ProcessRaFlagsExtOption(const Ip6::Nd::RaFlagsExtOption &aFlagsOption, Router &aRouter); bool Contains(const Entry::Checker &aChecker) const; void RemovePrefix(const Entry::Matcher &aMatcher); void RemoveOrDeprecateEntriesFromInactiveRouters(void); void RemoveRoutersWithNoEntries(void); - Entry *AllocateEntry(void) { return mEntryPool.Allocate(); } - void FreeEntry(Entry &aEntry) { mEntryPool.Free(aEntry); } + void FreeRouters(LinkedList &aRouters); void FreeEntries(LinkedList &aEntries); void UpdateNetworkDataOnChangeTo(Entry &aEntry); const Entry *FindFavoredEntryToPublish(const Ip6::Prefix &aPrefix) const; @@ -779,16 +795,30 @@ class RoutingManager : public InstanceLocator void SignalTableChanged(void); void UpdateRouterOnRx(Router &aRouter); void SendNeighborSolicitToRouter(const Router &aRouter); +#if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE + Router *AllocateRouter(void) { return Router::Allocate(); } + Entry *AllocateEntry(void) { return Entry::Allocate(); } + void FreeRouter(Router &aRouter) { aRouter.Free(); } + void FreeEntry(Entry &aEntry) { aEntry.Free(); } +#else + Router *AllocateRouter(void) { return mRouterPool.Allocate(); } + Entry *AllocateEntry(void) { return mEntryPool.Allocate(); } + void FreeRouter(Router &aRouter) { mRouterPool.Free(aRouter); } + void FreeEntry(Entry &aEntry) { mEntryPool.Free(aEntry); } +#endif using SignalTask = TaskletIn; using EntryTimer = TimerMilliIn; using RouterTimer = TimerMilliIn; - Array mRouters; - Pool mEntryPool; - EntryTimer mEntryTimer; - RouterTimer mRouterTimer; - SignalTask mSignalTask; + LinkedList mRouters; + EntryTimer mEntryTimer; + RouterTimer mRouterTimer; + SignalTask mSignalTask; +#if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE + Pool mEntryPool; + Pool mRouterPool; +#endif }; class OmrPrefixManager; @@ -899,15 +929,18 @@ class RoutingManager : public InstanceLocator TimeMilli mExpireTime; }; - void GenerateLocalPrefix(void); - void PublishAndAdvertise(void); - void Deprecate(void); - void ResetExpireTime(TimeMilli aNow); - void EnterAdvertisingState(void); - void AppendCurPrefix(Ip6::Nd::RouterAdvertMessage &aRaMessage); - void AppendOldPrefixes(Ip6::Nd::RouterAdvertMessage &aRaMessage); - void DeprecateOldPrefix(const Ip6::Prefix &aPrefix, TimeMilli aExpireTime); - void SavePrefix(const Ip6::Prefix &aPrefix, TimeMilli aExpireTime); + State GetState(void) const { return mState; } + void SetState(State aState); + void GenerateLocalPrefix(void); + void PublishAndAdvertise(void); + void Deprecate(void); + void ResetExpireTime(TimeMilli aNow); + void AppendCurPrefix(Ip6::Nd::RouterAdvertMessage &aRaMessage); + void AppendOldPrefixes(Ip6::Nd::RouterAdvertMessage &aRaMessage); + void DeprecateOldPrefix(const Ip6::Prefix &aPrefix, TimeMilli aExpireTime); + void SavePrefix(const Ip6::Prefix &aPrefix, TimeMilli aExpireTime); + + static const char *StateToString(State aState); using ExpireTimer = TimerMilliIn; @@ -985,6 +1018,8 @@ class RoutingManager : public InstanceLocator void Stop(void) { Unpublish(); } void Evaluate(void); + void UpdateAdvPioFlags(bool aAdvPioFlag); + RoutePreference GetPreference(void) const { return mPreference; } void SetPreference(RoutePreference aPreference); void ClearPreference(void); @@ -1019,6 +1054,7 @@ class RoutingManager : public InstanceLocator State mState; RoutePreference mPreference; bool mUserSetPreference; + bool mAdvPioFlag; DelayTimer mTimer; }; diff --git a/third_party/openthread/repo/src/core/coap/coap.cpp b/third_party/openthread/repo/src/core/coap/coap.cpp index 38e56185..696d0fc8 100644 --- a/third_party/openthread/repo/src/core/coap/coap.cpp +++ b/third_party/openthread/repo/src/core/coap/coap.cpp @@ -32,10 +32,10 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "net/ip6.hpp" #include "net/udp6.hpp" #include "thread/thread_netif.hpp" diff --git a/third_party/openthread/repo/src/core/coap/coap.hpp b/third_party/openthread/repo/src/core/coap/coap.hpp index 30a98ec4..9a08916a 100644 --- a/third_party/openthread/repo/src/core/coap/coap.hpp +++ b/third_party/openthread/repo/src/core/coap/coap.hpp @@ -848,7 +848,7 @@ class CoapBase : public InstanceLocator, private NonCopyable /** * Sets the resource handler function. * - * @param[in] aResourceHandler The resource handler function pointer. + * @param[in] aHandler The resource handler function pointer. * */ void SetResourceHandler(ResourceHandler aHandler) { mResourceHandler = aHandler; } diff --git a/third_party/openthread/repo/src/core/coap/coap_message.cpp b/third_party/openthread/repo/src/core/coap/coap_message.cpp index 72fb6148..61c2ae0a 100644 --- a/third_party/openthread/repo/src/core/coap/coap_message.cpp +++ b/third_party/openthread/repo/src/core/coap/coap_message.cpp @@ -38,9 +38,9 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/random.hpp" #include "common/string.hpp" +#include "instance/instance.hpp" namespace ot { namespace Coap { diff --git a/third_party/openthread/repo/src/core/coap/coap_secure.cpp b/third_party/openthread/repo/src/core/coap/coap_secure.cpp index 3f5730af..7d0fbe1b 100644 --- a/third_party/openthread/repo/src/core/coap/coap_secure.cpp +++ b/third_party/openthread/repo/src/core/coap/coap_secure.cpp @@ -30,10 +30,10 @@ #if OPENTHREAD_CONFIG_DTLS_ENABLE -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/new.hpp" +#include "instance/instance.hpp" #include "meshcop/dtls.hpp" #include "thread/thread_netif.hpp" diff --git a/third_party/openthread/repo/src/core/common/heap.cpp b/third_party/openthread/repo/src/core/common/heap.cpp index 7b431ee3..cc403467 100644 --- a/third_party/openthread/repo/src/core/common/heap.cpp +++ b/third_party/openthread/repo/src/core/common/heap.cpp @@ -33,7 +33,7 @@ #include "heap.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" namespace ot { namespace Heap { diff --git a/third_party/openthread/repo/src/core/common/linked_list.hpp b/third_party/openthread/repo/src/core/common/linked_list.hpp index 3f04aef1..0d9ecf9a 100644 --- a/third_party/openthread/repo/src/core/common/linked_list.hpp +++ b/third_party/openthread/repo/src/core/common/linked_list.hpp @@ -180,6 +180,26 @@ template class LinkedList aPrevEntry.SetNext(&aEntry); } + /** + * Pushes an entry after the tail in the linked list. + * + * @param[in] aEntry A reference to an entry to push into the list. + * + */ + void PushAfterTail(Type &aEntry) + { + Type *tail = GetTail(); + + if (tail == nullptr) + { + Push(aEntry); + } + else + { + PushAfter(aEntry, *tail); + } + } + /** * Pops an entry from head of the linked list. * diff --git a/third_party/openthread/repo/src/core/common/locator_getters.hpp b/third_party/openthread/repo/src/core/common/locator_getters.hpp index 990b8c6d..ad9067f5 100644 --- a/third_party/openthread/repo/src/core/common/locator_getters.hpp +++ b/third_party/openthread/repo/src/core/common/locator_getters.hpp @@ -37,9 +37,9 @@ #include "openthread-core-config.h" -#include "common/instance.hpp" #include "common/locator.hpp" #include "common/tasklet.hpp" +#include "instance/instance.hpp" namespace ot { diff --git a/third_party/openthread/repo/src/core/common/log.cpp b/third_party/openthread/repo/src/core/common/log.cpp index 04c74bbb..1809cd54 100644 --- a/third_party/openthread/repo/src/core/common/log.cpp +++ b/third_party/openthread/repo/src/core/common/log.cpp @@ -38,9 +38,10 @@ #include #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/num_utils.hpp" +#include "common/numeric_limits.hpp" #include "common/string.hpp" +#include "instance/instance.hpp" /* * Verify debug UART dependency. @@ -169,99 +170,120 @@ template void Logger::DumpAtLevel(const char *aModuleName, const void *aData, uint16_t aDataLength); -void Logger::DumpLine(const char *aModuleName, LogLevel aLogLevel, const uint8_t *aData, const uint16_t aDataLength) +void Logger::DumpInModule(const char *aModuleName, + LogLevel aLogLevel, + const char *aText, + const void *aData, + uint16_t aDataLength) { - ot::String string; + HexDumpInfo info; + + VerifyOrExit(otLoggingGetLevel() >= aLogLevel); - string.Append("|"); + info.mDataBytes = reinterpret_cast(aData); + info.mDataLength = aDataLength; + info.mTitle = aText; + info.mIterator = 0; - for (uint8_t i = 0; i < kDumpBytesPerLine; i++) + while (GenerateNextHexDumpLine(info) == kErrorNone) { - if (i < aDataLength) - { - string.Append(" %02X", aData[i]); - } - else - { - string.Append(" .."); - } + LogInModule(aModuleName, aLogLevel, "%s", info.mLine); + } - if (!((i + 1) % 8)) - { - string.Append(" |"); - } +exit: + return; +} + +#endif // OPENTHREAD_CONFIG_LOG_PKT_DUMP + +#endif // OT_SHOULD_LOG + +Error GenerateNextHexDumpLine(HexDumpInfo &aInfo) +{ + constexpr uint16_t kIterTableStartLine = 0; + constexpr uint16_t kIterFirstDataLine = NumericLimits::kMax - 2; + constexpr uint16_t kIterTableEndLine = NumericLimits::kMax - 1; + constexpr uint16_t kIterFinished = NumericLimits::kMax; + constexpr uint16_t kWidth = 72; + constexpr uint16_t kTitleSuffixLen = sizeof("[ len=000]") - 1; + constexpr uint16_t kDumpBytesPerLine = 16; + + Error error = kErrorNone; + StringWriter writer(aInfo.mLine, sizeof(aInfo.mLine)); + + switch (aInfo.mIterator) + { + case kIterTableStartLine: + { + uint16_t txtLen = StringLength(aInfo.mTitle, kWidth - kTitleSuffixLen) + kTitleSuffixLen; + + writer.AppendCharMultipleTimes('=', static_cast((kWidth - txtLen) / 2)); + writer.Append("[%s len=%03u]", aInfo.mTitle, aInfo.mDataLength); + writer.AppendCharMultipleTimes('=', static_cast(kWidth - txtLen - (kWidth - txtLen) / 2)); + aInfo.mIterator = kIterFirstDataLine; + break; } - string.Append(" "); + case kIterTableEndLine: + writer.AppendCharMultipleTimes('-', kWidth); + aInfo.mIterator = kIterFinished; + break; + + case kIterFinished: + error = kErrorNotFound; + break; - for (uint8_t i = 0; i < kDumpBytesPerLine; i++) + case kIterFirstDataLine: + aInfo.mIterator = 0; + OT_FALL_THROUGH; + + default: { - char c = '.'; + uint16_t startIndex = aInfo.mIterator; + uint16_t endIndex = aInfo.mIterator + kDumpBytesPerLine; + + writer.Append("|"); - if (i < aDataLength) + for (uint16_t i = startIndex; i < endIndex; i++) { - char byteAsChar = static_cast(0x7f & aData[i]); + (i < aInfo.mDataLength) ? writer.Append(" %02X", aInfo.mDataBytes[i]) : writer.Append(" "); - if (isprint(byteAsChar)) + if ((i % 8) == 7) { - c = byteAsChar; + writer.Append(" |"); } } - string.Append("%c", c); - } + writer.Append(" "); - LogInModule(aModuleName, aLogLevel, "%s", string.AsCString()); -} + for (uint16_t i = startIndex; i < endIndex; i++) + { + char c = ' '; -void Logger::DumpInModule(const char *aModuleName, - LogLevel aLogLevel, - const char *aText, - const void *aData, - uint16_t aDataLength) -{ - constexpr uint16_t kWidth = 72; - constexpr uint16_t kTextSuffixLen = sizeof("[ len=000]") - 1; + if (i < aInfo.mDataLength) + { + uint8_t byte = aInfo.mDataBytes[i]; - uint16_t txtLen = StringLength(aText, kWidth - kTextSuffixLen) + kTextSuffixLen; - ot::String string; + c = ((byte < 127) && isprint(static_cast(byte))) ? static_cast(byte) : '.'; + } - VerifyOrExit(otLoggingGetLevel() >= aLogLevel); + writer.Append("%c", c); + } - for (uint16_t i = 0; i < static_cast((kWidth - txtLen) / 2); i++) - { - string.Append("="); - } + writer.Append(" |"); - string.Append("[%s len=%03u]", aText, aDataLength); + aInfo.mIterator = endIndex; - for (uint16_t i = 0; i < static_cast(kWidth - txtLen - (kWidth - txtLen) / 2); i++) - { - string.Append("="); - } - - LogInModule(aModuleName, aLogLevel, "%s", string.AsCString()); + if (aInfo.mIterator >= aInfo.mDataLength) + { + aInfo.mIterator = kIterTableEndLine; + } - for (uint16_t i = 0; i < aDataLength; i += kDumpBytesPerLine) - { - DumpLine(aModuleName, aLogLevel, static_cast(aData) + i, - Min(static_cast(aDataLength - i), kDumpBytesPerLine)); + break; } - - string.Clear(); - - for (uint16_t i = 0; i < kWidth; i++) - { - string.Append("-"); } - LogInModule(aModuleName, aLogLevel, "%s", string.AsCString()); - -exit: - return; + return error; } -#endif // OPENTHREAD_CONFIG_LOG_PKT_DUMP - -#endif // OT_SHOULD_LOG } // namespace ot diff --git a/third_party/openthread/repo/src/core/common/log.hpp b/third_party/openthread/repo/src/core/common/log.hpp index 6d46030d..47293e0b 100644 --- a/third_party/openthread/repo/src/core/common/log.hpp +++ b/third_party/openthread/repo/src/core/common/log.hpp @@ -40,6 +40,8 @@ #include #include +#include "common/error.hpp" + namespace ot { /** @@ -332,8 +334,6 @@ class Logger template static void DumpAtLevel(const char *aModuleName, const char *aText, const void *aData, uint16_t aDataLength); - - static void DumpLine(const char *aModuleName, LogLevel aLogLevel, const uint8_t *aData, uint16_t aDataLength); #endif }; @@ -372,6 +372,32 @@ extern template void Logger::DumpAtLevel(const char *aModuleName, #endif // OPENTHREAD_CONFIG_LOG_PKT_DUMP #endif // OT_SHOULD_LOG +typedef otLogHexDumpInfo HexDumpInfo; ///< Represents the hex dump info. + +/** + * Generates the next hex dump line. + * + * Can call this method back-to-back to generate the hex dump output line by line. On the first call the `mIterator` + * field in @p aInfo MUST be set to zero. + * + * Here is an example of the generated hex dump output: + * + * "==========================[{mTitle} len=070]============================" + * "| 41 D8 87 34 12 FF FF 25 | 4C 57 DA F2 FB 2F 62 7F | A..4...%LW.../b. |" + * "| 3B 01 F0 4D 4C 4D 4C 54 | 4F 00 15 15 00 00 00 00 | ;..MLMLTO....... |" + * "| 00 00 00 01 80 DB 60 82 | 7E 33 72 3B CC B3 A1 84 | ......`.~3r;.... |" + * "| 3B E6 AD B2 0B 45 E7 45 | C5 B9 00 1A CB 2D 6D 1C | ;....E.E.....-m. |" + * "| 10 3E 3C F5 D3 70 | | .><..p |" + * "------------------------------------------------------------------------" + * + * @param[in,out] aInfo A reference to a `LogHexDumpInfo` to use to generate hex dump. + * + * @retval kErrorNone Successfully generated the next line, `mLine` field in @p aInfo is updated. + * @retval kErrorNotFound Reached the end and no more line to generate. + * + */ +Error GenerateNextHexDumpLine(HexDumpInfo &aInfo); + } // namespace ot #endif // LOG_HPP_ diff --git a/third_party/openthread/repo/src/core/common/message.cpp b/third_party/openthread/repo/src/core/common/message.cpp index 9d3ebcaa..1c7028d0 100644 --- a/third_party/openthread/repo/src/core/common/message.cpp +++ b/third_party/openthread/repo/src/core/common/message.cpp @@ -37,11 +37,11 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/heap.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/num_utils.hpp" #include "common/numeric_limits.hpp" +#include "instance/instance.hpp" #include "net/checksum.hpp" #include "net/ip6.hpp" @@ -80,6 +80,8 @@ Message *MessagePool::Allocate(Message::Type aType, uint16_t aReserveHeader, con message->SetType(aType); message->SetReserved(aReserveHeader); message->SetLinkSecurityEnabled(aSettings.IsLinkSecurityEnabled()); + message->SetLoopbackToHostAllowed(OPENTHREAD_CONFIG_IP6_ALLOW_LOOP_BACK_HOST_DATAGRAMS); + message->SetOrigin(Message::kOriginHostTrusted); SuccessOrExit(error = message->SetPriority(aSettings.GetPriority())); SuccessOrExit(error = message->SetLength(0)); @@ -772,6 +774,8 @@ Message *Message::Clone(uint16_t aLength) const messageCopy->SetOffset(offset); messageCopy->SetSubType(GetSubType()); + messageCopy->SetLoopbackToHostAllowed(IsLoopbackToHostAllowed()); + messageCopy->SetOrigin(GetOrigin()); #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE messageCopy->SetTimeSync(IsTimeSync()); #endif diff --git a/third_party/openthread/repo/src/core/common/message.hpp b/third_party/openthread/repo/src/core/common/message.hpp index d40bf08a..66153e24 100644 --- a/third_party/openthread/repo/src/core/common/message.hpp +++ b/third_party/openthread/repo/src/core/common/message.hpp @@ -207,16 +207,18 @@ class Buffer : public otMessageBuffer, public LinkedListEntry ChildMask mChildMask; // ChildMask to indicate which sleepy children need to receive this. #endif - uint8_t mType : 3; // The message type. - uint8_t mSubType : 4; // The message sub type. - bool mDirectTx : 1; // Whether a direct transmission is required. - bool mLinkSecurity : 1; // Whether link security is enabled. - uint8_t mPriority : 2; // The message priority level (higher value is higher priority). - bool mInPriorityQ : 1; // Whether the message is queued in normal or priority queue. - bool mTxSuccess : 1; // Whether the direct tx of the message was successful. - bool mDoNotEvict : 1; // Whether this message may be evicted. - bool mMulticastLoop : 1; // Whether this multicast message may be looped back. - bool mResolvingAddress : 1; // Whether the message is pending an address query resolution. + uint8_t mType : 3; // The message type. + uint8_t mSubType : 4; // The message sub type. + bool mDirectTx : 1; // Whether a direct transmission is required. + bool mLinkSecurity : 1; // Whether link security is enabled. + uint8_t mPriority : 2; // The message priority level (higher value is higher priority). + bool mInPriorityQ : 1; // Whether the message is queued in normal or priority queue. + bool mTxSuccess : 1; // Whether the direct tx of the message was successful. + bool mDoNotEvict : 1; // Whether this message may be evicted. + bool mMulticastLoop : 1; // Whether this multicast message may be looped back. + bool mResolvingAddress : 1; // Whether the message is pending an address query resolution. + bool mAllowLookbackToHost : 1; // Whether the message is allowed to be looped back to host. + uint8_t mOrigin : 2; // The origin of the message. #if OPENTHREAD_CONFIG_MULTI_RADIO uint8_t mRadioType : 2; // The radio link type the message was received on, or should be sent on. bool mIsRadioTypeSet : 1; // Whether the radio type is set. @@ -349,6 +351,17 @@ class Message : public otMessage, public Buffer, public GetProvider kCopyToUse, }; + /** + * Represents an IPv6 message origin. + * + */ + enum Origin : uint8_t + { + kOriginThreadNetif = OT_MESSAGE_ORIGIN_THREAD_NETIF, // Message from Thread Netif. + kOriginHostTrusted = OT_MESSAGE_ORIGIN_HOST_TRUSTED, // Message from a trusted source on host. + kOriginHostUntrusted = OT_MESSAGE_ORIGIN_HOST_UNTRUSTED, // Message from an untrusted source on host. + }; + /** * Represents settings used for creating a new message. * @@ -1135,6 +1148,69 @@ class Message : public otMessage, public Buffer, public GetProvider */ void SetResolvingAddress(bool aResolvingAddress) { GetMetadata().mResolvingAddress = aResolvingAddress; } + /** + * Indicates whether the message is allowed to be looped back to host. + * + * @retval TRUE If the message is allowed to be looped back to host. + * @retval FALSE If the message is not allowed to be looped back to host. + * + */ + bool IsLoopbackToHostAllowed(void) const { return GetMetadata().mAllowLookbackToHost; } + + /** + * Sets whether or not allow the message to be looped back to host. + * + * @param[in] aAllowLoopbackToHost Whether or not allow the message to be looped back to host. + * + */ + void SetLoopbackToHostAllowed(bool aAllowLoopbackToHost) + { + GetMetadata().mAllowLookbackToHost = aAllowLoopbackToHost; + } + + /** + * Gets the message origin. + * + * @returns An enum representing the origin of the message. + * + */ + Origin GetOrigin(void) const { return static_cast(GetMetadata().mOrigin); } + + /** + * Sets the message origin. + * + * @param[in] aOrigin An enum representing the origin of the message. + * + */ + void SetOrigin(Origin aOrigin) { GetMetadata().mOrigin = aOrigin; } + + /** + * Indicates whether or not the message origin is Thread Netif. + * + * @retval TRUE If the message origin is Thread Netif. + * @retval FALSE If the message origin is not Thread Netif. + * + */ + bool IsOriginThreadNetif(void) const { return GetOrigin() == kOriginThreadNetif; } + + /** + * Indicates whether or not the message origin is a trusted source on host. + * + * @retval TRUE If the message origin is a trusted source on host. + * @retval FALSE If the message origin is not a trusted source on host. + * + */ + bool IsOriginHostTrusted(void) const { return GetOrigin() == kOriginHostTrusted; } + + /** + * Indicates whether or not the message origin is an untrusted source on host. + * + * @retval TRUE If the message origin is an untrusted source on host. + * @retval FALSE If the message origin is not an untrusted source on host. + * + */ + bool IsOriginHostUntrusted(void) const { return GetOrigin() == kOriginHostUntrusted; } + /** * Indicates whether or not link security is enabled for the message. * @@ -1798,6 +1874,8 @@ DefineCoreType(otMessageSettings, Message::Settings); DefineCoreType(otMessage, Message); DefineCoreType(otMessageQueue, MessageQueue); +DefineMapEnum(otMessageOrigin, Message::Origin); + } // namespace ot #endif // MESSAGE_HPP_ diff --git a/third_party/openthread/repo/src/core/common/notifier.cpp b/third_party/openthread/repo/src/core/common/notifier.cpp index 7f7646f1..f25e71eb 100644 --- a/third_party/openthread/repo/src/core/common/notifier.cpp +++ b/third_party/openthread/repo/src/core/common/notifier.cpp @@ -186,6 +186,9 @@ void Notifier::EmitEvents(void) // being published (if needed). Get().HandleNotifierEvents(events); #endif +#if OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE + Get().HandleNotifierEvents(events); +#endif for (ExternalCallback &callback : mExternalCallbacks) { diff --git a/third_party/openthread/repo/src/core/common/settings.cpp b/third_party/openthread/repo/src/core/common/settings.cpp index c9b6f3ad..504eb7c5 100644 --- a/third_party/openthread/repo/src/core/common/settings.cpp +++ b/third_party/openthread/repo/src/core/common/settings.cpp @@ -35,9 +35,9 @@ #include "common/array.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/num_utils.hpp" +#include "instance/instance.hpp" #include "meshcop/dataset.hpp" #include "thread/mle.hpp" diff --git a/third_party/openthread/repo/src/core/common/string.cpp b/third_party/openthread/repo/src/core/common/string.cpp index c7aa7218..4019628d 100644 --- a/third_party/openthread/repo/src/core/common/string.cpp +++ b/third_party/openthread/repo/src/core/common/string.cpp @@ -160,6 +160,35 @@ bool StringMatch(const char *aFirstString, const char *aSecondString, StringMatc return Match(aFirstString, aSecondString, aMode) == kFullMatch; } +Error StringCopy(char *aTargetBuffer, uint16_t aTargetSize, const char *aSource, StringEncodingCheck aEncodingCheck) +{ + Error error = kErrorNone; + uint16_t length; + + if (aSource == nullptr) + { + aTargetBuffer[0] = kNullChar; + ExitNow(); + } + + length = StringLength(aSource, aTargetSize); + VerifyOrExit(length < aTargetSize, error = kErrorInvalidArgs); + + switch (aEncodingCheck) + { + case kStringNoEncodingCheck: + break; + case kStringCheckUtf8Encoding: + VerifyOrExit(IsValidUtf8String(aSource), error = kErrorParse); + break; + } + + memcpy(aTargetBuffer, aSource, length + 1); // `+ 1` to also copy null char. + +exit: + return error; +} + Error StringParseUint8(const char *&aString, uint8_t &aUint8) { return StringParseUint8(aString, aUint8, NumericLimits::kMax); @@ -281,6 +310,16 @@ StringWriter &StringWriter::AppendHexBytes(const uint8_t *aBytes, uint16_t aLeng return *this; } +StringWriter &StringWriter::AppendCharMultipleTimes(char aChar, uint16_t aCount) +{ + while (aCount--) + { + Append("%c", aChar); + } + + return *this; +} + bool IsValidUtf8String(const char *aString) { return IsValidUtf8String(aString, strlen(aString)); } bool IsValidUtf8String(const char *aString, size_t aLength) diff --git a/third_party/openthread/repo/src/core/common/string.hpp b/third_party/openthread/repo/src/core/common/string.hpp index 035bc3f3..0c73bb60 100644 --- a/third_party/openthread/repo/src/core/common/string.hpp +++ b/third_party/openthread/repo/src/core/common/string.hpp @@ -67,6 +67,16 @@ enum StringMatchMode : uint8_t kStringCaseInsensitiveMatch, ///< Case insensitive match (uppercase and lowercase characters are treated as equal). }; +/** + * Represents string encoding check when copying string. + * + */ +enum StringEncodingCheck : uint8_t +{ + kStringNoEncodingCheck, ///< Do not check the string encoding. + kStringCheckUtf8Encoding, ///< Validate that string follows UTF-8 encoding. +}; + static constexpr char kNullChar = '\0'; ///< null character. /** @@ -156,6 +166,43 @@ bool StringEndsWith(const char *aString, const char *aSubString, StringMatchMode */ bool StringMatch(const char *aFirstString, const char *aSecondString, StringMatchMode aMode = kStringExactMatch); +/** + * Copies a string into a given target buffer with a given size if it fits. + * + * @param[out] aTargetBuffer A pointer to the target buffer to copy into. + * @param[out] aTargetSize The size (number of characters) in @p aTargetBuffer array. + * @param[in] aSource A pointer to null-terminated string to copy from. Can be `nullptr` which treated as "". + * @param[in] aEncodingCheck Specifies the encoding format check (e.g., UTF-8) to perform. + * + * @retval kErrorNone The @p aSource fits in the given buffer. @p aTargetBuffer is updated. + * @retval kErrorInvalidArgs The @p aSource does not fit in the given buffer. + * @retval kErrorParse The @p aSource does not follow the encoding format specified by @p aEncodingCheck. + * + */ +Error StringCopy(char *TargetBuffer, uint16_t aTargetSize, const char *aSource, StringEncodingCheck aEncodingCheck); + +/** + * Copies a string into a given target buffer with a given size if it fits. + * + * @tparam kSize The size of buffer. + * + * @param[out] aTargetBuffer A reference to the target buffer array to copy into. + * @param[in] aSource A pointer to null-terminated string to copy from. Can be `nullptr` which treated as "". + * @param[in] aEncodingCheck Specifies the encoding format check (e.g., UTF-8) to perform. + * + * @retval kErrorNone The @p aSource fits in the given buffer. @p aTargetBuffer is updated. + * @retval kErrorInvalidArgs The @p aSource does not fit in the given buffer. + * @retval kErrorParse The @p aSource does not follow the encoding format specified by @p aEncodingCheck. + * + */ +template +Error StringCopy(char (&aTargetBuffer)[kSize], + const char *aSource, + StringEncodingCheck aEncodingCheck = kStringNoEncodingCheck) +{ + return StringCopy(aTargetBuffer, kSize, aSource, aEncodingCheck); +} + /** * Parses a decimal number from a string as `uint8_t` and skips over the parsed characters. * @@ -376,6 +423,15 @@ class StringWriter */ StringWriter &AppendHexBytes(const uint8_t *aBytes, uint16_t aLength); + /** + * Appends a given character a given number of times. + * + * @param[in] aChar The character to append. + * @param[in] aCount Number of times to append @p aChar. + * + */ + StringWriter &AppendCharMultipleTimes(char aChar, uint16_t aCount); + /** * Converts all uppercase letter characters in the string to lowercase. * diff --git a/third_party/openthread/repo/src/core/common/time.hpp b/third_party/openthread/repo/src/core/common/time.hpp index 89c22c23..e1e56416 100644 --- a/third_party/openthread/repo/src/core/common/time.hpp +++ b/third_party/openthread/repo/src/core/common/time.hpp @@ -65,6 +65,7 @@ class Time : public Unequatable