diff --git a/.github/workflows/border_router.yml b/.github/workflows/border_router.yml index 86d484ce95c..de8a3c6b277 100644 --- a/.github/workflows/border_router.yml +++ b/.github/workflows/border_router.yml @@ -110,7 +110,7 @@ jobs: name: ${{ matrix.name }} env: PACKET_VERIFICATION: ${{ matrix.packet_verification }} - THREAD_VERSION: 1.3 + THREAD_VERSION: 1.4 VIRTUAL_TIME: 0 PYTHONUNBUFFERED: 1 REFERENCE_DEVICE: 1 @@ -173,15 +173,15 @@ jobs: run: | export CI_ENV="$(bash <(curl -s https://codecov.io/env)) -e GITHUB_ACTIONS -e OTBR_COVERAGE" echo "CI_ENV=${CI_ENV}" - (cd third_party/openthread/repo && sudo -E ./script/test cert_suite ${{ matrix.cert_scripts }} || (sudo chmod a+r *.log *.json *.pcap && false)) + (cd third_party/openthread/repo && sudo -E ./script/test cert_suite ${{ matrix.cert_scripts }} || (sudo chmod a+r ot_testing/* && false)) - uses: actions/upload-artifact@v4 if: ${{ failure() && steps.check_cache_result.outputs.cache-hit != 'true' }} with: - name: thread-1-3-backbone-results + name: thread-1-4-backbone-results path: | - third_party/openthread/repo/*.pcap - third_party/openthread/repo/*.json - third_party/openthread/repo/*.log + third_party/openthread/repo/ot_testing/*.pcap + third_party/openthread/repo/ot_testing/*.json + third_party/openthread/repo/ot_testing/*.log - name: Codecov if: ${{ success() && steps.check_cache_result.outputs.cache-hit != 'true' }} uses: codecov/codecov-action@v4 diff --git a/.github/workflows/macOS.yml b/.github/workflows/macOS.yml index a99adde89e2..9cb944d365d 100644 --- a/.github/workflows/macOS.yml +++ b/.github/workflows/macOS.yml @@ -42,7 +42,7 @@ concurrency: jobs: build-check: - runs-on: macos-12 + runs-on: macos-14 steps: - uses: actions/checkout@v4 with: @@ -54,14 +54,13 @@ jobs: rm -f /usr/local/bin/pydoc3* rm -f /usr/local/bin/python3* brew update - brew reinstall boost cmake cpputest dbus jsoncpp ninja protobuf@21 pkg-config - brew upgrade node + brew reinstall boost cmake dbus jsoncpp ninja protobuf@21 pkg-config - name: Build run: | OTBR_OPTIONS="-DOTBR_BORDER_AGENT=OFF \ -DOTBR_MDNS=OFF \ - -DOTBR_ADVERTISING_PROXY=OFF \ - -DOTBR_DISCOVERY_PROXY=OFF \ + -DOTBR_SRP_ADVERTISING_PROXY=OFF \ + -DOTBR_DNSSD_DISCOVERY_PROXY=OFF \ -DOTBR_TREL=OFF \ -DOT_FIREWALL=OFF \ -DOTBR_DBUS=OFF" ./script/test build diff --git a/.github/workflows/meshcop.yml b/.github/workflows/meshcop.yml index 6bbc8503ada..eade0d4559c 100644 --- a/.github/workflows/meshcop.yml +++ b/.github/workflows/meshcop.yml @@ -60,6 +60,7 @@ jobs: - name: Build env: OTBR_MDNS: ${{ matrix.mdns }} + OTBR_COVERAGE: 1 run: | script/bootstrap script/test build diff --git a/.github/workflows/ncp_mode.yml b/.github/workflows/ncp_mode.yml new file mode 100644 index 00000000000..0370311ae6d --- /dev/null +++ b/.github/workflows/ncp_mode.yml @@ -0,0 +1,67 @@ +# +# Copyright (c) 2024, 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. +# + +name: NcpMode + +on: + push: + branches-ignore: + - 'dependabot/**' + pull_request: + branches: + - 'main' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || (github.repository == 'openthread/ot-br-posix' && github.run_id) || github.ref }} + cancel-in-progress: true + +jobs: + + ncp_mode: + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + mdns: ["mDNSResponder", "avahi"] + env: + BUILD_TARGET: check + OTBR_MDNS: ${{ matrix.mdns }} + OTBR_COVERAGE: 1 + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - name: Bootstrap + run: tests/scripts/bootstrap.sh + - name: Build + run: | + OTBR_BUILD_DIR="./build/temp" script/cmake-build -DCMAKE_BUILD_TYPE=Debug -DOT_THREAD_VERSION=1.4 -DOTBR_COVERAGE=ON -DOTBR_DBUS=ON -DOTBR_FEATURE_FLAGS=ON -DOTBR_TELEMETRY_DATA_API=ON -DOTBR_WEB=ON -DOTBR_UNSECURE_JOIN=ON -DOTBR_TREL=ON + - name: Run + run: OTBR_VERBOSE=1 OTBR_TOP_BUILDDIR="./build/temp" script/test ncp_mode + - name: Codecov + uses: codecov/codecov-action@v4 diff --git a/.lgtm.yml b/.lgtm.yml index db582a3c0c0..a9812dd0019 100644 --- a/.lgtm.yml +++ b/.lgtm.yml @@ -36,7 +36,6 @@ extraction: - libboost-dev - libboost-filesystem-dev - libboost-system-dev - - libcpputest-dev - libdbus-1-dev - libjsoncpp-dev - ninja-build diff --git a/CMakeLists.txt b/CMakeLists.txt index 4fefd2798b7..d31b2096b1a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,7 +118,6 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) include(CTest) if(BUILD_TESTING) - pkg_check_modules(CPPUTEST cpputest REQUIRED) add_subdirectory(tests) endif() diff --git a/etc/docker/Dockerfile b/etc/docker/Dockerfile index 08f160c8443..b4eed1f92cd 100644 --- a/etc/docker/Dockerfile +++ b/etc/docker/Dockerfile @@ -73,17 +73,13 @@ ENV OTBR_DOCKER_DEPS git ca-certificates # Required and installed during build (script/bootstrap), could be removed ENV OTBR_BUILD_DEPS apt-utils build-essential psmisc ninja-build cmake wget ca-certificates \ - libreadline-dev libncurses-dev libcpputest-dev libdbus-1-dev libavahi-common-dev \ + libreadline-dev libncurses-dev libdbus-1-dev libavahi-common-dev \ libavahi-client-dev libboost-dev libboost-filesystem-dev libboost-system-dev \ libnetfilter-queue-dev # Required for OpenThread Backbone CI ENV OTBR_OT_BACKBONE_CI_DEPS curl lcov wget build-essential python3-dbus python3-zeroconf socat -# Required and installed during build (script/bootstrap) when RELEASE=1, could be removed -ENV OTBR_NORELEASE_DEPS \ - cpputest-dev - RUN apt-get update \ && apt-get install --no-install-recommends -y $OTBR_DOCKER_REQS $OTBR_DOCKER_DEPS \ && ([ "${OT_BACKBONE_CI}" != "1" ] || apt-get install --no-install-recommends -y $OTBR_OT_BACKBONE_CI_DEPS) \ @@ -107,7 +103,6 @@ RUN ([ "${DNS64}" = "0" ] || chmod 644 /etc/bind/named.conf.options) \ && mv /tmp/etc . \ && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $OTBR_DOCKER_DEPS \ && 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/* \ )) diff --git a/etc/docker/docker_entrypoint.sh b/etc/docker/docker_entrypoint.sh index 1addb73559a..d39abed5520 100755 --- a/etc/docker/docker_entrypoint.sh +++ b/etc/docker/docker_entrypoint.sh @@ -58,6 +58,11 @@ function parse_args() shift shift ;; + --debug-level) + DEBUG_LEVEL=$2 + shift + shift + ;; *) shift ;; @@ -81,12 +86,15 @@ parse_args "$@" [ -n "$TUN_INTERFACE_NAME" ] || TUN_INTERFACE_NAME="wpan0" [ -n "$BACKBONE_INTERFACE" ] || BACKBONE_INTERFACE="eth0" [ -n "$NAT64_PREFIX" ] || NAT64_PREFIX="64:ff9b::/96" +[ -n "$DEBUG_LEVEL" ] || DEBUG_LEVEL="7" +[ -n "$HTTP_PORT" ] || HTTP_PORT=80 echo "RADIO_URL:" $RADIO_URL echo "TREL_URL:" "$TREL_URL" echo "TUN_INTERFACE_NAME:" $TUN_INTERFACE_NAME echo "BACKBONE_INTERFACE: $BACKBONE_INTERFACE" echo "NAT64_PREFIX:" $NAT64_PREFIX +echo "DEBUG_LEVEL:" $DEBUG_LEVEL NAT64_PREFIX=${NAT64_PREFIX/\//\\\/} TAYGA_CONF=/etc/tayga.conf @@ -96,8 +104,8 @@ BIND_CONF_OPTIONS=/etc/bind/named.conf.options ! test -f $BIND_CONF_OPTIONS || sed -i "s/dns64.*$/dns64 $NAT64_PREFIX {};/" $BIND_CONF_OPTIONS sed -i "s/$INFRA_IF_NAME/$BACKBONE_INTERFACE/" /etc/sysctl.d/60-otbr-accept-ra.conf -echo "OTBR_AGENT_OPTS=\"-I $TUN_INTERFACE_NAME -B $BACKBONE_INTERFACE -d7 $RADIO_URL $TREL_URL\"" >/etc/default/otbr-agent -echo "OTBR_WEB_OPTS=\"-I $TUN_INTERFACE_NAME -d7 -p 80\"" >/etc/default/otbr-web +echo "OTBR_AGENT_OPTS=\"-I $TUN_INTERFACE_NAME -B $BACKBONE_INTERFACE -d${DEBUG_LEVEL} $RADIO_URL $TREL_URL\"" >/etc/default/otbr-agent +echo "OTBR_WEB_OPTS=\"-I $TUN_INTERFACE_NAME -d${DEBUG_LEVEL} -p $HTTP_PORT\"" >/etc/default/otbr-web /app/script/server diff --git a/etc/openwrt/openthread-br/Makefile b/etc/openwrt/openthread-br/Makefile index cf0fdfb4e43..a9199378a61 100644 --- a/etc/openwrt/openthread-br/Makefile +++ b/etc/openwrt/openthread-br/Makefile @@ -52,7 +52,7 @@ CMAKE_OPTIONS+= \ -DOT_FIREWALL=ON \ -DOT_POSIX_SETTINGS_PATH=\"/etc/openthread\" \ -DOT_READLINE=OFF \ - -DOTBR_NAT64=ON \ + -DOTBR_NAT64=OFF \ -DNAT64_SERVICE=\"openthread\" TARGET_CFLAGS += -DOPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME=\\\"/var/run/openthread-%s\\\" diff --git a/script/bootstrap b/script/bootstrap index 4e8fdb024bc..5f93320fa77 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -53,8 +53,6 @@ install_packages_apt() sudo apt-get install --no-install-recommends -y build-essential ninja-build cmake - with RELEASE || sudo apt-get install --no-install-recommends -y libcpputest-dev - sudo apt-get install --no-install-recommends -y rsyslog # For DBus server @@ -132,7 +130,7 @@ EOF sudo apt-get install --no-install-recommends -y libjsoncpp-dev # reference device - without REFERENCE_DEVICE || sudo apt-get install --no-install-recommends -y radvd dnsutils avahi-utils + without REFERENCE_DEVICE || sudo apt-get install --no-install-recommends -y radvd dnsutils avahi-utils iperf3 # backbone-router without BACKBONE_ROUTER || sudo apt-get install --no-install-recommends -y libnetfilter-queue1 libnetfilter-queue-dev @@ -173,7 +171,7 @@ install_packages_rpm() install_packages_brew() { - brew install boost cmake cpputest dbus jsoncpp ninja + brew install boost cmake dbus jsoncpp ninja } install_packages_source() diff --git a/script/clang-format b/script/clang-format index e31466d22b5..bd1120ee8e1 100755 --- a/script/clang-format +++ b/script/clang-format @@ -43,7 +43,7 @@ if command -v clang-format-14 >/dev/null; then alias clang-format=clang-format-14 elif command -v clang-format >/dev/null; then case "$(clang-format --version)" in - "$CLANG_FORMAT_VERSION"*) ;; + *"$CLANG_FORMAT_VERSION"*) ;; *) die "$(clang-format --version); clang-format 14.0 required" diff --git a/script/test b/script/test index 93f642cb530..ca9398e0452 100755 --- a/script/test +++ b/script/test @@ -62,7 +62,7 @@ readonly OTBR_REST OTBR_OPTIONS="${OTBR_OPTIONS-}" readonly OTBR_OPTIONS -OTBR_TOP_BUILDDIR="${BUILD_DIR}/otbr" +OTBR_TOP_BUILDDIR="${OTBR_TOP_BUILDDIR:-${BUILD_DIR}/otbr}" readonly OTBR_TOP_BUILDDIR ####################################### @@ -128,7 +128,7 @@ do_build() otbr_options=( "-DCMAKE_BUILD_TYPE=${OTBR_BUILD_TYPE}" "-DCMAKE_INSTALL_PREFIX=/usr" - "-DOT_THREAD_VERSION=1.3" + "-DOT_THREAD_VERSION=1.4" "-DOTBR_DBUS=ON" "-DOTBR_FEATURE_FLAGS=ON" "-DOTBR_TELEMETRY_DATA_API=ON" @@ -152,7 +152,8 @@ do_check() { (cd "${OTBR_TOP_BUILDDIR}" \ && ninja && sudo ninja install \ - && CTEST_OUTPUT_ON_FAILURE=1 ninja test) + && CTEST_OUTPUT_ON_FAILURE=1 ctest -LE sudo \ + && CTEST_OUTPUT_ON_FAILURE=1 sudo ctest -L sudo) # Seperate running tests for sudo and non-sudo cases. } do_doxygen() @@ -236,6 +237,9 @@ main() meshcop) top_builddir="${OTBR_TOP_BUILDDIR}" print_result ./tests/scripts/meshcop ;; + ncp_mode) + top_builddir="${OTBR_TOP_BUILDDIR}" print_result ./tests/scripts/ncp_mode + ;; openwrt) print_result ./tests/scripts/openwrt ;; diff --git a/src/agent/application.cpp b/src/agent/application.cpp index 29bd4c19791..c656d249a4d 100644 --- a/src/agent/application.cpp +++ b/src/agent/application.cpp @@ -60,98 +60,58 @@ Application::Application(const std::string &aInterfaceName, #else , mBackboneInterfaceName(aBackboneInterfaceNames.empty() ? "" : aBackboneInterfaceNames.front()) #endif + , mHost(Ncp::ThreadHost::Create(mInterfaceName.c_str(), + aRadioUrls, + mBackboneInterfaceName, + /* aDryRun */ false, + aEnableAutoAttach)) #if OTBR_ENABLE_MDNS , mPublisher(Mdns::Publisher::Create([this](Mdns::Publisher::State aState) { this->HandleMdnsState(aState); })) #endif -#if OTBR_ENABLE_VENDOR_SERVER - , mVendorServer(vendor::VendorServer::newInstance(*this)) -#endif -{ - mHost = MakeUnique(mInterfaceName.c_str(), aRadioUrls, mBackboneInterfaceName, - /* aDryRun */ false, aEnableAutoAttach); - -#if OTBR_ENABLE_BORDER_AGENT - mBorderAgent = MakeUnique(*mHost, *mPublisher); -#endif -#if OTBR_ENABLE_BACKBONE_ROUTER - mBackboneAgent = MakeUnique(*mHost, aInterfaceName, mBackboneInterfaceName); -#endif -#if OTBR_ENABLE_SRP_ADVERTISING_PROXY - mAdvertisingProxy = MakeUnique(*mHost, *mPublisher); -#endif -#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY - mDiscoveryProxy = MakeUnique(*mHost, *mPublisher); -#endif -#if OTBR_ENABLE_TREL - mTrelDnssd = MakeUnique(*mHost, *mPublisher); -#endif -#if OTBR_ENABLE_OPENWRT - mUbusAgent = MakeUnique(*mHost); -#endif -#if OTBR_ENABLE_REST_SERVER - mRestWebServer = MakeUnique(*mHost, aRestListenAddress, aRestListenPort); -#endif #if OTBR_ENABLE_DBUS_SERVER && OTBR_ENABLE_BORDER_AGENT - mDBusAgent = MakeUnique(*mHost, *mPublisher); + , mDBusAgent(MakeUnique(*mHost, *mPublisher)) #endif - - OT_UNUSED_VARIABLE(aRestListenAddress); - OT_UNUSED_VARIABLE(aRestListenPort); +{ + if (mHost->GetCoprocessorType() == OT_COPROCESSOR_RCP) + { + CreateRcpMode(aRestListenAddress, aRestListenPort); + } } void Application::Init(void) { mHost->Init(); -#if OTBR_ENABLE_MDNS - mPublisher->Start(); -#endif -#if OTBR_ENABLE_BORDER_AGENT -// This is for delaying publishing the MeshCoP service until the correct -// vendor name and OUI etc. are correctly set by BorderAgent::SetMeshCopServiceValues() -#if OTBR_STOP_BORDER_AGENT_ON_INIT - mBorderAgent->SetEnabled(false); -#else - mBorderAgent->SetEnabled(true); -#endif -#endif -#if OTBR_ENABLE_BACKBONE_ROUTER - mBackboneAgent->Init(); -#endif -#if OTBR_ENABLE_SRP_ADVERTISING_PROXY - mAdvertisingProxy->SetEnabled(true); -#endif -#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY - mDiscoveryProxy->SetEnabled(true); -#endif -#if OTBR_ENABLE_OPENWRT - mUbusAgent->Init(); -#endif -#if OTBR_ENABLE_REST_SERVER - mRestWebServer->Init(); -#endif -#if OTBR_ENABLE_DBUS_SERVER - mDBusAgent->Init(); -#endif -#if OTBR_ENABLE_VENDOR_SERVER - mVendorServer->Init(); -#endif + switch (mHost->GetCoprocessorType()) + { + case OT_COPROCESSOR_RCP: + InitRcpMode(); + break; + case OT_COPROCESSOR_NCP: + InitNcpMode(); + break; + default: + DieNow("Unknown coprocessor type!"); + break; + } + + otbrLogInfo("Co-processor version: %s", mHost->GetCoprocessorVersion()); } void Application::Deinit(void) { -#if OTBR_ENABLE_SRP_ADVERTISING_PROXY - mAdvertisingProxy->SetEnabled(false); -#endif -#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY - mDiscoveryProxy->SetEnabled(false); -#endif -#if OTBR_ENABLE_BORDER_AGENT - mBorderAgent->SetEnabled(false); -#endif -#if OTBR_ENABLE_MDNS - mPublisher->Stop(); -#endif + switch (mHost->GetCoprocessorType()) + { + case OT_COPROCESSOR_RCP: + DeinitRcpMode(); + break; + case OT_COPROCESSOR_NCP: + DeinitNcpMode(); + break; + default: + DieNow("Unknown coprocessor type!"); + break; + } mHost->Deinit(); } @@ -255,4 +215,101 @@ void Application::HandleSignal(int aSignal) signal(aSignal, SIG_DFL); } +void Application::CreateRcpMode(const std::string &aRestListenAddress, int aRestListenPort) +{ + otbr::Ncp::RcpHost &rcpHost = static_cast(*mHost); +#if OTBR_ENABLE_BORDER_AGENT + mBorderAgent = MakeUnique(rcpHost, *mPublisher); +#endif +#if OTBR_ENABLE_BACKBONE_ROUTER + mBackboneAgent = MakeUnique(rcpHost, mInterfaceName, mBackboneInterfaceName); +#endif +#if OTBR_ENABLE_SRP_ADVERTISING_PROXY + mAdvertisingProxy = MakeUnique(rcpHost, *mPublisher); +#endif +#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY + mDiscoveryProxy = MakeUnique(rcpHost, *mPublisher); +#endif +#if OTBR_ENABLE_TREL + mTrelDnssd = MakeUnique(rcpHost, *mPublisher); +#endif +#if OTBR_ENABLE_OPENWRT + mUbusAgent = MakeUnique(rcpHost); +#endif +#if OTBR_ENABLE_REST_SERVER + mRestWebServer = MakeUnique(rcpHost, aRestListenAddress, aRestListenPort); +#endif +#if OTBR_ENABLE_VENDOR_SERVER + mVendorServer = vendor::VendorServer::newInstance(*this); +#endif + + OT_UNUSED_VARIABLE(aRestListenAddress); + OT_UNUSED_VARIABLE(aRestListenPort); +} + +void Application::InitRcpMode(void) +{ +#if OTBR_ENABLE_MDNS + mPublisher->Start(); +#endif +#if OTBR_ENABLE_BORDER_AGENT +// This is for delaying publishing the MeshCoP service until the correct +// vendor name and OUI etc. are correctly set by BorderAgent::SetMeshCopServiceValues() +#if OTBR_STOP_BORDER_AGENT_ON_INIT + mBorderAgent->SetEnabled(false); +#else + mBorderAgent->SetEnabled(true); +#endif +#endif +#if OTBR_ENABLE_BACKBONE_ROUTER + mBackboneAgent->Init(); +#endif +#if OTBR_ENABLE_SRP_ADVERTISING_PROXY + mAdvertisingProxy->SetEnabled(true); +#endif +#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY + mDiscoveryProxy->SetEnabled(true); +#endif +#if OTBR_ENABLE_OPENWRT + mUbusAgent->Init(); +#endif +#if OTBR_ENABLE_REST_SERVER + mRestWebServer->Init(); +#endif +#if OTBR_ENABLE_DBUS_SERVER + mDBusAgent->Init(*mBorderAgent); +#endif +#if OTBR_ENABLE_VENDOR_SERVER + mVendorServer->Init(); +#endif +} + +void Application::DeinitRcpMode(void) +{ +#if OTBR_ENABLE_SRP_ADVERTISING_PROXY + mAdvertisingProxy->SetEnabled(false); +#endif +#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY + mDiscoveryProxy->SetEnabled(false); +#endif +#if OTBR_ENABLE_BORDER_AGENT + mBorderAgent->SetEnabled(false); +#endif +#if OTBR_ENABLE_MDNS + mPublisher->Stop(); +#endif +} + +void Application::InitNcpMode(void) +{ +#if OTBR_ENABLE_DBUS_SERVER + mDBusAgent->Init(*mBorderAgent); +#endif +} + +void Application::DeinitNcpMode(void) +{ + /* empty */ +} + } // namespace otbr diff --git a/src/agent/application.hpp b/src/agent/application.hpp index 7ec58a36cba..92b44ef1580 100644 --- a/src/agent/application.hpp +++ b/src/agent/application.hpp @@ -83,7 +83,6 @@ class VendorServer; /** * This class implements OTBR application management. - * */ class Application : private NonCopyable { @@ -97,7 +96,6 @@ class Application : private NonCopyable * @param[in] aEnableAutoAttach Whether or not to automatically attach to the saved network. * @param[in] aRestListenAddress Network address to listen on. * @param[in] aRestListenPort Network port to listen on. - * */ explicit Application(const std::string &aInterfaceName, const std::vector &aBackboneInterfaceNames, @@ -108,13 +106,11 @@ class Application : private NonCopyable /** * This method initializes the Application instance. - * */ void Init(void); /** * This method de-initializes the Application instance. - * */ void Deinit(void); @@ -123,7 +119,6 @@ class Application : private NonCopyable * * @retval OTBR_ERROR_NONE The application exited without any error. * @retval OTBR_ERROR_ERRNO The application exited with some system error. - * */ otbrError Run(void); @@ -132,7 +127,7 @@ class Application : private NonCopyable * * @returns The OpenThread controller object. */ - Ncp::RcpHost &GetNcp(void) { return *mHost; } + Ncp::ThreadHost &GetHost(void) { return *mHost; } #if OTBR_ENABLE_MDNS /** @@ -246,7 +241,6 @@ class Application : private NonCopyable * This method handles mDNS publisher's state changes. * * @param[in] aState The state of mDNS publisher. - * */ void HandleMdnsState(Mdns::Publisher::State aState); @@ -256,12 +250,19 @@ class Application : private NonCopyable static void HandleSignal(int aSignal); + void CreateRcpMode(const std::string &aRestListenAddress, int aRestListenPort); + void InitRcpMode(void); + void DeinitRcpMode(void); + + void InitNcpMode(void); + void DeinitNcpMode(void); + std::string mInterfaceName; #if __linux__ otbr::Utils::InfraLinkSelector mInfraLinkSelector; #endif - const char *mBackboneInterfaceName; - std::unique_ptr mHost; + const char *mBackboneInterfaceName; + std::unique_ptr mHost; #if OTBR_ENABLE_MDNS std::unique_ptr mPublisher; #endif diff --git a/src/agent/main.cpp b/src/agent/main.cpp index 0fc78c45b6a..e47c96439e5 100644 --- a/src/agent/main.cpp +++ b/src/agent/main.cpp @@ -31,10 +31,6 @@ #include #include -#include -#include -#include -#include #include #include @@ -47,7 +43,7 @@ #include #include -#if __ANDROID__ && OTBR_CONFIG_ANDROID_PROPERTY_ENABLE +#if OTBR_ENABLE_PLATFORM_ANDROID #include #endif @@ -56,7 +52,13 @@ #include "common/logging.hpp" #include "common/mainloop.hpp" #include "common/types.hpp" -#include "ncp/rcp_host.hpp" +#include "ncp/thread_host.hpp" + +#ifdef OTBR_ENABLE_PLATFORM_ANDROID +#ifndef __ANDROID__ +#error "OTBR_ENABLE_PLATFORM_ANDROID can be enabled for only Android devices" +#endif +#endif static const char kDefaultInterfaceName[] = "wpan0"; @@ -79,7 +81,7 @@ enum OTBR_OPT_REST_LISTEN_PORT, }; -#ifndef __ANDROID__ +#ifndef OTBR_ENABLE_PLATFORM_ANDROID static jmp_buf sResetJump; #endif static otbr::Application *gApp = nullptr; @@ -117,6 +119,7 @@ static bool ParseInteger(const char *aStr, long &aOutResult) return successful; } +#ifndef OTBR_ENABLE_PLATFORM_ANDROID static constexpr char kAutoAttachDisableArg[] = "--auto-attach=0"; static char sAutoAttachDisableArgStorage[sizeof(kAutoAttachDisableArg)]; @@ -134,6 +137,7 @@ static std::vector AppendAutoAttachDisableArg(int argc, char *argv[]) return args; } +#endif static void PrintHelp(const char *aProgramName) { @@ -161,7 +165,7 @@ static otbrLogLevel GetDefaultLogLevel(void) { otbrLogLevel level = OTBR_LOG_INFO; -#if __ANDROID__ && OTBR_CONFIG_ANDROID_PROPERTY_ENABLE +#if OTBR_ENABLE_PLATFORM_ANDROID char value[PROPERTY_VALUE_MAX]; property_get("ro.build.type", value, "user"); @@ -176,18 +180,18 @@ static otbrLogLevel GetDefaultLogLevel(void) static void PrintRadioVersionAndExit(const std::vector &aRadioUrls) { - otbr::Ncp::RcpHost rcpHost{/* aInterfaceName */ "", aRadioUrls, - /* aBackboneInterfaceName */ "", - /* aDryRun */ true, /* aEnableAutoAttach */ false}; - const char *radioVersion; + auto host = std::unique_ptr( + otbr::Ncp::ThreadHost::Create(/* aInterfaceName */ "", aRadioUrls, + /* aBackboneInterfaceName */ "", + /* aDryRun */ true, /* aEnableAutoAttach */ false)); + const char *coprocessorVersion; - rcpHost.Init(); + host->Init(); - radioVersion = otPlatRadioGetVersionString(rcpHost.GetInstance()); - otbrLogNotice("Radio version: %s", radioVersion); - printf("%s\n", radioVersion); + coprocessorVersion = host->GetCoprocessorVersion(); + printf("%s\n", coprocessorVersion); - rcpHost.Deinit(); + host->Deinit(); exit(EXIT_SUCCESS); } @@ -328,7 +332,7 @@ void otPlatReset(otInstance *aInstance) gApp->Deinit(); gApp = nullptr; -#ifndef __ANDROID__ +#ifndef OTBR_ENABLE_PLATFORM_ANDROID longjmp(sResetJump, 1); assert(false); #else @@ -340,7 +344,7 @@ void otPlatReset(otInstance *aInstance) int main(int argc, char *argv[]) { -#ifndef __ANDROID__ +#ifndef OTBR_ENABLE_PLATFORM_ANDROID if (setjmp(sResetJump)) { std::vector args = AppendAutoAttachDisableArg(argc, argv); diff --git a/src/agent/uris.hpp b/src/agent/uris.hpp index 9fe79c1a3d7..632fc9f2e12 100644 --- a/src/agent/uris.hpp +++ b/src/agent/uris.hpp @@ -38,7 +38,6 @@ namespace otbr { /** * The URI Path for Address Query. - * */ #define OT_URI_PATH_ADDRESS_QUERY "a/aq" @@ -46,7 +45,6 @@ namespace otbr { * @def OT_URI_PATH_ADDRESS_NOTIFY * * The URI Path for Address Notify. - * */ #define OT_URI_PATH_ADDRESS_NOTIFY "a/an" @@ -54,7 +52,6 @@ namespace otbr { * @def OT_URI_PATH_ADDRESS_ERROR * * The URI Path for Address Error. - * */ #define OT_URI_PATH_ADDRESS_ERROR "a/ae" @@ -62,7 +59,6 @@ namespace otbr { * @def OT_URI_PATH_ADDRESS_RELEASE * * The URI Path for Address Release. - * */ #define OT_URI_PATH_ADDRESS_RELEASE "a/ar" @@ -70,7 +66,6 @@ namespace otbr { * @def OT_URI_PATH_ADDRESS_SOLICIT * * The URI Path for Address Solicit. - * */ #define OT_URI_PATH_ADDRESS_SOLICIT "a/as" @@ -78,7 +73,6 @@ namespace otbr { * @def OT_URI_PATH_ACTIVE_GET * * The URI Path for MGMT_ACTIVE_GET - * */ #define OT_URI_PATH_ACTIVE_GET "c/ag" @@ -86,7 +80,6 @@ namespace otbr { * @def OT_URI_PATH_ACTIVE_SET * * The URI Path for MGMT_ACTIVE_SET - * */ #define OT_URI_PATH_ACTIVE_SET "c/as" @@ -94,7 +87,6 @@ namespace otbr { * @def OT_URI_PATH_DATASET_CHANGED * * The URI Path for MGMT_DATASET_CHANGED - * */ #define OT_URI_PATH_DATASET_CHANGED "c/dc" @@ -102,7 +94,6 @@ namespace otbr { * @def OT_URI_PATH_ENERGY_SCAN * * The URI Path for Energy Scan - * */ #define OT_URI_PATH_ENERGY_SCAN "c/es" @@ -110,7 +101,6 @@ namespace otbr { * @def OT_URI_PATH_ENERGY_REPORT * * The URI Path for Energy Report - * */ #define OT_URI_PATH_ENERGY_REPORT "c/er" @@ -118,7 +108,6 @@ namespace otbr { * @def OT_URI_PATH_PENDING_GET * * The URI Path for MGMT_PENDING_GET - * */ #define OT_URI_PATH_PENDING_GET "c/pg" @@ -126,7 +115,6 @@ namespace otbr { * @def OT_URI_PATH_PENDING_SET * * The URI Path for MGMT_PENDING_SET - * */ #define OT_URI_PATH_PENDING_SET "c/ps" @@ -134,7 +122,6 @@ namespace otbr { * @def OT_URI_PATH_SERVER_DATA * * The URI Path for Server Data Registration. - * */ #define OT_URI_PATH_SERVER_DATA "a/sd" @@ -142,7 +129,6 @@ namespace otbr { * @def OT_URI_PATH_ANNOUNCE_BEGIN * * The URI Path for Announce Begin. - * */ #define OT_URI_PATH_ANNOUNCE_BEGIN "c/ab" @@ -150,7 +136,6 @@ namespace otbr { * @def OT_URI_PATH_RELAY_RX * * The URI Path for Relay RX. - * */ #define OT_URI_PATH_RELAY_RX "c/rx" @@ -158,7 +143,6 @@ namespace otbr { * @def OT_URI_PATH_RELAY_TX * * The URI Path for Relay TX. - * */ #define OT_URI_PATH_RELAY_TX "c/tx" @@ -166,7 +150,6 @@ namespace otbr { * @def OT_URI_PATH_JOINER_FINALIZE * * The URI Path for Joiner Finalize - * */ #define OT_URI_PATH_JOINER_FINALIZE "c/jf" @@ -174,7 +157,6 @@ namespace otbr { * @def OT_URI_PATH_JOINER_ENTRUST * * The URI Path for Joiner Entrust - * */ #define OT_URI_PATH_JOINER_ENTRUST "c/je" @@ -182,7 +164,6 @@ namespace otbr { * @def OT_URI_PATH_LEADER_PETITION * * The URI Path for Leader Petition - * */ #define OT_URI_PATH_LEADER_PETITION "c/lp" @@ -190,7 +171,6 @@ namespace otbr { * @def OT_URI_PATH_LEADER_KEEP_ALIVE * * The URI Path for Leader Keep Alive - * */ #define OT_URI_PATH_LEADER_KEEP_ALIVE "c/la" @@ -198,7 +178,6 @@ namespace otbr { * @def OT_URI_PATH_PANID_CONFLICT * * The URI Path for PAN ID Conflict - * */ #define OT_URI_PATH_PANID_CONFLICT "c/pc" @@ -206,7 +185,6 @@ namespace otbr { * @def OT_URI_PATH_PANID_QUERY * * The URI Path for PAN ID Query - * */ #define OT_URI_PATH_PANID_QUERY "c/pq" @@ -214,7 +192,6 @@ namespace otbr { * @def OT_URI_PATH_COMMISSIONER_GET * * The URI Path for MGMT_COMMISSIONER_GET - * */ #define OT_URI_PATH_COMMISSIONER_GET "c/cg" @@ -222,7 +199,6 @@ namespace otbr { * @def OT_URI_PATH_COMMISSIONER_SET * * The URI Path for MGMT_COMMISSIONER_SET - * */ #define OT_URI_PATH_COMMISSIONER_SET "c/cs" @@ -230,7 +206,6 @@ namespace otbr { * @def OT_URI_PATH_COMMISSIONER_PETITION * * The URI Path for Commissioner Petition. - * */ #define OT_URI_PATH_COMMISSIONER_PETITION "c/cp" @@ -238,7 +213,6 @@ namespace otbr { * @def OT_URI_PATH_COMMISSIONER_KEEP_ALIVE * * The URI Path for Commissioner Keep Alive. - * */ #define OT_URI_PATH_COMMISSIONER_KEEP_ALIVE "c/ca" @@ -246,7 +220,6 @@ namespace otbr { * @def OT_URI_PATH_DIAGNOSTIC_GET_REQUEST * * The URI Path for Network Diagnostic Get Request. - * */ #define OT_URI_PATH_DIAGNOSTIC_GET_REQUEST "d/dg" @@ -254,7 +227,6 @@ namespace otbr { * @def OT_URI_PATH_DIAGNOSTIC_GET_QUERY * * The URI Path for Network Diagnostic Get Query. - * */ #define OT_URI_PATH_DIAGNOSTIC_GET_QUERY "d/dq" @@ -262,7 +234,6 @@ namespace otbr { * @def OT_URI_PATH_DIAGNOSTIC_GET_ANSWER * * The URI Path for Network Diagnostic Get Answer. - * */ #define OT_URI_PATH_DIAGNOSTIC_GET_ANSWER "d/da" @@ -270,7 +241,6 @@ namespace otbr { * @def OT_URI_PATH_DIAG_RST * * The URI Path for Network Diagnostic Reset. - * */ #define OT_URI_PATH_DIAGNOSTIC_RESET "d/dr" diff --git a/src/backbone_router/backbone_agent.hpp b/src/backbone_router/backbone_agent.hpp index 67cb4a150f8..9f1d1884a72 100644 --- a/src/backbone_router/backbone_agent.hpp +++ b/src/backbone_router/backbone_agent.hpp @@ -63,7 +63,6 @@ namespace BackboneRouter { /** * This class implements Thread Backbone agent functionality. - * */ class BackboneAgent : private NonCopyable { @@ -74,13 +73,11 @@ class BackboneAgent : private NonCopyable * This constructor intiializes the `BackboneAgent` instance. * * @param[in] aHost The Thread controller instance. - * */ BackboneAgent(otbr::Ncp::RcpHost &aHost, std::string aInterfaceName, std::string aBackboneInterfaceName); /** * This method initializes the Backbone agent. - * */ void Init(void); diff --git a/src/backbone_router/constants.hpp b/src/backbone_router/constants.hpp index 363e34c3df8..245710cd5fe 100644 --- a/src/backbone_router/constants.hpp +++ b/src/backbone_router/constants.hpp @@ -50,7 +50,6 @@ namespace BackboneRouter { /** * Backbone configurations. - * */ enum { diff --git a/src/backbone_router/dua_routing_manager.hpp b/src/backbone_router/dua_routing_manager.hpp index bb4c929c736..54d76998a99 100644 --- a/src/backbone_router/dua_routing_manager.hpp +++ b/src/backbone_router/dua_routing_manager.hpp @@ -60,14 +60,12 @@ namespace BackboneRouter { /** * This class implements the DUA routing manager. - * */ class DuaRoutingManager : private NonCopyable { public: /** * This constructor initializes a DUA routing manager instance. - * */ explicit DuaRoutingManager(std::string aInterfaceName, std::string aBackboneInterfaceName) : mEnabled(false) @@ -78,13 +76,11 @@ class DuaRoutingManager : private NonCopyable /** * This method enables the DUA routing manager. - * */ void Enable(const Ip6Prefix &aDomainPrefix); /** * This method disables the DUA routing manager. - * */ void Disable(void); diff --git a/src/backbone_router/nd_proxy.cpp b/src/backbone_router/nd_proxy.cpp index d42e7d7e874..fdc19615899 100644 --- a/src/backbone_router/nd_proxy.cpp +++ b/src/backbone_router/nd_proxy.cpp @@ -121,14 +121,12 @@ void NdProxyManager::Update(MainloopContext &aMainloop) { if (mIcmp6RawSock >= 0) { - FD_SET(mIcmp6RawSock, &aMainloop.mReadFdSet); - aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, mIcmp6RawSock); + aMainloop.AddFdToReadSet(mIcmp6RawSock); } if (mUnicastNsQueueSock >= 0) { - FD_SET(mUnicastNsQueueSock, &aMainloop.mReadFdSet); - aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, mUnicastNsQueueSock); + aMainloop.AddFdToReadSet(mUnicastNsQueueSock); } } diff --git a/src/backbone_router/nd_proxy.hpp b/src/backbone_router/nd_proxy.hpp index 92823c75c28..1a6690cb563 100644 --- a/src/backbone_router/nd_proxy.hpp +++ b/src/backbone_router/nd_proxy.hpp @@ -71,14 +71,12 @@ namespace BackboneRouter { /** * This class implements ND Proxy manager. - * */ class NdProxyManager : public MainloopProcessor, private NonCopyable { public: /** * This constructor initializes a NdProxyManager instance. - * */ explicit NdProxyManager(otbr::Ncp::RcpHost &aHost, std::string aBackboneInterfaceName) : mHost(aHost) @@ -92,7 +90,6 @@ class NdProxyManager : public MainloopProcessor, private NonCopyable /** * This method initializes a ND Proxy manager instance. - * */ void Init(void); @@ -100,13 +97,11 @@ class NdProxyManager : public MainloopProcessor, private NonCopyable * This method enables the ND Proxy manager. * * @param[in] aDomainPrefix The Domain Prefix. - * */ void Enable(const Ip6Prefix &aDomainPrefix); /** * This method disables the ND Proxy manager. - * */ void Disable(void); @@ -119,7 +114,6 @@ class NdProxyManager : public MainloopProcessor, private NonCopyable * @param[in] aEvent The Backbone Router ND Proxy event type. * @param[in] aDua The Domain Unicast Address of the ND Proxy, or `nullptr` if @p `aEvent` is * `OT_BACKBONE_ROUTER_NDPROXY_CLEARED`. - * */ void HandleBackboneRouterNdProxyEvent(otBackboneRouterNdProxyEvent aEvent, const otIp6Address *aDua); @@ -127,7 +121,6 @@ class NdProxyManager : public MainloopProcessor, private NonCopyable * This method returns if the ND Proxy manager is enabled. * * @returns If the ND Proxy manager is enabled; - * */ bool IsEnabled(void) const { return mIcmp6RawSock >= 0; } diff --git a/src/border_agent/border_agent.cpp b/src/border_agent/border_agent.cpp index 88933ee47bc..47283972a07 100644 --- a/src/border_agent/border_agent.cpp +++ b/src/border_agent/border_agent.cpp @@ -50,8 +50,11 @@ #include #include +#include #include +#include #include +#include #include #include @@ -67,15 +70,19 @@ #include "common/types.hpp" #include "utils/hex.hpp" +#if !(OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO) +#error "Border Agent feature requires at least one `OTBR_MDNS` implementation" +#endif + namespace otbr { static const char kBorderAgentServiceType[] = "_meshcop._udp"; ///< Border agent service type of mDNS static const char kBorderAgentEpskcServiceType[] = "_meshcop-e._udp"; ///< Border agent ePSKc service static constexpr int kBorderAgentServiceDummyPort = 49152; +static constexpr int kEpskcRandomGenLen = 8; /** * Locators - * */ enum { @@ -99,6 +106,14 @@ enum : uint8_t kThreadIfStatusActive = 2, }; +enum : uint8_t +{ + kThreadRoleDisabledOrDetached = 0, + kThreadRoleChild = 1, + kThreadRoleRouter = 2, + kThreadRoleLeader = 3, +}; + enum : uint8_t { kAvailabilityInfrequent = 0, @@ -112,6 +127,7 @@ struct StateBitmap uint32_t mAvailability : 2; uint32_t mBbrIsActive : 1; uint32_t mBbrIsPrimary : 1; + uint32_t mThreadRole : 2; uint32_t mEpskcSupported : 1; StateBitmap(void) @@ -120,7 +136,8 @@ struct StateBitmap , mAvailability(0) , mBbrIsActive(0) , mBbrIsPrimary(0) - , mEpskcSupported(OTBR_ENABLE_EPSKC) + , mThreadRole(kThreadRoleDisabledOrDetached) + , mEpskcSupported(0) { } @@ -133,6 +150,7 @@ struct StateBitmap bitmap |= mAvailability << 5; bitmap |= mBbrIsActive << 7; bitmap |= mBbrIsPrimary << 8; + bitmap |= mThreadRole << 9; bitmap |= mEpskcSupported << 11; return bitmap; } @@ -142,11 +160,40 @@ BorderAgent::BorderAgent(otbr::Ncp::RcpHost &aHost, Mdns::Publisher &aPublisher) : mHost(aHost) , mPublisher(aPublisher) , mIsEnabled(false) + , mIsEphemeralKeyEnabled(otThreadGetVersion() >= OT_THREAD_VERSION_1_4) , mVendorName(OTBR_VENDOR_NAME) , mProductName(OTBR_PRODUCT_NAME) , mBaseServiceInstanceName(OTBR_MESHCOP_SERVICE_INSTANCE_NAME) { mHost.AddThreadStateChangedCallback([this](otChangedFlags aFlags) { HandleThreadStateChanged(aFlags); }); + otbrLogInfo("Ephemeral Key is: %s during initialization", (mIsEphemeralKeyEnabled ? "enabled" : "disabled")); +} + +otbrError BorderAgent::CreateEphemeralKey(std::string &aEphemeralKey) +{ + std::string digitString; + char checksum; + uint8_t candidateBuffer[1]; + otbrError error = OTBR_ERROR_NONE; + + for (uint8_t i = 0; i < kEpskcRandomGenLen; ++i) + { + while (true) + { + SuccessOrExit(otRandomCryptoFillBuffer(candidateBuffer, 1), error = OTBR_ERROR_ABORTED); + // Generates a random number in the range [0, 9] with equal probability. + if (candidateBuffer[0] < 250) + { + digitString += static_cast('0' + candidateBuffer[0] % 10); + break; + } + } + } + SuccessOrExit(otVerhoeffChecksumCalculate(digitString.c_str(), &checksum), error = OTBR_ERROR_INVALID_ARGS); + aEphemeralKey = digitString + checksum; + +exit: + return error; } otbrError BorderAgent::SetMeshCopServiceValues(const std::string &aServiceInstanceName, @@ -196,6 +243,25 @@ void BorderAgent::SetEnabled(bool aIsEnabled) return; } +void BorderAgent::SetEphemeralKeyEnabled(bool aIsEnabled) +{ + VerifyOrExit(GetEphemeralKeyEnabled() != aIsEnabled); + mIsEphemeralKeyEnabled = aIsEnabled; + + if (!mIsEphemeralKeyEnabled) + { + // If the ePSKc feature is enabled, we call the clear function which + // will wait for the session to close if it is in active use before + // removing ephemeral key and unpublishing the service. + otBorderAgentClearEphemeralKey(mHost.GetInstance()); + } + + UpdateMeshCopService(); + +exit: + return; +} + void BorderAgent::Start(void) { otbrLogInfo("Start Thread Border Agent"); @@ -236,6 +302,11 @@ void BorderAgent::HandleEpskcStateChanged(void *aContext) { borderAgent->UnpublishEpskcService(); } + + for (auto &ephemeralKeyCallback : borderAgent->mEphemeralKeyChangedCallbacks) + { + ephemeralKeyCallback(); + } } void BorderAgent::PublishEpskcService() @@ -285,6 +356,11 @@ void BorderAgent::UnpublishEpskcService() }); } +void BorderAgent::AddEphemeralKeyChangedCallback(EphemeralKeyChangedCallback aCallback) +{ + mEphemeralKeyChangedCallbacks.push_back(std::move(aCallback)); +} + void BorderAgent::HandleMdnsState(Mdns::Publisher::State aState) { VerifyOrExit(IsEnabled()); @@ -341,12 +417,24 @@ StateBitmap GetStateBitmap(otInstance &aInstance) { case OT_DEVICE_ROLE_DISABLED: state.mThreadIfStatus = kThreadIfStatusNotInitialized; + state.mThreadRole = kThreadRoleDisabledOrDetached; break; case OT_DEVICE_ROLE_DETACHED: state.mThreadIfStatus = kThreadIfStatusInitialized; + state.mThreadRole = kThreadRoleDisabledOrDetached; break; - default: + case OT_DEVICE_ROLE_CHILD: state.mThreadIfStatus = kThreadIfStatusActive; + state.mThreadRole = kThreadRoleChild; + break; + case OT_DEVICE_ROLE_ROUTER: + state.mThreadIfStatus = kThreadIfStatusActive; + state.mThreadRole = kThreadRoleRouter; + break; + case OT_DEVICE_ROLE_LEADER: + state.mThreadIfStatus = kThreadIfStatusActive; + state.mThreadRole = kThreadRoleLeader; + break; } #if OTBR_ENABLE_BACKBONE_ROUTER @@ -472,9 +560,9 @@ void BorderAgent::PublishMeshCopService(void) // "xa" stands for Extended MAC Address (64-bit) of the Thread Interface of the Border Agent. txtList.emplace_back("xa", extAddr->m8, sizeof(extAddr->m8)); - - state = GetStateBitmap(*instance); - stateUint32 = htobe32(state.ToUint32()); + state = GetStateBitmap(*instance); + state.mEpskcSupported = GetEphemeralKeyEnabled(); + stateUint32 = htobe32(state.ToUint32()); txtList.emplace_back("sb", reinterpret_cast(&stateUint32), sizeof(stateUint32)); if (state.mThreadIfStatus == kThreadIfStatusActive) @@ -587,7 +675,7 @@ void BorderAgent::HandleThreadStateChanged(otChangedFlags aFlags) bool BorderAgent::IsThreadStarted(void) const { - otDeviceRole role = otThreadGetDeviceRole(mHost.GetInstance()); + otDeviceRole role = mHost.GetDeviceRole(); return role == OT_DEVICE_ROLE_CHILD || role == OT_DEVICE_ROLE_ROUTER || role == OT_DEVICE_ROLE_LEADER; } diff --git a/src/border_agent/border_agent.hpp b/src/border_agent/border_agent.hpp index 58f84a058a9..ed9686f4c3f 100644 --- a/src/border_agent/border_agent.hpp +++ b/src/border_agent/border_agent.hpp @@ -36,10 +36,6 @@ #include "openthread-br/config.h" -#if !(OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO) -#error "Border Agent feature requires at least one `OTBR_MDNS` implementation" -#endif - #include #include @@ -78,17 +74,18 @@ namespace otbr { /** * This class implements Thread border agent functionality. - * */ class BorderAgent : private NonCopyable { public: + /** The callback for receiving ephemeral key changes. */ + using EphemeralKeyChangedCallback = std::function; + /** * The constructor to initialize the Thread border agent. * * @param[in] aHost A reference to the Thread controller. * @param[in] aPublisher A reference to the mDNS Publisher. - * */ BorderAgent(otbr::Ncp::RcpHost &aHost, Mdns::Publisher &aPublisher); @@ -122,18 +119,46 @@ class BorderAgent : private NonCopyable * This method enables/disables the Border Agent. * * @param[in] aIsEnabled Whether to enable the Border Agent. - * */ void SetEnabled(bool aIsEnabled); + /** + * This method enables/disables the Border Agent Ephemeral Key feature. + * + * @param[in] aIsEnabled Whether to enable the BA Ephemeral Key feature. + */ + void SetEphemeralKeyEnabled(bool aIsEnabled); + + /** + * This method returns the Border Agent Ephemeral Key feature state. + */ + bool GetEphemeralKeyEnabled(void) const { return mIsEphemeralKeyEnabled; } + /** * This method handles mDNS publisher's state changes. * * @param[in] aState The state of mDNS publisher. - * */ void HandleMdnsState(Mdns::Publisher::State aState); + /** + * This method creates ephemeral key in the Border Agent. + * + * @param[out] aEphemeralKey The ephemeral key digit string of length 9 with first 8 digits randomly + * generated, and the last 9th digit as verhoeff checksum. + * + * @returns OTBR_ERROR_INVALID_ARGS If Verhoeff checksum calculate returns error. + * @returns OTBR_ERROR_NONE If successfully generate the ePSKc. + */ + static otbrError CreateEphemeralKey(std::string &aEphemeralKey); + + /** + * This method adds a callback for ephemeral key changes. + * + * @param[in] aCallback The callback to receive ephemeral key changed events. + */ + void AddEphemeralKeyChangedCallback(EphemeralKeyChangedCallback aCallback); + private: void Start(void); void Stop(void); @@ -158,6 +183,7 @@ class BorderAgent : private NonCopyable otbr::Ncp::RcpHost &mHost; Mdns::Publisher &mPublisher; bool mIsEnabled; + bool mIsEphemeralKeyEnabled; std::map> mMeshCopTxtUpdate; @@ -176,6 +202,8 @@ class BorderAgent : private NonCopyable // conflicts. For example, this value can be "OpenThread Border Router #7AC3" or // "OpenThread Border Router #7AC3 (14379)". std::string mServiceInstanceName; + + std::vector mEphemeralKeyChangedCallbacks; }; /** diff --git a/src/common/api_strings.cpp b/src/common/api_strings.cpp index fcb429f75be..77fee9231c9 100644 --- a/src/common/api_strings.cpp +++ b/src/common/api_strings.cpp @@ -53,3 +53,25 @@ std::string GetDeviceRoleName(otDeviceRole aRole) return roleName; } + +#if OTBR_ENABLE_DHCP6_PD +std::string GetDhcp6PdStateName(otBorderRoutingDhcp6PdState aState) +{ + std::string stateName; + + switch (aState) + { + case OT_BORDER_ROUTING_DHCP6_PD_STATE_DISABLED: + stateName = OTBR_DHCP6_PD_STATE_NAME_DISABLED; + break; + case OT_BORDER_ROUTING_DHCP6_PD_STATE_STOPPED: + stateName = OTBR_DHCP6_PD_STATE_NAME_STOPPED; + break; + case OT_BORDER_ROUTING_DHCP6_PD_STATE_RUNNING: + stateName = OTBR_DHCP6_PD_STATE_NAME_RUNNING; + break; + } + + return stateName; +} +#endif // OTBR_ENABLE_DHCP6_PD diff --git a/src/common/api_strings.hpp b/src/common/api_strings.hpp index 8b1eb9fcd8f..7093e049772 100644 --- a/src/common/api_strings.hpp +++ b/src/common/api_strings.hpp @@ -30,7 +30,6 @@ * @file * This file has helper functions to convert internal state representations * to string (useful for APIs). - * */ #ifndef OTBR_COMMON_API_STRINGS_HPP_ #define OTBR_COMMON_API_STRINGS_HPP_ @@ -39,6 +38,7 @@ #include +#include #include #define OTBR_ROLE_NAME_DISABLED "disabled" @@ -47,6 +47,16 @@ #define OTBR_ROLE_NAME_ROUTER "router" #define OTBR_ROLE_NAME_LEADER "leader" +#if OTBR_ENABLE_DHCP6_PD +#define OTBR_DHCP6_PD_STATE_NAME_DISABLED "disabled" +#define OTBR_DHCP6_PD_STATE_NAME_STOPPED "stopped" +#define OTBR_DHCP6_PD_STATE_NAME_RUNNING "running" +#endif + std::string GetDeviceRoleName(otDeviceRole aRole); +#if OTBR_ENABLE_DHCP6_PD +std::string GetDhcp6PdStateName(otBorderRoutingDhcp6PdState aDhcp6PdState); +#endif // OTBR_ENABLE_DHCP6_PD + #endif // OTBR_COMMON_API_STRINGS_HPP_ diff --git a/src/common/callback.hpp b/src/common/callback.hpp index 7df19e5d53c..3af21d35c67 100644 --- a/src/common/callback.hpp +++ b/src/common/callback.hpp @@ -51,7 +51,6 @@ template class OnceCallback; * * Inspired by Chromium base::OnceCallback * (https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main/base/callback.h). - * */ template class OnceCallback { diff --git a/src/common/code_utils.hpp b/src/common/code_utils.hpp index 87791a2b8ff..f6d2620faf2 100644 --- a/src/common/code_utils.hpp +++ b/src/common/code_utils.hpp @@ -52,7 +52,6 @@ * @param[in] aAlignType The type to align with and convert the pointer to this type. * * @returns A pointer to aligned memory. - * */ #define OTBR_ALIGNED(aMem, aAlignType) \ reinterpret_cast( \ @@ -74,7 +73,6 @@ * the status is unsuccessful. * * @param[in] aStatus A scalar status to be evaluated against zero (0). - * */ #define SuccessOrExit(aStatus, ...) \ do \ @@ -92,7 +90,6 @@ * * @param[in] aStatus A scalar error status to be evaluated against zero (0). * @param[in] aMessage A message (text string) to print on failure. - * */ #define SuccessOrDie(aStatus, aMessage) \ do \ @@ -112,7 +109,6 @@ * @param[in] aCondition A Boolean expression to be evaluated. * @param[in] ... An expression or block to execute when the * assertion fails. - * */ #define VerifyOrExit(aCondition, ...) \ do \ @@ -130,7 +126,6 @@ * * @param[in] aCondition The condition to verify * @param[in] aMessage A message (text string) to print on failure. - * */ #define VerifyOrDie(aCondition, aMessage) \ do \ @@ -142,6 +137,18 @@ } \ } while (false) +/** + * This macro prints the message and terminates the program. + * + * @param[in] aMessage A message (text string) to print. + */ +#define DieNow(aMessage) \ + do \ + { \ + otbrLogEmerg("FAILED %s:%d - %s", __FILE__, __LINE__, aMessage); \ + exit(-1); \ + } while (false) + /** * This unconditionally executes @a ... and branches to the local * label 'exit'. @@ -152,7 +159,6 @@ * * @param[in] ... An optional expression or block to execute * when the assertion fails. - * */ #define ExitNow(...) \ do \ @@ -179,7 +185,6 @@ 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. - * */ class NonCopyable { diff --git a/src/common/dns_utils.hpp b/src/common/dns_utils.hpp index 13d8e8c285f..4645369cccb 100644 --- a/src/common/dns_utils.hpp +++ b/src/common/dns_utils.hpp @@ -29,7 +29,6 @@ /** * @file * This file includes DNS utilities. - * */ #ifndef OTBR_COMMON_DNS_UTILS_HPP_ #define OTBR_COMMON_DNS_UTILS_HPP_ @@ -42,7 +41,6 @@ * This structure represents DNS Name information. * * @sa SplitFullDnsName - * */ struct DnsNameInfo { @@ -55,7 +53,6 @@ struct DnsNameInfo * This method returns if the DNS name is a service instance. * * @returns Whether the DNS name is a service instance. - * */ bool IsServiceInstance(void) const { return !mInstanceName.empty(); }; @@ -63,7 +60,6 @@ struct DnsNameInfo * This method returns if the DNS name is a service. * * @returns Whether the DNS name is a service. - * */ bool IsService(void) const { return !mServiceName.empty() && mInstanceName.empty(); } @@ -71,7 +67,6 @@ struct DnsNameInfo * This method returns if the DNS name is a host. * * @returns Whether the DNS name is a host. - * */ bool IsHost(void) const { return mServiceName.empty(); } }; @@ -84,7 +79,6 @@ struct DnsNameInfo * @returns A `DnsNameInfo` structure containing DNS name information. * * @sa DnsNameInfo - * */ DnsNameInfo SplitFullDnsName(const std::string &aName); @@ -97,7 +91,6 @@ DnsNameInfo SplitFullDnsName(const std::string &aName); * * @retval OTBR_ERROR_NONE Successfully split the full service name. * @retval OTBR_ERROR_INVALID_ARGS If the full service name is not valid. - * */ otbrError SplitFullServiceName(const std::string &aFullName, std::string &aType, std::string &aDomain); @@ -111,7 +104,6 @@ otbrError SplitFullServiceName(const std::string &aFullName, std::string &aType, * * @retval OTBR_ERROR_NONE Successfully split the full service instance name. * @retval OTBR_ERROR_INVALID_ARGS If the full service instance name is not valid. - * */ otbrError SplitFullServiceInstanceName(const std::string &aFullName, std::string &aInstanceName, @@ -127,7 +119,6 @@ otbrError SplitFullServiceInstanceName(const std::string &aFullName, * * @retval OTBR_ERROR_NONE Successfully split the full host name. * @retval OTBR_ERROR_INVALID_ARGS If the full host name is not valid. - * */ otbrError SplitFullHostName(const std::string &aFullName, std::string &aHostName, std::string &aDomain); diff --git a/src/common/logging.hpp b/src/common/logging.hpp index ad36d4f5682..7015b8d2dca 100644 --- a/src/common/logging.hpp +++ b/src/common/logging.hpp @@ -46,7 +46,6 @@ /** * Logging level. - * */ typedef enum { @@ -79,7 +78,6 @@ void otbrLogSetLevel(otbrLogLevel aLevel); * Control log to syslog. * * @param[in] aEnabled True to enable logging to/via syslog. - * */ void otbrLogSyslogSetEnabled(bool aEnabled); @@ -90,7 +88,6 @@ void otbrLogSyslogSetEnabled(bool aEnabled); * @param[in] aLevel Log level of the logger. * @param[in] aPrintStderr Whether to log to stderr. * @param[in] aSyslogDisable Whether to disable logging to syslog. - * */ void otbrLogInit(const char *aProgramName, otbrLogLevel aLevel, bool aPrintStderr, bool aSyslogDisable); @@ -100,7 +97,6 @@ void otbrLogInit(const char *aProgramName, otbrLogLevel aLevel, bool aPrintStder * @param[in] aLevel Log level of the logger. * @param[in] aLogTag Log tag. * @param[in] aFormat Format string as in printf. - * */ void otbrLog(otbrLogLevel aLevel, const char *aLogTag, const char *aFormat, ...); @@ -110,7 +106,6 @@ void otbrLog(otbrLogLevel aLevel, const char *aLogTag, const char *aFormat, ...) * @param[in] aLevel Log level of the logger. * @param[in] aFormat Format string as in printf. * @param[in] aArgList The variable-length arguments list. - * */ void otbrLogv(otbrLogLevel aLevel, const char *aFormat, va_list aArgList); @@ -120,7 +115,6 @@ void otbrLogv(otbrLogLevel aLevel, const char *aFormat, va_list aArgList); * @param[in] aLevel Log level of the logger. * @param[in] aFormat Format string as in printf. * @param[in] aArgList The variable-length arguments list. - * */ void otbrLogvNoFilter(otbrLogLevel aLevel, const char *aFormat, va_list aArgList); @@ -132,7 +126,6 @@ void otbrLogvNoFilter(otbrLogLevel aLevel, const char *aFormat, va_list aArgList * @param[in] aPrefix String before dumping memory. * @param[in] aMemory The pointer to the memory to be dumped. * @param[in] aSize The size of memory in bytes to be dumped. - * */ void otbrDump(otbrLogLevel aLevel, const char *aLogTag, const char *aPrefix, const void *aMemory, size_t aSize); @@ -142,13 +135,11 @@ void otbrDump(otbrLogLevel aLevel, const char *aLogTag, const char *aPrefix, con * @param[in] aError The error code. * * @returns The string information of error. - * */ const char *otbrErrorString(otbrError aError); /** * This function deinitializes the logging service. - * */ void otbrLogDeinit(void); @@ -161,7 +152,6 @@ void otbrLogDeinit(void); * @param[in] aError The action result. * @param[in] aFormat Format string as in printf. * @param[in] ... Arguments for the format specification. - * */ #define otbrLogResult(aError, aFormat, ...) \ do \ @@ -177,7 +167,6 @@ void otbrLogDeinit(void); * Log at level emergency. * * @param[in] ... Arguments for the format specification. - * */ /** @@ -186,7 +175,6 @@ void otbrLogDeinit(void); * Log at level alert. * * @param[in] ... Arguments for the format specification. - * */ /** @@ -195,7 +183,6 @@ void otbrLogDeinit(void); * Log at level critical. * * @param[in] ... Arguments for the format specification. - * */ /** @@ -204,7 +191,6 @@ void otbrLogDeinit(void); * Log at level error. * * @param[in] ... Arguments for the format specification. - * */ /** @@ -213,7 +199,6 @@ void otbrLogDeinit(void); * Log at level warning. * * @param[in] ... Arguments for the format specification. - * */ /** @@ -222,7 +207,6 @@ void otbrLogDeinit(void); * Log at level notice. * * @param[in] ... Arguments for the format specification. - * */ /** @@ -231,7 +215,6 @@ void otbrLogDeinit(void); * Log at level information. * * @param[in] ... Arguments for the format specification. - * */ /** @@ -240,7 +223,6 @@ void otbrLogDeinit(void); * Log at level debug. * * @param[in] ... Arguments for the format specification. - * */ #define otbrLogEmerg(...) otbrLog(OTBR_LOG_EMERG, OTBR_LOG_TAG, __VA_ARGS__) #define otbrLogAlert(...) otbrLog(OTBR_LOG_ALERT, OTBR_LOG_TAG, __VA_ARGS__) diff --git a/src/common/mainloop.cpp b/src/common/mainloop.cpp index f2024fbbe4a..f7400b5c972 100644 --- a/src/common/mainloop.cpp +++ b/src/common/mainloop.cpp @@ -40,4 +40,36 @@ MainloopProcessor::~MainloopProcessor(void) { MainloopManager::GetInstance().RemoveMainloopProcessor(this); } + +void MainloopContext::AddFdToReadSet(int aFd) +{ + AddFdToSet(aFd, kReadFdSet); +} + +void MainloopContext::AddFdToSet(int aFd, uint8_t aFdSetsMask) +{ + bool isSet = false; + + if (aFdSetsMask & kErrorFdSet) + { + FD_SET(aFd, &mErrorFdSet); + isSet = true; + } + if (aFdSetsMask & kReadFdSet) + { + FD_SET(aFd, &mReadFdSet); + isSet = true; + } + if (aFdSetsMask & kWriteFdSet) + { + FD_SET(aFd, &mWriteFdSet); + isSet = true; + } + + if (isSet) + { + mMaxFd = std::max(mMaxFd, aFd); + } +} + } // namespace otbr diff --git a/src/common/mainloop.hpp b/src/common/mainloop.hpp index 91ccb58957d..e887ceafc38 100644 --- a/src/common/mainloop.hpp +++ b/src/common/mainloop.hpp @@ -42,14 +42,33 @@ namespace otbr { /** * This type defines the context data for running a mainloop. - * */ -using MainloopContext = otSysMainloopContext; +class MainloopContext : public otSysMainloopContext +{ +public: + static constexpr uint8_t kErrorFdSet = 1 << 0; + static constexpr uint8_t kReadFdSet = 1 << 1; + static constexpr uint8_t kWriteFdSet = 1 << 2; + + /** + * This method adds a fd to the read fd set inside the MainloopContext. + * + * @param[in] aFd The fd to add. + */ + void AddFdToReadSet(int aFd); + + /** + * This method adds a fd to the fd sets inside the MainloopContext. + * + * @param[in] aFd The fd to add. + * @param[in] aFdSetsMask A bitmask indicating which fd sets to add. + */ + void AddFdToSet(int aFd, uint8_t aFdSetsMask); +}; /** * This abstract class defines the interface of a mainloop processor * which adds fds to the mainloop context and handles fds events. - * */ class MainloopProcessor { @@ -62,7 +81,6 @@ class MainloopProcessor * This method updates the mainloop context. * * @param[in,out] aMainloop A reference to the mainloop to be updated. - * */ virtual void Update(MainloopContext &aMainloop) = 0; @@ -70,7 +88,6 @@ class MainloopProcessor * This method processes mainloop events. * * @param[in] aMainloop A reference to the mainloop context. - * */ virtual void Process(const MainloopContext &aMainloop) = 0; }; diff --git a/src/common/mainloop_manager.hpp b/src/common/mainloop_manager.hpp index 739d9de4182..f379e2dfb8a 100644 --- a/src/common/mainloop_manager.hpp +++ b/src/common/mainloop_manager.hpp @@ -48,20 +48,17 @@ namespace otbr { /** * This class implements the mainloop manager. - * */ class MainloopManager : private NonCopyable { public: /** * The constructor to initialize the mainloop manager. - * */ MainloopManager() = default; /** * This method returns the singleton instance of the mainloop manager. - * */ static MainloopManager &GetInstance(void) { @@ -73,7 +70,6 @@ class MainloopManager : private NonCopyable * This method adds a mainloop processors to the mainloop managger. * * @param[in] aMainloopProcessor A pointer to the mainloop processor. - * */ void AddMainloopProcessor(MainloopProcessor *aMainloopProcessor); @@ -81,7 +77,6 @@ class MainloopManager : private NonCopyable * This method removes a mainloop processors from the mainloop managger. * * @param[in] aMainloopProcessor A pointer to the mainloop processor. - * */ void RemoveMainloopProcessor(MainloopProcessor *aMainloopProcessor); @@ -89,7 +84,6 @@ class MainloopManager : private NonCopyable * This method updates the mainloop context of all mainloop processors. * * @param[in,out] aMainloop A reference to the mainloop to be updated. - * */ void Update(MainloopContext &aMainloop); @@ -97,7 +91,6 @@ class MainloopManager : private NonCopyable * This method processes mainloop events of all mainloop processors. * * @param[in] aMainloop A reference to the mainloop context. - * */ void Process(const MainloopContext &aMainloop); diff --git a/src/common/task_runner.cpp b/src/common/task_runner.cpp index 9a7f154d1fa..28c715cd32d 100644 --- a/src/common/task_runner.cpp +++ b/src/common/task_runner.cpp @@ -82,8 +82,7 @@ TaskRunner::TaskId TaskRunner::Post(Milliseconds aDelay, Task aTask) void TaskRunner::Update(MainloopContext &aMainloop) { - FD_SET(mEventFd[kRead], &aMainloop.mReadFdSet); - aMainloop.mMaxFd = std::max(mEventFd[kRead], aMainloop.mMaxFd); + aMainloop.AddFdToReadSet(mEventFd[kRead]); { std::lock_guard _(mTaskQueueMutex); diff --git a/src/common/task_runner.hpp b/src/common/task_runner.hpp index 1e72e80775a..f56d613d792 100644 --- a/src/common/task_runner.hpp +++ b/src/common/task_runner.hpp @@ -52,14 +52,12 @@ namespace otbr { /** * This class implements the Task Runner that executes * tasks on the mainloop. - * */ class TaskRunner : public MainloopProcessor, private NonCopyable { public: /** * This type represents the generic executable task. - * */ template using Task = std::function; @@ -67,19 +65,16 @@ class TaskRunner : public MainloopProcessor, private NonCopyable * This type represents a unique task ID to an delayed task. * * Note: A valid task ID is never zero. - * */ typedef uint64_t TaskId; /** * This constructor initializes the Task Runner instance. - * */ TaskRunner(void); /** * This destructor destroys the Task Runner instance. - * */ ~TaskRunner(void) override; @@ -90,7 +85,6 @@ class TaskRunner : public MainloopProcessor, private NonCopyable * It is safe to call this method in different threads concurrently. * * @param[in] aTask The task to be executed. - * */ void Post(Task aTask); @@ -104,7 +98,6 @@ class TaskRunner : public MainloopProcessor, private NonCopyable * @param[in] aTask The task to be executed. * * @returns The unique task ID of the delayed task. - * */ TaskId Post(Milliseconds aDelay, Task aTask); @@ -113,7 +106,6 @@ class TaskRunner : public MainloopProcessor, private NonCopyable * It is safe to call this method in different threads concurrently. * * @param[in] aTaskId The unique task ID of the delayed task to cancel. - * */ void Cancel(TaskId aTaskId); @@ -125,7 +117,6 @@ class TaskRunner : public MainloopProcessor, private NonCopyable * the caller will be blocked forever. * * @returns The result returned by the task @p aTask. - * */ template T PostAndWait(const Task &aTask) { diff --git a/src/common/tlv.hpp b/src/common/tlv.hpp index 16bc00adcb8..ade73b71bd3 100644 --- a/src/common/tlv.hpp +++ b/src/common/tlv.hpp @@ -43,7 +43,6 @@ namespace otbr { /** * This class implements TMF Tlv functionality. - * */ class Tlv { @@ -57,13 +56,11 @@ class Tlv * This method returns the Tlv type. * * @returns The Tlv type. - * */ uint8_t GetType(void) const { return mType; } /** * This method sets the Tlv type. - * */ void SetType(uint8_t aType) { mType = aType; } @@ -71,7 +68,6 @@ class Tlv * This method returns the Tlv length. * * @returns The Tlv length. - * */ uint16_t GetLength(void) const { @@ -99,7 +95,6 @@ class Tlv * This method returns a pointer to the value. * * @returns The Tlv value. - * */ const void *GetValue(void) const { @@ -111,7 +106,6 @@ class Tlv * This method returns the value as a uint16_t. * * @returns The uint16_t value. - * */ uint16_t GetValueUInt16(void) const { @@ -124,7 +118,6 @@ class Tlv * This method returns the value as a uint8_t. * * @returns The uint8_t value. - * */ uint8_t GetValueUInt8(void) const { return *static_cast(GetValue()); } @@ -132,7 +125,6 @@ class Tlv * This method sets a uint64_t as the value. * * @param[in] aValue The uint64_t value. - * */ void SetValue(uint64_t aValue) { @@ -150,7 +142,6 @@ class Tlv * This method sets a uint32_t as the value. * * @param[in] aValue The uint32_t value. - * */ void SetValue(uint32_t aValue) { @@ -168,7 +159,6 @@ class Tlv * This method sets uint16_t as the value. * * @param[in] aValue The uint16_t value. - * */ void SetValue(uint16_t aValue) { @@ -184,7 +174,6 @@ class Tlv * This method sets uint8_t as the value. * * @param[in] aValue The uint8_t value. - * */ void SetValue(uint8_t aValue) { @@ -196,7 +185,6 @@ class Tlv * This method sets int8_t as the value. * * @param[in] aValue The int8_t value. - * */ void SetValue(int8_t aValue) { @@ -217,7 +205,6 @@ class Tlv * This method returns the pointer to the next Tlv. * * @returns A pointer to the next Tlv. - * */ const Tlv *GetNext(void) const { @@ -228,7 +215,6 @@ class Tlv * This method returns the pointer to the next Tlv. * * @returns A pointer to the next Tlv. - * */ Tlv *GetNext(void) { return reinterpret_cast(static_cast(GetValue()) + GetLength()); } diff --git a/src/common/types.cpp b/src/common/types.cpp index 0568c5125fe..2fef20f8af6 100644 --- a/src/common/types.cpp +++ b/src/common/types.cpp @@ -41,6 +41,11 @@ Ip6Address::Ip6Address(const uint8_t (&aAddress)[16]) memcpy(m8, aAddress, sizeof(m8)); } +Ip6Address::Ip6Address(const otIp6Address &aAddress) +{ + memcpy(m8, aAddress.mFields.m8, sizeof(m8)); +} + std::string Ip6Address::ToString() const { char strbuf[INET6_ADDRSTRLEN]; @@ -128,6 +133,11 @@ bool Ip6Prefix::operator==(const Ip6Prefix &aOther) const return isEqual; } +bool Ip6Prefix::operator!=(const Ip6Prefix &aOther) const +{ + return !(*this == aOther); +} + void Ip6Prefix::Set(const otIp6Prefix &aPrefix) { memcpy(reinterpret_cast(this), &aPrefix, sizeof(*this)); @@ -159,4 +169,46 @@ std::string MacAddress::ToString(void) const return std::string(strbuf); } +otError OtbrErrorToOtError(otbrError aError) +{ + otError error; + + switch (aError) + { + case OTBR_ERROR_NONE: + error = OT_ERROR_NONE; + break; + + case OTBR_ERROR_NOT_FOUND: + error = OT_ERROR_NOT_FOUND; + break; + + case OTBR_ERROR_PARSE: + error = OT_ERROR_PARSE; + break; + + case OTBR_ERROR_NOT_IMPLEMENTED: + error = OT_ERROR_NOT_IMPLEMENTED; + break; + + case OTBR_ERROR_INVALID_ARGS: + error = OT_ERROR_INVALID_ARGS; + break; + + case OTBR_ERROR_DUPLICATED: + error = OT_ERROR_DUPLICATED; + break; + + case OTBR_ERROR_INVALID_STATE: + error = OT_ERROR_INVALID_STATE; + break; + + default: + error = OT_ERROR_FAILED; + break; + } + + return error; +} + } // namespace otbr diff --git a/src/common/types.hpp b/src/common/types.hpp index 4de70312e83..a102a9eba98 100644 --- a/src/common/types.hpp +++ b/src/common/types.hpp @@ -42,12 +42,14 @@ #include #include +#include +#include + #include "common/byteswap.hpp" #ifndef IN6ADDR_ANY /** * Any IPv6 address literal. - * */ #define IN6ADDR_ANY "::" #endif @@ -60,7 +62,6 @@ /** * Forward declaration for otIp6Prefix to avoid including - * */ struct otIp6Prefix; @@ -85,6 +86,7 @@ enum otbrError OTBR_ERROR_ABORTED = -12, ///< The operation is aborted. OTBR_ERROR_INVALID_STATE = -13, ///< The target isn't in a valid state. OTBR_ERROR_INFRA_LINK_CHANGED = -14, ///< The infrastructure link is changed. + OTBR_ERROR_DROPPED = -15, ///< The packet is dropped. }; namespace otbr { @@ -103,14 +105,12 @@ static constexpr char kLinkLocalAllNodesMulticastAddress[] = "ff02::01"; /** * This class implements the Ipv6 address functionality. - * */ class Ip6Address { public: /** * Default constructor. - * */ Ip6Address(void) { @@ -122,7 +122,6 @@ class Ip6Address * Constructor with an 16-bit Thread locator. * * @param[in] aLocator The 16-bit Thread locator, RLOC or ALOC. - * */ Ip6Address(uint16_t aLocator) { @@ -137,15 +136,20 @@ class Ip6Address * Constructor with an Ip6 address. * * @param[in] aAddress The Ip6 address. - * */ Ip6Address(const uint8_t (&aAddress)[16]); + /** + * Constructor with an otIp6Address. + * + * @param[in] aAddress A const reference to an otIp6Address. + */ + explicit Ip6Address(const otIp6Address &aAddress); + /** * Constructor with a string. * * @param[in] aString The string representing the IPv6 address. - * */ Ip6Address(const char *aString) { FromString(aString, *this); } @@ -155,7 +159,6 @@ class Ip6Address * @param[in] aOther The other Ip6 address to compare with. * * @returns Whether the Ip6 address is smaller than the other address. - * */ bool operator<(const Ip6Address &aOther) const { return memcmp(this, &aOther, sizeof(Ip6Address)) < 0; } @@ -165,15 +168,22 @@ class Ip6Address * @param[in] aOther The other Ip6 address to compare with. * * @returns Whether the Ip6 address is equal to the other address. - * */ bool operator==(const Ip6Address &aOther) const { return m64[0] == aOther.m64[0] && m64[1] == aOther.m64[1]; } + /** + * This method overloads `!=` operator and compares if the Ip6 address is NOT equal to the other address. + * + * @param[in] aOther The other Ip6 address to compare with. + * + * @returns Whether the Ip6 address is NOT equal to the other address. + */ + bool operator!=(const Ip6Address &aOther) const { return !(*this == aOther); } + /** * Retrieve the 16-bit Thread locator. * * @returns RLOC16 or ALOC16. - * */ uint16_t ToLocator(void) const { return static_cast(m8[14] << 8 | m8[15]); } @@ -181,7 +191,6 @@ class Ip6Address * This method returns the solicited node multicast address. * * @returns The solicited node multicast address. - * */ Ip6Address ToSolicitedNodeMulticastAddress(void) const; @@ -189,7 +198,6 @@ class Ip6Address * This method returns the string representation for the Ip6 address. * * @returns The string representation of the Ip6 address. - * */ std::string ToString(void) const; @@ -198,7 +206,6 @@ class Ip6Address * * @retval TRUE If the Ip6 address is the Unspecified Address. * @retval FALSE If the Ip6 address is not the Unspecified Address. - * */ bool IsUnspecified(void) const { return m64[0] == 0 && m64[1] == 0; } @@ -206,7 +213,6 @@ class Ip6Address * This method returns if the Ip6 address is a multicast address. * * @returns Whether the Ip6 address is a multicast address. - * */ bool IsMulticast(void) const { return m8[0] == 0xff; } @@ -214,7 +220,6 @@ class Ip6Address * This method returns if the Ip6 address is a link-local address. * * @returns Whether the Ip6 address is a link-local address. - * */ bool IsLinkLocal(void) const { return (m16[0] & bswap_16(0xffc0)) == bswap_16(0xfe80); } @@ -223,7 +228,6 @@ class Ip6Address * * @retval TRUE If the Ip6 address is the Loopback Address. * @retval FALSE If the Ip6 address is not the Loopback Address. - * */ bool IsLoopback(void) const { return (m32[0] == 0 && m32[1] == 0 && m32[2] == 0 && m32[3] == htobe32(1)); } @@ -231,7 +235,6 @@ class Ip6Address * This function returns the wellknown Link Local All Nodes Multicast Address (ff02::1). * * @returns The Link Local All Nodes Multicast Address. - * */ static const Ip6Address &GetLinkLocalAllNodesMulticastAddress(void) { @@ -244,7 +247,6 @@ class Ip6Address * This function returns the wellknown Solicited Node Multicast Address Prefix (ff02::01:ff00:0). * * @returns The Solicited Node Multicast Address Prefix. - * */ static const Ip6Address &GetSolicitedMulticastAddressPrefix(void) { @@ -261,7 +263,6 @@ class Ip6Address * * @retval OTBR_ERROR_NONE If the Ip6 address was successfully converted. * @retval OTBR_ERROR_INVALID_ARGS If @p `aStr` is not a valid string representing of Ip6 address. - * */ static otbrError FromString(const char *aStr, Ip6Address &aAddr); @@ -269,7 +270,6 @@ class Ip6Address * This method copies the Ip6 address to a `sockaddr_in6` structure. * * @param[out] aSockAddr The `sockaddr_in6` structure to copy the Ip6 address to. - * */ void CopyTo(struct sockaddr_in6 &aSockAddr) const; @@ -277,7 +277,6 @@ class Ip6Address * This method copies the Ip6 address from a `sockaddr_in6` structure. * * @param[in] aSockAddr The `sockaddr_in6` structure to copy the Ip6 address from. - * */ void CopyFrom(const struct sockaddr_in6 &aSockAddr); @@ -285,7 +284,6 @@ class Ip6Address * This method copies the Ip6 address to a `in6_addr` structure. * * @param[out] aIn6Addr The `in6_addr` structure to copy the Ip6 address to. - * */ void CopyTo(struct in6_addr &aIn6Addr) const; @@ -293,7 +291,6 @@ class Ip6Address * This method copies the Ip6 address from a `in6_addr` structure. * * @param[in] aIn6Addr The `in6_addr` structure to copy the Ip6 address from. - * */ void CopyFrom(const struct in6_addr &aIn6Addr); @@ -311,14 +308,12 @@ class Ip6Address /** * This class represents a Ipv6 prefix. - * */ class Ip6Prefix { public: /** * Default constructor. - * */ Ip6Prefix(void) { Clear(); } @@ -327,7 +322,6 @@ class Ip6Prefix * * @param[in] aIp6AddrStr The IPv6 address string. * @param[in] aLength The prefix length. - * */ Ip6Prefix(const char *aIp6AddrStr, uint8_t aLength) : mPrefix(aIp6AddrStr) @@ -345,15 +339,22 @@ class Ip6Prefix * @param[in] aOther The Ip6Prefix object to compare with. * * @returns True if the two objects are equal, false otherwise. - * */ bool operator==(const Ip6Prefix &aOther) const; + /** + * This method overloads `!=` operator for comparing two Ip6Prefix objects. + + * @param[in] aOther The Ip6Prefix object to compare with. + * + * @returns True if the two objects are NOT equal, false otherwise. + */ + bool operator!=(const Ip6Prefix &aOther) const; + /** * This method sets the Ip6 prefix to an `otIp6Prefix` value. * * @param[in] aPrefix The `otIp6Prefix` value to set the Ip6 prefix. - * */ void Set(const otIp6Prefix &aPrefix); @@ -361,13 +362,11 @@ class Ip6Prefix * This method returns the string representation for the Ip6 prefix. * * @returns The string representation of the Ip6 prefix. - * */ std::string ToString(void) const; /** * This method clears the Ip6 prefix to be unspecified. - * */ void Clear(void) { memset(reinterpret_cast(this), 0, sizeof(*this)); } @@ -375,7 +374,6 @@ class Ip6Prefix * This method returns if the Ip6 prefix is valid. * * @returns If the Ip6 prefix is valid. - * */ bool IsValid(void) const { return mLength > 0 && mLength <= 128; } @@ -383,7 +381,6 @@ class Ip6Prefix * This method checks if the object is the default route prefix ("::/0") * * @returns true if the object is the default route prefix, false otherwise. - * */ bool IsDefaultRoutePrefix(void) const { return (*this == Ip6Prefix("::", 0)); } @@ -391,7 +388,6 @@ class Ip6Prefix * This method checks if the object is the ULA prefix ("fc00::/7") * * @returns true if the object is the ULA prefix, false otherwise. - * */ bool IsUlaPrefix(void) const { return (*this == Ip6Prefix("fc00::", 7)); } @@ -399,6 +395,38 @@ class Ip6Prefix uint8_t mLength; ///< The IPv6 prefix length (in bits). }; +/** + * This class represents a Ipv6 address and its info. + */ +class Ip6AddressInfo +{ +public: + Ip6AddressInfo(void) { Clear(); } + + Ip6AddressInfo(const otIp6Address &aAddress, + uint8_t aPrefixLength, + uint8_t aScope, + bool aPreferred, + bool aMeshLocal) + : mAddress(aAddress) + , mPrefixLength(aPrefixLength) + , mScope(aScope) + , mPreferred(aPreferred) + , mMeshLocal(aMeshLocal) + { + } + + void Clear(void) { memset(reinterpret_cast(this), 0, sizeof(*this)); } + + otIp6Address mAddress; + uint8_t mPrefixLength; + uint8_t mScope : 4; + bool mPreferred : 1; + bool mMeshLocal : 1; + + bool operator==(const Ip6AddressInfo &aOther) const { return memcmp(this, &aOther, sizeof(Ip6AddressInfo)) == 0; } +}; + /** * This class represents an ethernet MAC address. */ @@ -407,7 +435,6 @@ class MacAddress public: /** * Default constructor. - * */ MacAddress(void) { @@ -420,7 +447,6 @@ class MacAddress * This method returns the string representation for the MAC address. * * @returns The string representation of the MAC address. - * */ std::string ToString(void) const; @@ -469,6 +495,15 @@ static constexpr size_t kVendorOuiLength = 3; static constexpr size_t kMaxVendorNameLength = 24; static constexpr size_t kMaxProductNameLength = 24; +/** + * This method converts a otbrError to a otError. + * + * @param[in] aError a otbrError code. + * + * @returns a otError code. + */ +otError OtbrErrorToOtError(otbrError aError); + } // namespace otbr #endif // OTBR_COMMON_TYPES_HPP_ diff --git a/src/dbus/client/client_error.hpp b/src/dbus/client/client_error.hpp index 7f499bdc6c1..8a0363d0e29 100644 --- a/src/dbus/client/client_error.hpp +++ b/src/dbus/client/client_error.hpp @@ -52,7 +52,6 @@ namespace DBus { * * @returns The corresponding otError. OT_ERROR_GENERIC will be returned * if the error name is not defined in OpenThread. - * */ ClientError ConvertFromDBusErrorName(const std::string &aErrorName); @@ -62,7 +61,6 @@ ClientError ConvertFromDBusErrorName(const std::string &aErrorName); * @param[in] aMessage The dbus reply message. * * @returns The error code encoded in the message. - * */ ClientError CheckErrorMessage(DBusMessage *aMessage); diff --git a/src/dbus/client/thread_api_dbus.cpp b/src/dbus/client/thread_api_dbus.cpp index 944c23f5bf8..51f8828e6a8 100644 --- a/src/dbus/client/thread_api_dbus.cpp +++ b/src/dbus/client/thread_api_dbus.cpp @@ -463,6 +463,11 @@ ClientError ThreadApiDBus::SetNat64Enabled(bool aEnabled) return CallDBusMethodSync(OTBR_DBUS_SET_NAT64_ENABLED_METHOD, std::tie(aEnabled)); } +ClientError ThreadApiDBus::SetEphemeralKeyEnabled(bool aEnabled) +{ + return SetProperty(OTBR_DBUS_PROPERTY_EPHEMERAL_KEY_ENABLED, aEnabled); +} + ClientError ThreadApiDBus::SetMeshLocalPrefix(const std::array &aPrefix) { return SetProperty(OTBR_DBUS_PROPERTY_MESH_LOCAL_PREFIX, aPrefix); @@ -488,6 +493,11 @@ ClientError ThreadApiDBus::SetRadioRegion(const std::string &aRadioRegion) return SetProperty(OTBR_DBUS_PROPERTY_RADIO_REGION, aRadioRegion); } +ClientError ThreadApiDBus::GetEphemeralKeyEnabled(bool &aEnabled) +{ + return GetProperty(OTBR_DBUS_PROPERTY_EPHEMERAL_KEY_ENABLED, aEnabled); +} + ClientError ThreadApiDBus::GetLinkMode(LinkModeConfig &aConfig) { return GetProperty(OTBR_DBUS_PROPERTY_LINK_MODE, aConfig); diff --git a/src/dbus/client/thread_api_dbus.hpp b/src/dbus/client/thread_api_dbus.hpp index b47aaedc0d2..e817e525355 100644 --- a/src/dbus/client/thread_api_dbus.hpp +++ b/src/dbus/client/thread_api_dbus.hpp @@ -64,7 +64,6 @@ class ThreadApiDBus * Will use the default interfacename * * @param[in] aConnection The dbus connection. - * */ ThreadApiDBus(DBusConnection *aConnection); @@ -73,7 +72,6 @@ class ThreadApiDBus * * @param[in] aConnection The dbus connection. * @param[in] aInterfaceName The network interface name. - * */ ThreadApiDBus(DBusConnection *aConnection, const std::string &aInterfaceName); @@ -81,7 +79,6 @@ class ThreadApiDBus * This method adds a callback for device role change. * * @param[in] aHandler The device role handler. - * */ void AddDeviceRoleHandler(const DeviceRoleHandler &aHandler); @@ -94,7 +91,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError PermitUnsecureJoin(uint16_t aPort, uint32_t aSeconds); @@ -106,7 +102,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError Scan(const ScanHandler &aHandler); @@ -121,7 +116,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError EnergyScan(uint32_t aScanDuration, const EnergyScanHandler &aHandler); @@ -138,7 +132,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError Attach(const std::string &aNetworkName, uint16_t aPanId, @@ -159,7 +152,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError Attach(const OtResultHandler &aHandler); @@ -169,7 +161,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError Detach(const OtResultHandler &aHandler); @@ -188,7 +179,6 @@ class ThreadApiDBus * @retval OT_ERROR_INVALID_STATE The device is attaching. * @retval OT_ERROR_INVALID_ARGS Arguments are invalid. * @retval OT_ERROR_BUSY There is an ongoing request. - * */ ClientError AttachAllNodesTo(const std::vector &aDataset); @@ -200,7 +190,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError FactoryReset(const OtResultHandler &aHandler); @@ -210,7 +199,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError Reset(void); @@ -230,7 +218,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError JoinerStart(const std::string &aPskd, const std::string &aProvisioningUrl, @@ -246,7 +233,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError JoinerStop(void); @@ -258,7 +244,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError AddOnMeshPrefix(const OnMeshPrefix &aPrefix); @@ -270,7 +255,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError RemoveOnMeshPrefix(const Ip6Prefix &aPrefix); @@ -282,7 +266,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError AddExternalRoute(const ExternalRoute &aExternalRoute); @@ -294,7 +277,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError RemoveExternalRoute(const Ip6Prefix &aPrefix); @@ -306,7 +288,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError SetMeshLocalPrefix(const std::array &aPrefix); @@ -318,7 +299,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError SetActiveDatasetTlvs(const std::vector &aDataset); @@ -331,7 +311,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError SetFeatureFlagListData(const std::vector &aFeatureFlagListData); @@ -343,7 +322,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError SetLinkMode(const LinkModeConfig &aConfig); @@ -355,22 +333,42 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError SetRadioRegion(const std::string &aRadioRegion); /** * This method sets the NAT64 switch. * - * @param[in] aEnable A boolean to enable/disable the NAT64. + * @param[in] aEnabled A boolean to enable/disable the NAT64. * * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError SetNat64Enabled(bool aEnabled); + /** + * This method sets the Ephemeral Key switch. + * + * @param[in] aEnabled A boolean to enable/disable the Ephemeral Key. + * + * @retval ERROR_NONE Successfully performed the dbus function call + * @retval ERROR_DBUS dbus encode/decode error + * @retval ... OpenThread defined error value otherwise + */ + ClientError SetEphemeralKeyEnabled(bool aEnabled); + + /** + * This method gets the Ephemeral Key switch. + * + * @param[out] aEnabled A boolean of enable/disable for Ephemeral Key state. + * + * @retval ERROR_NONE Successfully performed the dbus function call + * @retval ERROR_DBUS dbus encode/decode error + * @retval ... OpenThread defined error value otherwise + */ + ClientError GetEphemeralKeyEnabled(bool &aEnabled); + /** * This method gets the link operating mode. * @@ -379,7 +377,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetLinkMode(LinkModeConfig &aConfig); @@ -391,7 +388,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetDeviceRole(DeviceRole &aDeviceRole); @@ -403,7 +399,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetNetworkName(std::string &aName); @@ -415,7 +410,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetPanId(uint16_t &aPanId); @@ -427,7 +421,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetExtPanId(uint64_t &aExtPanId); @@ -439,7 +432,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetChannel(uint16_t &aChannel); @@ -451,7 +443,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetNetworkKey(std::vector &aNetworkKey); @@ -463,7 +454,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetCcaFailureRate(uint16_t &aFailureRate); @@ -475,7 +465,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetLinkCounters(MacCounters &aCounters); // For telemetry @@ -487,7 +476,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetIp6Counters(IpCounters &aCounters); // For telemetry @@ -499,7 +487,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetSupportedChannelMask(uint32_t &aChannelMask); @@ -511,7 +498,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetPreferredChannelMask(uint32_t &aChannelMask); @@ -523,7 +509,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetRloc16(uint16_t &aRloc16); @@ -535,7 +520,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetExtendedAddress(uint64_t &aExtendedAddress); @@ -548,7 +532,6 @@ class ThreadApiDBus * @retval ERROR_DBUS dbus encode/decode error. * @retval OT_ERROR_INVALID_STATE The node is not a router. * @retval ... OpenThread defined error value otherwise. - * */ ClientError GetRouterId(uint8_t &aRouterId); @@ -560,7 +543,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetLeaderData(LeaderData &aLeaderData); @@ -572,7 +554,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetNetworkData(std::vector &aNetworkData); @@ -584,7 +565,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetStableNetworkData(std::vector &aNetworkData); @@ -596,7 +576,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetLocalLeaderWeight(uint8_t &aWeight); @@ -608,7 +587,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetChannelMonitorSampleCount(uint32_t &aSampleCount); @@ -620,7 +598,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetChannelMonitorAllChannelQualities(std::vector &aChannelQualities); @@ -632,7 +609,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetChildTable(std::vector &aChildTable); @@ -644,7 +620,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetNeighborTable(std::vector &aNeighborTable); @@ -656,7 +631,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetPartitionId(uint32_t &aPartitionId); @@ -668,7 +642,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetInstantRssi(int8_t &aRssi); @@ -680,7 +653,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetRadioTxPower(int8_t &aTxPower); @@ -692,7 +664,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetExternalRoutes(std::vector &aExternalRoutes); @@ -704,7 +675,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetOnMeshPrefixes(std::vector &aOnMeshPrefixes); @@ -716,7 +686,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetActiveDatasetTlvs(std::vector &aDataset); @@ -728,7 +697,6 @@ class ThreadApiDBus * @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); @@ -741,7 +709,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetFeatureFlagListData(std::vector &aFeatureFlagListData); @@ -753,7 +720,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetRadioRegion(std::string &aRadioRegion); @@ -765,7 +731,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetSrpServerInfo(SrpServerInfo &aSrpServerInfo); @@ -778,7 +743,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetTrelInfo(TrelInfo &aTrelInfo); #endif @@ -791,7 +755,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetMdnsTelemetryInfo(MdnsTelemetryInfo &aMdnsTelemetryInfo); @@ -804,7 +767,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetDnssdCounters(DnssdCounters &aDnssdCounters); #endif @@ -813,7 +775,6 @@ class ThreadApiDBus * This method returns the network interface name the client is bound to. * * @returns The network interface name. - * */ std::string GetInterfaceName(void); @@ -832,7 +793,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError UpdateVendorMeshCopTxtEntries(std::vector &aUpdate); @@ -844,7 +804,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetNat64State(Nat64ComponentState &aState); @@ -856,7 +815,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetNat64Mappings(std::vector &aMappings); @@ -868,7 +826,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetNat64ProtocolCounters(Nat64ProtocolCounters &aCounters); @@ -880,7 +837,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetNat64ErrorCounters(Nat64ErrorCounters &aCounters); @@ -893,7 +849,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetTelemetryData(std::vector &aTelemetryData); @@ -906,7 +861,6 @@ class ThreadApiDBus * @retval ERROR_NONE Successfully performed the dbus function call * @retval ERROR_DBUS dbus encode/decode error * @retval ... OpenThread defined error value otherwise - * */ ClientError GetCapabilities(std::vector &aCapabilities); diff --git a/src/dbus/common/constants.hpp b/src/dbus/common/constants.hpp index a8e16482491..0238bc55d8d 100644 --- a/src/dbus/common/constants.hpp +++ b/src/dbus/common/constants.hpp @@ -48,6 +48,7 @@ #define OTBR_DBUS_ENERGY_SCAN_METHOD "EnergyScan" #define OTBR_DBUS_ATTACH_METHOD "Attach" #define OTBR_DBUS_DETACH_METHOD "Detach" +#define OTBR_DBUS_JOIN_METHOD "Join" #define OTBR_DBUS_FACTORY_RESET_METHOD "FactoryReset" #define OTBR_DBUS_RESET_METHOD "Reset" #define OTBR_DBUS_ADD_ON_MESH_PREFIX_METHOD "AddOnMeshPrefix" @@ -62,6 +63,9 @@ #define OTBR_DBUS_GET_PROPERTIES_METHOD "GetProperties" #define OTBR_DBUS_LEAVE_NETWORK_METHOD "LeaveNetwork" #define OTBR_DBUS_SET_NAT64_ENABLED_METHOD "SetNat64Enabled" +#define OTBR_DBUS_ACTIVATE_EPHEMERAL_KEY_MODE_METHOD "ActivateEphemeralKeyMode" +#define OTBR_DBUS_DEACTIVATE_EPHEMERAL_KEY_MODE_METHOD "DeactivateEphemeralKeyMode" +#define OTBR_DBUS_SCHEDULE_MIGRATION_METHOD "ScheduleMigration" #define OTBR_DBUS_PROPERTY_MESH_LOCAL_PREFIX "MeshLocalPrefix" #define OTBR_DBUS_PROPERTY_LINK_MODE "LinkMode" @@ -115,8 +119,10 @@ #define OTBR_DBUS_PROPERTY_NAT64_MAPPINGS "Nat64Mappings" #define OTBR_DBUS_PROPERTY_NAT64_PROTOCOL_COUNTERS "Nat64ProtocolCounters" #define OTBR_DBUS_PROPERTY_NAT64_ERROR_COUNTERS "Nat64ErrorCounters" +#define OTBR_DBUS_PROPERTY_EPHEMERAL_KEY_ENABLED "EphemeralKeyEnabled" #define OTBR_DBUS_PROPERTY_INFRA_LINK_INFO "InfraLinkInfo" #define OTBR_DBUS_PROPERTY_DNS_UPSTREAM_QUERY_STATE "DnsUpstreamQueryState" +#define OTBR_DBUS_PROPERTY_DHCP6_PD_STATE "Dhcp6PdState" #define OTBR_DBUS_PROPERTY_TELEMETRY_DATA "TelemetryData" #define OTBR_DBUS_PROPERTY_CAPABILITIES "Capabilities" diff --git a/src/dbus/common/error.hpp b/src/dbus/common/error.hpp index 8b7a2239747..7d853d74754 100644 --- a/src/dbus/common/error.hpp +++ b/src/dbus/common/error.hpp @@ -46,7 +46,6 @@ namespace otbr { * @namespace otbr::DBus * * @brief This namespace contains OpenThread Border Router DBus API. - * */ namespace DBus { diff --git a/src/dbus/common/types.hpp b/src/dbus/common/types.hpp index c32dd03e1dd..3c427bf64db 100644 --- a/src/dbus/common/types.hpp +++ b/src/dbus/common/types.hpp @@ -193,7 +193,6 @@ struct ExternalRoute /** * This structure represents the MAC layer counters. - * */ struct MacCounters { @@ -220,61 +219,51 @@ struct MacCounters * @p mTxTotal = @p mTxUnicast + @p mTxBroadcast * @p mTxTotal = @p mTxAckRequested + @p mTxNoAckRequested * @p mTxTotal = @p mTxData + @p mTxDataPoll + @p mTxBeacon + @p mTxBeaconRequest + @p mTxOther - * */ uint32_t mTxTotal; /** * The total number of unique unicast MAC frame transmission requests. - * */ uint32_t mTxUnicast; /** * The total number of unique broadcast MAC frame transmission requests. - * */ uint32_t mTxBroadcast; /** * The total number of unique MAC frame transmission requests with requested acknowledgment. - * */ uint32_t mTxAckRequested; /** * The total number of unique MAC frame transmission requests that were acked. - * */ uint32_t mTxAcked; /** * The total number of unique MAC frame transmission requests without requested acknowledgment. - * */ uint32_t mTxNoAckRequested; /** * The total number of unique MAC Data frame transmission requests. - * */ uint32_t mTxData; /** * The total number of unique MAC Data Poll frame transmission requests. - * */ uint32_t mTxDataPoll; /** * The total number of unique MAC Beacon frame transmission requests. - * */ uint32_t mTxBeacon; /** * The total number of unique MAC Beacon Request frame transmission requests. - * */ uint32_t mTxBeaconRequest; @@ -282,7 +271,6 @@ struct MacCounters * The total number of unique other MAC frame transmission requests. * * This counter is currently unused. - * */ uint32_t mTxOther; @@ -302,19 +290,16 @@ struct MacCounters * * Currently, this counter is invalid if the platform's radio driver capability includes * @sa OT_RADIO_CAPS_TRANSMIT_RETRIES. - * */ uint32_t mTxRetry; /** * The total number of unique MAC transmission packets that meet maximal retry limit for direct packets. - * */ uint32_t mTxDirectMaxRetryExpiry; /** * The total number of unique MAC transmission packets that meet maximal retry limit for indirect packets. - * */ uint32_t mTxIndirectMaxRetryExpiry; @@ -329,19 +314,16 @@ struct MacCounters * If @sa OT_RADIO_CAPS_TRANSMIT_RETRIES is enabled, this counter represents the total number of full CSMA/CA * failed attempts and it is incremented by one for each individual data frame request (regardless of the amount of * retransmissions). - * */ uint32_t mTxErrCca; /** * The total number of unique MAC transmission request failures cause by an abort error. - * */ uint32_t mTxErrAbort; /** * The total number of unique MAC transmission requests failures caused by a busy channel (a CSMA/CA fail). - * */ uint32_t mTxErrBusyChannel; @@ -350,61 +332,51 @@ struct MacCounters * * This counter counts all frames reported by the platform's radio driver, including frames * that were dropped, for example because of an FCS error. - * */ uint32_t mRxTotal; /** * The total number of unicast frames received. - * */ uint32_t mRxUnicast; /** * The total number of broadcast frames received. - * */ uint32_t mRxBroadcast; /** * The total number of MAC Data frames received. - * */ uint32_t mRxData; /** * The total number of MAC Data Poll frames received. - * */ uint32_t mRxDataPoll; /** * The total number of MAC Beacon frames received. - * */ uint32_t mRxBeacon; /** * The total number of MAC Beacon Request frames received. - * */ uint32_t mRxBeaconRequest; /** * The total number of other types of frames received. - * */ uint32_t mRxOther; /** * The total number of frames dropped by MAC Filter module, for example received from denylisted node. - * */ uint32_t mRxAddressFiltered; /** * The total number of frames dropped by destination address check, for example received frame for other node. - * */ uint32_t mRxDestAddrFiltered; @@ -413,25 +385,21 @@ struct MacCounters * * This counter may be incremented, for example when ACK frame generated by the receiver hasn't reached * transmitter node which performed retransmission. - * */ uint32_t mRxDuplicated; /** * The total number of frames dropped because of missing or malformed content. - * */ uint32_t mRxErrNoFrame; /** * The total number of frames dropped due to unknown neighbor. - * */ uint32_t mRxErrUnknownNeighbor; /** * The total number of frames dropped due to invalid source address. - * */ uint32_t mRxErrInvalidSrcAddr; @@ -440,19 +408,16 @@ struct MacCounters * * This counter may be incremented, for example when lower than expected Frame Counter is used * to encrypt the frame. - * */ uint32_t mRxErrSec; /** * The total number of frames dropped due to invalid FCS. - * */ uint32_t mRxErrFcs; /** * The total number of frames dropped due to other error. - * */ uint32_t mRxErrOther; }; @@ -715,7 +680,7 @@ struct TrelInfo }; bool mEnabled; ///< Whether TREL is enabled. - u_int16_t mNumTrelPeers; ///< The number of TREL peers. + uint16_t mNumTrelPeers; ///< The number of TREL peers. TrelPacketCounters mTrelCounters; ///< The TREL counters. }; diff --git a/src/dbus/server/CMakeLists.txt b/src/dbus/server/CMakeLists.txt index 2d0ae640036..f8ee7c4c1b7 100644 --- a/src/dbus/server/CMakeLists.txt +++ b/src/dbus/server/CMakeLists.txt @@ -37,7 +37,8 @@ add_custom_target(otbr-dbus-introspect-header ALL add_library(otbr-dbus-server STATIC dbus_agent.cpp dbus_object.cpp - dbus_thread_object.cpp + dbus_thread_object_ncp.cpp + dbus_thread_object_rcp.cpp error_helper.cpp ) @@ -55,7 +56,7 @@ target_link_libraries(otbr-dbus-server PUBLIC if(OTBR_DOC) add_custom_target(otbr-dbus-server-doc ALL - COMMAND gdbus-codegen --generate-docbook generated-docs ${CMAKE_CURRENT_SOURCE_DIR}/introspect.xml + COMMAND gdbus-codegen --generate-docbook generated-docs ${CMAKE_CURRENT_SOURCE_DIR}/introspect.xml COMMAND xmlto html generated-docs-io.openthread.BorderRouter.xml WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} VERBATIM diff --git a/src/dbus/server/dbus_agent.cpp b/src/dbus/server/dbus_agent.cpp index 82772045fca..6869971fc87 100644 --- a/src/dbus/server/dbus_agent.cpp +++ b/src/dbus/server/dbus_agent.cpp @@ -36,6 +36,8 @@ #include "common/logging.hpp" #include "dbus/common/constants.hpp" +#include "dbus/server/dbus_thread_object_ncp.hpp" +#include "dbus/server/dbus_thread_object_rcp.hpp" #include "mdns/mdns.hpp" namespace otbr { @@ -44,14 +46,14 @@ namespace DBus { const struct timeval DBusAgent::kPollTimeout = {0, 0}; constexpr std::chrono::seconds DBusAgent::kDBusWaitAllowance; -DBusAgent::DBusAgent(otbr::Ncp::RcpHost &aHost, Mdns::Publisher &aPublisher) +DBusAgent::DBusAgent(otbr::Ncp::ThreadHost &aHost, Mdns::Publisher &aPublisher) : mInterfaceName(aHost.GetInterfaceName()) , mHost(aHost) , mPublisher(aPublisher) { } -void DBusAgent::Init(void) +void DBusAgent::Init(otbr::BorderAgent &aBorderAgent) { otbrError error = OTBR_ERROR_NONE; @@ -65,8 +67,23 @@ void DBusAgent::Init(void) VerifyOrDie(mConnection != nullptr, "Failed to get DBus connection"); - mThreadObject = - std::unique_ptr(new DBusThreadObject(mConnection.get(), mInterfaceName, &mHost, &mPublisher)); + switch (mHost.GetCoprocessorType()) + { + case OT_COPROCESSOR_RCP: + mThreadObject = MakeUnique(*mConnection, mInterfaceName, + static_cast(mHost), &mPublisher, aBorderAgent); + break; + + case OT_COPROCESSOR_NCP: + mThreadObject = + MakeUnique(*mConnection, mInterfaceName, static_cast(mHost)); + break; + + default: + DieNow("Unknown coprocessor type!"); + break; + } + error = mThreadObject->Init(); VerifyOrDie(error == OTBR_ERROR_NONE, "Failed to initialize DBus Agent"); } @@ -122,6 +139,7 @@ void DBusAgent::Update(MainloopContext &aMainloop) { unsigned int flags; int fd; + uint8_t fdSetMask = MainloopContext::kErrorFdSet; if (dbus_connection_get_dispatch_status(mConnection.get()) == DBUS_DISPATCH_DATA_REMAINS) { @@ -145,17 +163,15 @@ void DBusAgent::Update(MainloopContext &aMainloop) if (flags & DBUS_WATCH_READABLE) { - FD_SET(fd, &aMainloop.mReadFdSet); + fdSetMask |= MainloopContext::kReadFdSet; } if ((flags & DBUS_WATCH_WRITABLE)) { - FD_SET(fd, &aMainloop.mWriteFdSet); + fdSetMask |= MainloopContext::kWriteFdSet; } - FD_SET(fd, &aMainloop.mErrorFdSet); - - aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd); + aMainloop.AddFdToSet(fd, fdSetMask); } } diff --git a/src/dbus/server/dbus_agent.hpp b/src/dbus/server/dbus_agent.hpp index 17ff7ccd702..cd6793efa33 100644 --- a/src/dbus/server/dbus_agent.hpp +++ b/src/dbus/server/dbus_agent.hpp @@ -46,9 +46,9 @@ #include "dbus/common/dbus_message_helper.hpp" #include "dbus/common/dbus_resources.hpp" #include "dbus/server/dbus_object.hpp" -#include "dbus/server/dbus_thread_object.hpp" - -#include "ncp/rcp_host.hpp" +#include "dbus/server/dbus_thread_object_ncp.hpp" +#include "dbus/server/dbus_thread_object_rcp.hpp" +#include "ncp/thread_host.hpp" namespace otbr { namespace DBus { @@ -59,16 +59,15 @@ class DBusAgent : public MainloopProcessor, private NonCopyable /** * The constructor of dbus agent. * - * @param[in] aHost A reference to the Thread controller. - * + * @param[in] aHost A reference to the Thread host. + * @param[in] aPublisher A reference to the MDNS publisher. */ - DBusAgent(otbr::Ncp::RcpHost &aHost, Mdns::Publisher &aPublisher); + DBusAgent(otbr::Ncp::ThreadHost &aHost, Mdns::Publisher &aPublisher); /** * This method initializes the dbus agent. - * */ - void Init(void); + void Init(otbr::BorderAgent &aBorderAgent); void Update(MainloopContext &aMainloop) override; void Process(const MainloopContext &aMainloop) override; @@ -85,15 +84,14 @@ class DBusAgent : public MainloopProcessor, private NonCopyable static const struct timeval kPollTimeout; - std::string mInterfaceName; - std::unique_ptr mThreadObject; - UniqueDBusConnection mConnection; - otbr::Ncp::RcpHost &mHost; - Mdns::Publisher &mPublisher; + std::string mInterfaceName; + std::unique_ptr mThreadObject; + UniqueDBusConnection mConnection; + otbr::Ncp::ThreadHost &mHost; + Mdns::Publisher &mPublisher; /** * This map is used to track DBusWatch-es. - * */ std::set mWatches; }; diff --git a/src/dbus/server/dbus_object.cpp b/src/dbus/server/dbus_object.cpp index 64c384a6b3c..4fd0f3cb23d 100644 --- a/src/dbus/server/dbus_object.cpp +++ b/src/dbus/server/dbus_object.cpp @@ -50,6 +50,11 @@ DBusObject::DBusObject(DBusConnection *aConnection, const std::string &aObjectPa } otbrError DBusObject::Init(void) +{ + return Initialize(/* aIsAsyncPropertyHandler */ false); +} + +otbrError DBusObject::Initialize(bool aIsAsyncPropertyHandler) { otbrError error = OTBR_ERROR_NONE; DBusObjectPathVTable vTable; @@ -60,12 +65,21 @@ otbrError DBusObject::Init(void) VerifyOrExit(dbus_connection_register_object_path(mConnection, mObjectPath.c_str(), &vTable, this), error = OTBR_ERROR_DBUS); - RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_GET_METHOD, - std::bind(&DBusObject::GetPropertyMethodHandler, this, _1)); - RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_SET_METHOD, - std::bind(&DBusObject::SetPropertyMethodHandler, this, _1)); - RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_GET_ALL_METHOD, - std::bind(&DBusObject::GetAllPropertiesMethodHandler, this, _1)); + + if (aIsAsyncPropertyHandler) + { + RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_GET_METHOD, + std::bind(&DBusObject::AsyncGetPropertyMethodHandler, this, _1)); + } + else + { + RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_GET_METHOD, + std::bind(&DBusObject::GetPropertyMethodHandler, this, _1)); + RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_SET_METHOD, + std::bind(&DBusObject::SetPropertyMethodHandler, this, _1)); + RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_GET_ALL_METHOD, + std::bind(&DBusObject::GetAllPropertiesMethodHandler, this, _1)); + } exit: return error; @@ -98,6 +112,13 @@ void DBusObject::RegisterSetPropertyHandler(const std::string &aInterfac mSetPropertyHandlers.emplace(fullPath, aHandler); } +void DBusObject::RegisterAsyncGetPropertyHandler(const std::string &aInterfaceName, + const std::string &aPropertyName, + const AsyncPropertyHandlerType &aHandler) +{ + mAsyncGetPropertyHandlers[aInterfaceName].emplace(aPropertyName, aHandler); +} + DBusHandlerResult DBusObject::sMessageHandler(DBusConnection *aConnection, DBusMessage *aMessage, void *aData) { DBusObject *server = reinterpret_cast(aData); @@ -252,6 +273,40 @@ void DBusObject::SetPropertyMethodHandler(DBusRequest &aRequest) return; } +void DBusObject::AsyncGetPropertyMethodHandler(DBusRequest &aRequest) +{ + DBusMessageIter iter; + std::string interfaceName; + otError error = OT_ERROR_NONE; + std::string propertyName; + + VerifyOrExit(dbus_message_iter_init(aRequest.GetMessage(), &iter), error = OT_ERROR_FAILED); + SuccessOrExit(error = OtbrErrorToOtError(DBusMessageExtract(&iter, interfaceName))); + SuccessOrExit(error = OtbrErrorToOtError(DBusMessageExtract(&iter, propertyName))); + + { + auto propertyIter = mAsyncGetPropertyHandlers.find(interfaceName); + + otbrLogDebug("AsyncGetProperty %s.%s", interfaceName.c_str(), propertyName.c_str()); + VerifyOrExit(propertyIter != mAsyncGetPropertyHandlers.end(), error = OT_ERROR_NOT_FOUND); + { + auto &interfaceHandlers = propertyIter->second; + auto interfaceIter = interfaceHandlers.find(propertyName); + + VerifyOrExit(interfaceIter != interfaceHandlers.end(), error = OT_ERROR_NOT_FOUND); + (interfaceIter->second)(aRequest); + } + } + +exit: + if (error != OT_ERROR_NONE) + { + otbrLogWarning("GetProperty %s.%s error:%s", interfaceName.c_str(), propertyName.c_str(), + ConvertToDBusErrorName(error)); + aRequest.ReplyOtResult(error); + } +} + DBusObject::~DBusObject(void) { } diff --git a/src/dbus/server/dbus_object.hpp b/src/dbus/server/dbus_object.hpp index 8aa335baf07..d77f045000e 100644 --- a/src/dbus/server/dbus_object.hpp +++ b/src/dbus/server/dbus_object.hpp @@ -60,21 +60,19 @@ namespace DBus { /** * This class is a base class for implementing a d-bus object. - * */ class DBusObject : private NonCopyable { public: - using MethodHandlerType = std::function; - - using PropertyHandlerType = std::function; + using MethodHandlerType = std::function; + using AsyncPropertyHandlerType = std::function; + using PropertyHandlerType = std::function; /** * The constructor of a d-bus object. * * @param[in] aConnection The dbus-connection the object bounds to. * @param[in] aObjectPath The path of the object. - * */ DBusObject(DBusConnection *aConnection, const std::string &aObjectPath); @@ -85,7 +83,6 @@ class DBusObject : private NonCopyable * * @retval OTBR_ERROR_NONE Successfully registered the object. * @retval OTBR_ERROR_DBUS Failed to ragister an object. - * */ virtual otbrError Init(void); @@ -95,7 +92,6 @@ class DBusObject : private NonCopyable * @param[in] aInterfaceName The interface name. * @param[in] aMethodName The method name. * @param[in] aHandler The method handler. - * */ void RegisterMethod(const std::string &aInterfaceName, const std::string &aMethodName, @@ -107,7 +103,6 @@ class DBusObject : private NonCopyable * @param[in] aInterfaceName The interface name. * @param[in] aPropertyName The property name. * @param[in] aHandler The method handler. - * */ virtual void RegisterGetPropertyHandler(const std::string &aInterfaceName, const std::string &aPropertyName, @@ -119,12 +114,22 @@ class DBusObject : private NonCopyable * @param[in] aInterfaceName The interface name. * @param[in] aPropertyName The property name. * @param[in] aHandler The method handler. - * */ virtual void RegisterSetPropertyHandler(const std::string &aInterfaceName, const std::string &aPropertyName, const PropertyHandlerType &aHandler); + /** + * This method registers the async get handler for a property. + * + * @param[in] aInterfaceName The interface name. + * @param[in] aPropertyName The property name. + * @param[in] aHandler The method handler. + */ + virtual void RegisterAsyncGetPropertyHandler(const std::string &aInterfaceName, + const std::string &aPropertyName, + const AsyncPropertyHandlerType &aHandler); + /** * This method sends a signal. * @@ -134,7 +139,6 @@ class DBusObject : private NonCopyable * * @retval OTBR_ERROR_NONE Signal successfully sent. * @retval OTBR_ERROR_DBUS Failed to send the signal. - * */ template otbrError Signal(const std::string &aInterfaceName, @@ -162,7 +166,6 @@ class DBusObject : private NonCopyable * * @retval OTBR_ERROR_NONE Signal successfully sent. * @retval OTBR_ERROR_DBUS Failed to send the signal. - * */ template otbrError SignalPropertyChanged(const std::string &aInterfaceName, @@ -210,20 +213,22 @@ class DBusObject : private NonCopyable /** * The destructor of a d-bus object. - * */ virtual ~DBusObject(void); /** * Sends all outgoing messages, blocks until the message queue is empty. - * */ void Flush(void); +protected: + otbrError Initialize(bool aIsAsyncPropertyHandler); + private: void GetAllPropertiesMethodHandler(DBusRequest &aRequest); void GetPropertyMethodHandler(DBusRequest &aRequest); void SetPropertyMethodHandler(DBusRequest &aRequest); + void AsyncGetPropertyMethodHandler(DBusRequest &aRequest); static DBusHandlerResult sMessageHandler(DBusConnection *aConnection, DBusMessage *aMessage, void *aData); DBusHandlerResult MessageHandler(DBusConnection *aConnection, DBusMessage *aMessage); @@ -232,9 +237,11 @@ class DBusObject : private NonCopyable std::unordered_map mMethodHandlers; std::unordered_map> mGetPropertyHandlers; - std::unordered_map mSetPropertyHandlers; - DBusConnection *mConnection; - std::string mObjectPath; + std::unordered_map> + mAsyncGetPropertyHandlers; + std::unordered_map mSetPropertyHandlers; + DBusConnection *mConnection; + std::string mObjectPath; }; } // namespace DBus diff --git a/src/dbus/server/dbus_request.hpp b/src/dbus/server/dbus_request.hpp index 2e7128657ea..27a803e6a72 100644 --- a/src/dbus/server/dbus_request.hpp +++ b/src/dbus/server/dbus_request.hpp @@ -53,7 +53,6 @@ namespace DBus { /** * This class represents a incoming call for a d-bus method. - * */ class DBusRequest { @@ -63,7 +62,6 @@ class DBusRequest * * @param[in] aConnection The dbus connection. * @param[in] aMessage The incoming dbus message. - * */ DBusRequest(DBusConnection *aConnection, DBusMessage *aMessage) : mConnection(aConnection) @@ -77,7 +75,6 @@ class DBusRequest * The copy constructor of dbus request. * * @param[in] aOther The object to be copied from. - * */ DBusRequest(const DBusRequest &aOther) : mConnection(nullptr) @@ -90,7 +87,6 @@ class DBusRequest * The assignment operator of dbus request. * * @param[in] aOther The object to be copied from. - * */ DBusRequest &operator=(const DBusRequest &aOther) { @@ -102,7 +98,6 @@ class DBusRequest * This method returns the message sent to call the d-bus method. * * @returns The dbus message. - * */ DBusMessage *GetMessage(void) { return mMessage; } @@ -110,7 +105,6 @@ class DBusRequest * This method returns underlying d-bus connection. * * @returns The dbus connection. - * */ DBusConnection *GetConnection(void) { return mConnection; } @@ -118,7 +112,6 @@ class DBusRequest * This method replies to the d-bus method call. * * @param[in] aReply The tuple to be sent. - * */ template void Reply(const std::tuple &aReply) { @@ -143,7 +136,6 @@ class DBusRequest * * @param[in] aError The error to be sent. * @param[in] aResult The return value of the method call, if any. - * */ template void ReplyOtResult(otError aError, Optional aResult = Optional()) @@ -186,7 +178,6 @@ class DBusRequest /** * The destructor of DBusRequest - * */ ~DBusRequest(void) { diff --git a/src/dbus/server/dbus_thread_object_ncp.cpp b/src/dbus/server/dbus_thread_object_ncp.cpp new file mode 100644 index 00000000000..526a477f6d9 --- /dev/null +++ b/src/dbus/server/dbus_thread_object_ncp.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2024, 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 "dbus_thread_object_ncp.hpp" + +#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 "utils/thread_helper.hpp" + +using std::placeholders::_1; +using std::placeholders::_2; + +namespace otbr { +namespace DBus { + +DBusThreadObjectNcp::DBusThreadObjectNcp(DBusConnection &aConnection, + const std::string &aInterfaceName, + otbr::Ncp::NcpHost &aHost) + : DBusObject(&aConnection, OTBR_DBUS_OBJECT_PREFIX + aInterfaceName) + , mHost(aHost) +{ +} + +otbrError DBusThreadObjectNcp::Init(void) +{ + otbrError error = OTBR_ERROR_NONE; + + SuccessOrExit(error = DBusObject::Initialize(true)); + + RegisterAsyncGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_DEVICE_ROLE, + std::bind(&DBusThreadObjectNcp::AsyncGetDeviceRoleHandler, this, _1)); + + RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_JOIN_METHOD, + std::bind(&DBusThreadObjectNcp::JoinHandler, this, _1)); + RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_LEAVE_NETWORK_METHOD, + std::bind(&DBusThreadObjectNcp::LeaveHandler, this, _1)); + RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_SCHEDULE_MIGRATION_METHOD, + std::bind(&DBusThreadObjectNcp::ScheduleMigrationHandler, this, _1)); + + SuccessOrExit(error = Signal(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_SIGNAL_READY, std::make_tuple())); +exit: + return error; +} + +void DBusThreadObjectNcp::AsyncGetDeviceRoleHandler(DBusRequest &aRequest) +{ + otDeviceRole role = mHost.GetDeviceRole(); + + ReplyAsyncGetProperty(aRequest, GetDeviceRoleName(role)); +} + +void DBusThreadObjectNcp::ReplyAsyncGetProperty(DBusRequest &aRequest, const std::string &aContent) +{ + UniqueDBusMessage reply{dbus_message_new_method_return(aRequest.GetMessage())}; + DBusMessageIter replyIter; + otError error = OT_ERROR_NONE; + + dbus_message_iter_init_append(reply.get(), &replyIter); + SuccessOrExit(error = OtbrErrorToOtError(DBusMessageEncodeToVariant(&replyIter, aContent))); + +exit: + if (error == OT_ERROR_NONE) + { + dbus_connection_send(aRequest.GetConnection(), reply.get(), nullptr); + } + else + { + aRequest.ReplyOtResult(error); + } +} + +void DBusThreadObjectNcp::JoinHandler(DBusRequest &aRequest) +{ + std::vector dataset; + otOperationalDatasetTlvs activeOpDatasetTlvs; + otError error = OT_ERROR_NONE; + + auto args = std::tie(dataset); + + SuccessOrExit(DBusMessageToTuple(*aRequest.GetMessage(), args), error = OT_ERROR_INVALID_ARGS); + + VerifyOrExit(dataset.size() <= sizeof(activeOpDatasetTlvs.mTlvs), error = OT_ERROR_INVALID_ARGS); + std::copy(dataset.begin(), dataset.end(), activeOpDatasetTlvs.mTlvs); + activeOpDatasetTlvs.mLength = dataset.size(); + + mHost.Join(activeOpDatasetTlvs, [aRequest](otError aError, const std::string &aErrorInfo) mutable { + OT_UNUSED_VARIABLE(aErrorInfo); + aRequest.ReplyOtResult(aError); + }); + +exit: + if (error != OT_ERROR_NONE) + { + aRequest.ReplyOtResult(error); + } +} + +void DBusThreadObjectNcp::LeaveHandler(DBusRequest &aRequest) +{ + mHost.Leave([aRequest](otError aError, const std::string &aErrorInfo) mutable { + OT_UNUSED_VARIABLE(aErrorInfo); + aRequest.ReplyOtResult(aError); + }); +} + +void DBusThreadObjectNcp::ScheduleMigrationHandler(DBusRequest &aRequest) +{ + std::vector dataset; + uint32_t delayInMilli; + otOperationalDatasetTlvs pendingOpDatasetTlvs; + otError error = OT_ERROR_NONE; + + auto args = std::tie(dataset, delayInMilli); + + SuccessOrExit(DBusMessageToTuple(*aRequest.GetMessage(), args), error = OT_ERROR_INVALID_ARGS); + + VerifyOrExit(dataset.size() <= sizeof(pendingOpDatasetTlvs.mTlvs), error = OT_ERROR_INVALID_ARGS); + std::copy(dataset.begin(), dataset.end(), pendingOpDatasetTlvs.mTlvs); + pendingOpDatasetTlvs.mLength = dataset.size(); + + SuccessOrExit(error = agent::ThreadHelper::ProcessDatasetForMigration(pendingOpDatasetTlvs, delayInMilli)); + + mHost.ScheduleMigration(pendingOpDatasetTlvs, [aRequest](otError aError, const std::string &aErrorInfo) mutable { + OT_UNUSED_VARIABLE(aErrorInfo); + aRequest.ReplyOtResult(aError); + }); + +exit: + if (error != OT_ERROR_NONE) + { + aRequest.ReplyOtResult(error); + } +} + +} // namespace DBus +} // namespace otbr diff --git a/src/dbus/server/dbus_thread_object_ncp.hpp b/src/dbus/server/dbus_thread_object_ncp.hpp new file mode 100644 index 00000000000..542dc260bd1 --- /dev/null +++ b/src/dbus/server/dbus_thread_object_ncp.hpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024, 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 the d-bus object of Thread service when + * the co-processor is an NCP. + */ + +#ifndef OTBR_DBUS_THREAD_OBJECT_NCP_HPP_ +#define OTBR_DBUS_THREAD_OBJECT_NCP_HPP_ + +#include "openthread-br/config.h" + +#include + +#include + +#include "dbus/server/dbus_object.hpp" +#include "mdns/mdns.hpp" +#include "ncp/ncp_host.hpp" + +namespace otbr { +namespace DBus { + +/** + * @addtogroup border-router-dbus-server + * + * @brief + * This module includes the dbus server api. + * + * @{ + */ + +class DBusThreadObjectNcp : public DBusObject +{ +public: + /** + * This constructor of dbus thread object. + * + * @param[in] aConnection The dbus connection. + * @param[in] aInterfaceName The dbus interface name. + * @param[in] aHost The Thread controller. + */ + DBusThreadObjectNcp(DBusConnection &aConnection, const std::string &aInterfaceName, otbr::Ncp::NcpHost &aHost); + + /** + * This method initializes the dbus thread object. + * + * @retval OTBR_ERROR_NONE The initialization succeeded. + * @retval OTBR_ERROR_DBUS The initialization failed due to dbus connection. + */ + otbrError Init(void) override; + +private: + void AsyncGetDeviceRoleHandler(DBusRequest &aRequest); + void ReplyAsyncGetProperty(DBusRequest &aRequest, const std::string &aContent); + + void JoinHandler(DBusRequest &aRequest); + void LeaveHandler(DBusRequest &aRequest); + void ScheduleMigrationHandler(DBusRequest &aRequest); + + otbr::Ncp::NcpHost &mHost; +}; + +/** + * @} + */ + +} // namespace DBus +} // namespace otbr + +#endif // OTBR_DBUS_THREAD_OBJECT_NCP_HPP_ diff --git a/src/dbus/server/dbus_thread_object.cpp b/src/dbus/server/dbus_thread_object_rcp.cpp similarity index 72% rename from src/dbus/server/dbus_thread_object.cpp rename to src/dbus/server/dbus_thread_object_rcp.cpp index aa0f6b33bbd..36307d71c25 100644 --- a/src/dbus/server/dbus_thread_object.cpp +++ b/src/dbus/server/dbus_thread_object_rcp.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -50,7 +51,7 @@ #include "common/code_utils.hpp" #include "dbus/common/constants.hpp" #include "dbus/server/dbus_agent.hpp" -#include "dbus/server/dbus_thread_object.hpp" +#include "dbus/server/dbus_thread_object_rcp.hpp" #if OTBR_ENABLE_FEATURE_FLAGS #include "proto/feature_flag.pb.h" #endif @@ -59,6 +60,16 @@ #endif #include "proto/capabilities.pb.h" +/** + * @def OTBR_CONFIG_BORDER_AGENT_MESHCOP_E_UDP_PORT + * + * Specifies the border agent UDP port for meshcop-e service. + * If zero, an ephemeral port will be used. + */ +#ifndef OTBR_CONFIG_BORDER_AGENT_MESHCOP_E_UDP_PORT +#define OTBR_CONFIG_BORDER_AGENT_MESHCOP_E_UDP_PORT 0 +#endif + using std::placeholders::_1; using std::placeholders::_2; @@ -90,195 +101,208 @@ static std::string GetNat64StateName(otNat64State aState) namespace otbr { namespace DBus { -DBusThreadObject::DBusThreadObject(DBusConnection *aConnection, - const std::string &aInterfaceName, - otbr::Ncp::RcpHost *aHost, - Mdns::Publisher *aPublisher) - : DBusObject(aConnection, OTBR_DBUS_OBJECT_PREFIX + aInterfaceName) +DBusThreadObjectRcp::DBusThreadObjectRcp(DBusConnection &aConnection, + const std::string &aInterfaceName, + otbr::Ncp::RcpHost &aHost, + Mdns::Publisher *aPublisher, + otbr::BorderAgent &aBorderAgent) + : DBusObject(&aConnection, OTBR_DBUS_OBJECT_PREFIX + aInterfaceName) , mHost(aHost) , mPublisher(aPublisher) + , mBorderAgent(aBorderAgent) { } -otbrError DBusThreadObject::Init(void) +otbrError DBusThreadObjectRcp::Init(void) { otbrError error = OTBR_ERROR_NONE; - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); - SuccessOrExit(error = DBusObject::Init()); + SuccessOrExit(error = DBusObject::Initialize(false)); - threadHelper->AddDeviceRoleHandler(std::bind(&DBusThreadObject::DeviceRoleHandler, this, _1)); - threadHelper->AddActiveDatasetChangeHandler(std::bind(&DBusThreadObject::ActiveDatasetChangeHandler, this, _1)); - mHost->RegisterResetHandler(std::bind(&DBusThreadObject::NcpResetHandler, this)); + threadHelper->AddDeviceRoleHandler(std::bind(&DBusThreadObjectRcp::DeviceRoleHandler, this, _1)); +#if OTBR_ENABLE_DHCP6_PD + threadHelper->SetDhcp6PdStateCallback(std::bind(&DBusThreadObjectRcp::Dhcp6PdStateHandler, this, _1)); +#endif + threadHelper->AddActiveDatasetChangeHandler(std::bind(&DBusThreadObjectRcp::ActiveDatasetChangeHandler, this, _1)); + mHost.RegisterResetHandler(std::bind(&DBusThreadObjectRcp::NcpResetHandler, this)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_SCAN_METHOD, - std::bind(&DBusThreadObject::ScanHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::ScanHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_ENERGY_SCAN_METHOD, - std::bind(&DBusThreadObject::EnergyScanHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::EnergyScanHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_ATTACH_METHOD, - std::bind(&DBusThreadObject::AttachHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::AttachHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_DETACH_METHOD, - std::bind(&DBusThreadObject::DetachHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::DetachHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_FACTORY_RESET_METHOD, - std::bind(&DBusThreadObject::FactoryResetHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::FactoryResetHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_RESET_METHOD, - std::bind(&DBusThreadObject::ResetHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::ResetHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_JOINER_START_METHOD, - std::bind(&DBusThreadObject::JoinerStartHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::JoinerStartHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_JOINER_STOP_METHOD, - std::bind(&DBusThreadObject::JoinerStopHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::JoinerStopHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PERMIT_UNSECURE_JOIN_METHOD, - std::bind(&DBusThreadObject::PermitUnsecureJoinHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::PermitUnsecureJoinHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_ADD_ON_MESH_PREFIX_METHOD, - std::bind(&DBusThreadObject::AddOnMeshPrefixHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::AddOnMeshPrefixHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_REMOVE_ON_MESH_PREFIX_METHOD, - std::bind(&DBusThreadObject::RemoveOnMeshPrefixHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::RemoveOnMeshPrefixHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_ADD_EXTERNAL_ROUTE_METHOD, - std::bind(&DBusThreadObject::AddExternalRouteHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::AddExternalRouteHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_REMOVE_EXTERNAL_ROUTE_METHOD, - std::bind(&DBusThreadObject::RemoveExternalRouteHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::RemoveExternalRouteHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_ATTACH_ALL_NODES_TO_METHOD, - std::bind(&DBusThreadObject::AttachAllNodesToHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::AttachAllNodesToHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_UPDATE_VENDOR_MESHCOP_TXT_METHOD, - std::bind(&DBusThreadObject::UpdateMeshCopTxtHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::UpdateMeshCopTxtHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_GET_PROPERTIES_METHOD, - std::bind(&DBusThreadObject::GetPropertiesHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetPropertiesHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_LEAVE_NETWORK_METHOD, - std::bind(&DBusThreadObject::LeaveNetworkHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::LeaveNetworkHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_SET_NAT64_ENABLED_METHOD, - std::bind(&DBusThreadObject::SetNat64Enabled, this, _1)); + std::bind(&DBusThreadObjectRcp::SetNat64Enabled, this, _1)); + RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_ACTIVATE_EPHEMERAL_KEY_MODE_METHOD, + std::bind(&DBusThreadObjectRcp::ActivateEphemeralKeyModeHandler, this, _1)); + RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_DEACTIVATE_EPHEMERAL_KEY_MODE_METHOD, + std::bind(&DBusThreadObjectRcp::DeactivateEphemeralKeyModeHandler, this, _1)); RegisterMethod(DBUS_INTERFACE_INTROSPECTABLE, DBUS_INTROSPECT_METHOD, - std::bind(&DBusThreadObject::IntrospectHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::IntrospectHandler, this, _1)); RegisterSetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_MESH_LOCAL_PREFIX, - std::bind(&DBusThreadObject::SetMeshLocalPrefixHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::SetMeshLocalPrefixHandler, this, _1)); RegisterSetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_LINK_MODE, - std::bind(&DBusThreadObject::SetLinkModeHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::SetLinkModeHandler, this, _1)); RegisterSetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_ACTIVE_DATASET_TLVS, - std::bind(&DBusThreadObject::SetActiveDatasetTlvsHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::SetActiveDatasetTlvsHandler, this, _1)); RegisterSetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_FEATURE_FLAG_LIST_DATA, - std::bind(&DBusThreadObject::SetFeatureFlagListDataHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::SetFeatureFlagListDataHandler, this, _1)); RegisterSetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_RADIO_REGION, - std::bind(&DBusThreadObject::SetRadioRegionHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::SetRadioRegionHandler, this, _1)); RegisterSetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_DNS_UPSTREAM_QUERY_STATE, - std::bind(&DBusThreadObject::SetDnsUpstreamQueryState, this, _1)); + std::bind(&DBusThreadObjectRcp::SetDnsUpstreamQueryState, this, _1)); RegisterSetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_NAT64_CIDR, - std::bind(&DBusThreadObject::SetNat64Cidr, this, _1)); + std::bind(&DBusThreadObjectRcp::SetNat64Cidr, this, _1)); + RegisterSetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_EPHEMERAL_KEY_ENABLED, + std::bind(&DBusThreadObjectRcp::SetEphemeralKeyEnabled, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_LINK_MODE, - std::bind(&DBusThreadObject::GetLinkModeHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetLinkModeHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_DEVICE_ROLE, - std::bind(&DBusThreadObject::GetDeviceRoleHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetDeviceRoleHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_NETWORK_NAME, - std::bind(&DBusThreadObject::GetNetworkNameHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetNetworkNameHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_PANID, - std::bind(&DBusThreadObject::GetPanIdHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetPanIdHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_EXTPANID, - std::bind(&DBusThreadObject::GetExtPanIdHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetExtPanIdHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_EUI64, - std::bind(&DBusThreadObject::GetEui64Handler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetEui64Handler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_CHANNEL, - std::bind(&DBusThreadObject::GetChannelHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetChannelHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_NETWORK_KEY, - std::bind(&DBusThreadObject::GetNetworkKeyHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetNetworkKeyHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_CCA_FAILURE_RATE, - std::bind(&DBusThreadObject::GetCcaFailureRateHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetCcaFailureRateHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_LINK_COUNTERS, - std::bind(&DBusThreadObject::GetLinkCountersHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetLinkCountersHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_IP6_COUNTERS, - std::bind(&DBusThreadObject::GetIp6CountersHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetIp6CountersHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_SUPPORTED_CHANNEL_MASK, - std::bind(&DBusThreadObject::GetSupportedChannelMaskHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetSupportedChannelMaskHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_PREFERRED_CHANNEL_MASK, - std::bind(&DBusThreadObject::GetPreferredChannelMaskHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetPreferredChannelMaskHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_RLOC16, - std::bind(&DBusThreadObject::GetRloc16Handler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetRloc16Handler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_EXTENDED_ADDRESS, - std::bind(&DBusThreadObject::GetExtendedAddressHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetExtendedAddressHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_ROUTER_ID, - std::bind(&DBusThreadObject::GetRouterIdHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetRouterIdHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_LEADER_DATA, - std::bind(&DBusThreadObject::GetLeaderDataHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetLeaderDataHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_NETWORK_DATA_PRPOERTY, - std::bind(&DBusThreadObject::GetNetworkDataHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetNetworkDataHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_STABLE_NETWORK_DATA_PRPOERTY, - std::bind(&DBusThreadObject::GetStableNetworkDataHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetStableNetworkDataHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_LOCAL_LEADER_WEIGHT, - std::bind(&DBusThreadObject::GetLocalLeaderWeightHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetLocalLeaderWeightHandler, this, _1)); #if OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_CHANNEL_MONITOR_SAMPLE_COUNT, - std::bind(&DBusThreadObject::GetChannelMonitorSampleCountHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetChannelMonitorSampleCountHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_CHANNEL_MONITOR_ALL_CHANNEL_QUALITIES, - std::bind(&DBusThreadObject::GetChannelMonitorAllChannelQualities, this, _1)); + std::bind(&DBusThreadObjectRcp::GetChannelMonitorAllChannelQualities, this, _1)); #endif RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_CHILD_TABLE, - std::bind(&DBusThreadObject::GetChildTableHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetChildTableHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_NEIGHBOR_TABLE_PROEPRTY, - std::bind(&DBusThreadObject::GetNeighborTableHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetNeighborTableHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_PARTITION_ID_PROEPRTY, - std::bind(&DBusThreadObject::GetPartitionIDHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetPartitionIDHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_INSTANT_RSSI, - std::bind(&DBusThreadObject::GetInstantRssiHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetInstantRssiHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_RADIO_TX_POWER, - std::bind(&DBusThreadObject::GetRadioTxPowerHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetRadioTxPowerHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_EXTERNAL_ROUTES, - std::bind(&DBusThreadObject::GetExternalRoutesHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetExternalRoutesHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_ON_MESH_PREFIXES, - std::bind(&DBusThreadObject::GetOnMeshPrefixesHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetOnMeshPrefixesHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_ACTIVE_DATASET_TLVS, - std::bind(&DBusThreadObject::GetActiveDatasetTlvsHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetActiveDatasetTlvsHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_PENDING_DATASET_TLVS, - std::bind(&DBusThreadObject::GetPendingDatasetTlvsHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetPendingDatasetTlvsHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_FEATURE_FLAG_LIST_DATA, - std::bind(&DBusThreadObject::GetFeatureFlagListDataHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetFeatureFlagListDataHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_RADIO_REGION, - std::bind(&DBusThreadObject::GetRadioRegionHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetRadioRegionHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_SRP_SERVER_INFO, - std::bind(&DBusThreadObject::GetSrpServerInfoHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetSrpServerInfoHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_MDNS_TELEMETRY_INFO, - std::bind(&DBusThreadObject::GetMdnsTelemetryInfoHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetMdnsTelemetryInfoHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_DNSSD_COUNTERS, - std::bind(&DBusThreadObject::GetDnssdCountersHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetDnssdCountersHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_OTBR_VERSION, - std::bind(&DBusThreadObject::GetOtbrVersionHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetOtbrVersionHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_OT_HOST_VERSION, - std::bind(&DBusThreadObject::GetOtHostVersionHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetOtHostVersionHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_OT_RCP_VERSION, - std::bind(&DBusThreadObject::GetOtRcpVersionHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetOtRcpVersionHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_THREAD_VERSION, - std::bind(&DBusThreadObject::GetThreadVersionHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetThreadVersionHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_RADIO_SPINEL_METRICS, - std::bind(&DBusThreadObject::GetRadioSpinelMetricsHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetRadioSpinelMetricsHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_RCP_INTERFACE_METRICS, - std::bind(&DBusThreadObject::GetRcpInterfaceMetricsHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetRcpInterfaceMetricsHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_UPTIME, - std::bind(&DBusThreadObject::GetUptimeHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetUptimeHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_RADIO_COEX_METRICS, - std::bind(&DBusThreadObject::GetRadioCoexMetrics, this, _1)); + std::bind(&DBusThreadObjectRcp::GetRadioCoexMetrics, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_BORDER_ROUTING_COUNTERS, - std::bind(&DBusThreadObject::GetBorderRoutingCountersHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetBorderRoutingCountersHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_NAT64_STATE, - std::bind(&DBusThreadObject::GetNat64State, this, _1)); + std::bind(&DBusThreadObjectRcp::GetNat64State, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_NAT64_MAPPINGS, - std::bind(&DBusThreadObject::GetNat64Mappings, this, _1)); + std::bind(&DBusThreadObjectRcp::GetNat64Mappings, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_NAT64_PROTOCOL_COUNTERS, - std::bind(&DBusThreadObject::GetNat64ProtocolCounters, this, _1)); + std::bind(&DBusThreadObjectRcp::GetNat64ProtocolCounters, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_NAT64_ERROR_COUNTERS, - std::bind(&DBusThreadObject::GetNat64ErrorCounters, this, _1)); + std::bind(&DBusThreadObjectRcp::GetNat64ErrorCounters, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_NAT64_CIDR, - std::bind(&DBusThreadObject::GetNat64Cidr, this, _1)); + std::bind(&DBusThreadObjectRcp::GetNat64Cidr, this, _1)); + RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_EPHEMERAL_KEY_ENABLED, + std::bind(&DBusThreadObjectRcp::GetEphemeralKeyEnabled, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_INFRA_LINK_INFO, - std::bind(&DBusThreadObject::GetInfraLinkInfo, this, _1)); + std::bind(&DBusThreadObjectRcp::GetInfraLinkInfo, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_TREL_INFO, - std::bind(&DBusThreadObject::GetTrelInfoHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetTrelInfoHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_DNS_UPSTREAM_QUERY_STATE, - std::bind(&DBusThreadObject::GetDnsUpstreamQueryState, this, _1)); + std::bind(&DBusThreadObjectRcp::GetDnsUpstreamQueryState, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_TELEMETRY_DATA, - std::bind(&DBusThreadObject::GetTelemetryDataHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetTelemetryDataHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_CAPABILITIES, - std::bind(&DBusThreadObject::GetCapabilitiesHandler, this, _1)); + std::bind(&DBusThreadObjectRcp::GetCapabilitiesHandler, this, _1)); SuccessOrExit(error = Signal(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_SIGNAL_READY, std::make_tuple())); @@ -286,29 +310,37 @@ otbrError DBusThreadObject::Init(void) return error; } -void DBusThreadObject::DeviceRoleHandler(otDeviceRole aDeviceRole) +void DBusThreadObjectRcp::DeviceRoleHandler(otDeviceRole aDeviceRole) { SignalPropertyChanged(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_DEVICE_ROLE, GetDeviceRoleName(aDeviceRole)); } -void DBusThreadObject::NcpResetHandler(void) +#if OTBR_ENABLE_DHCP6_PD +void DBusThreadObjectRcp::Dhcp6PdStateHandler(otBorderRoutingDhcp6PdState aDhcp6PdState) { - mHost->GetThreadHelper()->AddDeviceRoleHandler(std::bind(&DBusThreadObject::DeviceRoleHandler, this, _1)); - mHost->GetThreadHelper()->AddActiveDatasetChangeHandler( - std::bind(&DBusThreadObject::ActiveDatasetChangeHandler, this, _1)); + SignalPropertyChanged(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_DHCP6_PD_STATE, + GetDhcp6PdStateName(aDhcp6PdState)); +} +#endif + +void DBusThreadObjectRcp::NcpResetHandler(void) +{ + mHost.GetThreadHelper()->AddDeviceRoleHandler(std::bind(&DBusThreadObjectRcp::DeviceRoleHandler, this, _1)); + mHost.GetThreadHelper()->AddActiveDatasetChangeHandler( + std::bind(&DBusThreadObjectRcp::ActiveDatasetChangeHandler, this, _1)); SignalPropertyChanged(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_DEVICE_ROLE, GetDeviceRoleName(OT_DEVICE_ROLE_DISABLED)); } -void DBusThreadObject::ScanHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::ScanHandler(DBusRequest &aRequest) { - auto threadHelper = mHost->GetThreadHelper(); - threadHelper->Scan(std::bind(&DBusThreadObject::ReplyScanResult, this, aRequest, _1, _2)); + auto threadHelper = mHost.GetThreadHelper(); + threadHelper->Scan(std::bind(&DBusThreadObjectRcp::ReplyScanResult, this, aRequest, _1, _2)); } -void DBusThreadObject::ReplyScanResult(DBusRequest &aRequest, - otError aError, - const std::vector &aResult) +void DBusThreadObjectRcp::ReplyScanResult(DBusRequest &aRequest, + otError aError, + const std::vector &aResult) { std::vector results; @@ -335,16 +367,17 @@ void DBusThreadObject::ReplyScanResult(DBusRequest &aR } } -void DBusThreadObject::EnergyScanHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::EnergyScanHandler(DBusRequest &aRequest) { otError error = OT_ERROR_NONE; - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); uint32_t scanDuration; auto args = std::tie(scanDuration); VerifyOrExit(DBusMessageToTuple(*aRequest.GetMessage(), args) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); - threadHelper->EnergyScan(scanDuration, std::bind(&DBusThreadObject::ReplyEnergyScanResult, this, aRequest, _1, _2)); + threadHelper->EnergyScan(scanDuration, + std::bind(&DBusThreadObjectRcp::ReplyEnergyScanResult, this, aRequest, _1, _2)); exit: if (error != OT_ERROR_NONE) @@ -353,9 +386,9 @@ void DBusThreadObject::EnergyScanHandler(DBusRequest &aRequest) } } -void DBusThreadObject::ReplyEnergyScanResult(DBusRequest &aRequest, - otError aError, - const std::vector &aResult) +void DBusThreadObjectRcp::ReplyEnergyScanResult(DBusRequest &aRequest, + otError aError, + const std::vector &aResult) { std::vector results; @@ -379,9 +412,9 @@ void DBusThreadObject::ReplyEnergyScanResult(DBusRequest } } -void DBusThreadObject::AttachHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::AttachHandler(DBusRequest &aRequest) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); std::string name; uint16_t panid; uint64_t extPanId; @@ -414,7 +447,7 @@ void DBusThreadObject::AttachHandler(DBusRequest &aRequest) } } -void DBusThreadObject::AttachAllNodesToHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::AttachAllNodesToHandler(DBusRequest &aRequest) { std::vector dataset; otError error = OT_ERROR_NONE; @@ -423,7 +456,7 @@ void DBusThreadObject::AttachAllNodesToHandler(DBusRequest &aRequest) VerifyOrExit(DBusMessageToTuple(*aRequest.GetMessage(), args) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); - mHost->GetThreadHelper()->AttachAllNodesTo(dataset, [aRequest](otError error, int64_t aAttachDelayMs) mutable { + mHost.GetThreadHelper()->AttachAllNodesTo(dataset, [aRequest](otError error, int64_t aAttachDelayMs) mutable { aRequest.ReplyOtResult(error, aAttachDelayMs); }); @@ -434,32 +467,32 @@ void DBusThreadObject::AttachAllNodesToHandler(DBusRequest &aRequest) } } -void DBusThreadObject::DetachHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::DetachHandler(DBusRequest &aRequest) { - aRequest.ReplyOtResult(mHost->GetThreadHelper()->Detach()); + aRequest.ReplyOtResult(mHost.GetThreadHelper()->Detach()); } -void DBusThreadObject::FactoryResetHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::FactoryResetHandler(DBusRequest &aRequest) { otError error = OT_ERROR_NONE; - SuccessOrExit(error = mHost->GetThreadHelper()->Detach()); - SuccessOrExit(otInstanceErasePersistentInfo(mHost->GetThreadHelper()->GetInstance())); - mHost->Reset(); + SuccessOrExit(error = mHost.GetThreadHelper()->Detach()); + SuccessOrExit(otInstanceErasePersistentInfo(mHost.GetThreadHelper()->GetInstance())); + mHost.Reset(); exit: aRequest.ReplyOtResult(error); } -void DBusThreadObject::ResetHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::ResetHandler(DBusRequest &aRequest) { - mHost->Reset(); + mHost.Reset(); aRequest.ReplyOtResult(OT_ERROR_NONE); } -void DBusThreadObject::JoinerStartHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::JoinerStartHandler(DBusRequest &aRequest) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); std::string pskd, provisionUrl, vendorName, vendorModel, vendorSwVersion, vendorData; auto args = std::tie(pskd, provisionUrl, vendorName, vendorModel, vendorSwVersion, vendorData); @@ -474,18 +507,18 @@ void DBusThreadObject::JoinerStartHandler(DBusRequest &aRequest) } } -void DBusThreadObject::JoinerStopHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::JoinerStopHandler(DBusRequest &aRequest) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otJoinerStop(threadHelper->GetInstance()); aRequest.ReplyOtResult(OT_ERROR_NONE); } -void DBusThreadObject::PermitUnsecureJoinHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::PermitUnsecureJoinHandler(DBusRequest &aRequest) { #ifdef OTBR_ENABLE_UNSECURE_JOIN - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); uint16_t port; uint32_t timeout; auto args = std::tie(port, timeout); @@ -503,9 +536,9 @@ void DBusThreadObject::PermitUnsecureJoinHandler(DBusRequest &aRequest) #endif } -void DBusThreadObject::AddOnMeshPrefixHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::AddOnMeshPrefixHandler(DBusRequest &aRequest) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); OnMeshPrefix onMeshPrefix; auto args = std::tie(onMeshPrefix); otError error = OT_ERROR_NONE; @@ -532,9 +565,9 @@ void DBusThreadObject::AddOnMeshPrefixHandler(DBusRequest &aRequest) aRequest.ReplyOtResult(error); } -void DBusThreadObject::RemoveOnMeshPrefixHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::RemoveOnMeshPrefixHandler(DBusRequest &aRequest) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); Ip6Prefix onMeshPrefix; auto args = std::tie(onMeshPrefix); otError error = OT_ERROR_NONE; @@ -552,9 +585,9 @@ void DBusThreadObject::RemoveOnMeshPrefixHandler(DBusRequest &aRequest) aRequest.ReplyOtResult(error); } -void DBusThreadObject::AddExternalRouteHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::AddExternalRouteHandler(DBusRequest &aRequest) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); ExternalRoute route; auto args = std::tie(route); otError error = OT_ERROR_NONE; @@ -579,9 +612,9 @@ void DBusThreadObject::AddExternalRouteHandler(DBusRequest &aRequest) aRequest.ReplyOtResult(error); } -void DBusThreadObject::RemoveExternalRouteHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::RemoveExternalRouteHandler(DBusRequest &aRequest) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); Ip6Prefix routePrefix; auto args = std::tie(routePrefix); otError error = OT_ERROR_NONE; @@ -600,7 +633,7 @@ void DBusThreadObject::RemoveExternalRouteHandler(DBusRequest &aRequest) aRequest.ReplyOtResult(error); } -void DBusThreadObject::IntrospectHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::IntrospectHandler(DBusRequest &aRequest) { std::string xmlString( #include "dbus/server/introspect.hpp" @@ -609,9 +642,9 @@ void DBusThreadObject::IntrospectHandler(DBusRequest &aRequest) aRequest.Reply(std::tie(xmlString)); } -otError DBusThreadObject::SetMeshLocalPrefixHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::SetMeshLocalPrefixHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otMeshLocalPrefix prefix; std::array data{}; otError error = OT_ERROR_NONE; @@ -624,9 +657,9 @@ otError DBusThreadObject::SetMeshLocalPrefixHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::SetLinkModeHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::SetLinkModeHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); LinkModeConfig cfg; otLinkModeConfig otCfg; otError error = OT_ERROR_NONE; @@ -641,9 +674,9 @@ otError DBusThreadObject::SetLinkModeHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetLinkModeHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetLinkModeHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otLinkModeConfig otCfg = otThreadGetLinkMode(threadHelper->GetInstance()); LinkModeConfig cfg; otError error = OT_ERROR_NONE; @@ -658,9 +691,9 @@ otError DBusThreadObject::GetLinkModeHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetDeviceRoleHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetDeviceRoleHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otDeviceRole role = otThreadGetDeviceRole(threadHelper->GetInstance()); std::string roleName = GetDeviceRoleName(role); otError error = OT_ERROR_NONE; @@ -671,9 +704,9 @@ otError DBusThreadObject::GetDeviceRoleHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetNetworkNameHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetNetworkNameHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); std::string networkName = otThreadGetNetworkName(threadHelper->GetInstance()); otError error = OT_ERROR_NONE; @@ -683,9 +716,9 @@ otError DBusThreadObject::GetNetworkNameHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetPanIdHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetPanIdHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); uint16_t panId = otLinkGetPanId(threadHelper->GetInstance()); otError error = OT_ERROR_NONE; @@ -695,9 +728,9 @@ otError DBusThreadObject::GetPanIdHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetExtPanIdHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetExtPanIdHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); const otExtendedPanId *extPanId = otThreadGetExtendedPanId(threadHelper->GetInstance()); uint64_t extPanIdVal; otError error = OT_ERROR_NONE; @@ -710,9 +743,9 @@ otError DBusThreadObject::GetExtPanIdHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetChannelHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetChannelHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); uint16_t channel = otLinkGetChannel(threadHelper->GetInstance()); otError error = OT_ERROR_NONE; @@ -722,9 +755,9 @@ otError DBusThreadObject::GetChannelHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetNetworkKeyHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetNetworkKeyHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otNetworkKey networkKey; otError error = OT_ERROR_NONE; @@ -736,9 +769,9 @@ otError DBusThreadObject::GetNetworkKeyHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetCcaFailureRateHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetCcaFailureRateHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); uint16_t failureRate = otLinkGetCcaFailureRate(threadHelper->GetInstance()); otError error = OT_ERROR_NONE; @@ -748,9 +781,9 @@ otError DBusThreadObject::GetCcaFailureRateHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetLinkCountersHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetLinkCountersHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); const otMacCounters *otCounters = otLinkGetCounters(threadHelper->GetInstance()); MacCounters counters; otError error = OT_ERROR_NONE; @@ -794,9 +827,9 @@ otError DBusThreadObject::GetLinkCountersHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetIp6CountersHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetIp6CountersHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); const otIpCounters *otCounters = otThreadGetIp6Counters(threadHelper->GetInstance()); IpCounters counters; otError error = OT_ERROR_NONE; @@ -812,9 +845,9 @@ otError DBusThreadObject::GetIp6CountersHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetSupportedChannelMaskHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetSupportedChannelMaskHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); uint32_t channelMask = otLinkGetSupportedChannelMask(threadHelper->GetInstance()); otError error = OT_ERROR_NONE; @@ -824,9 +857,9 @@ otError DBusThreadObject::GetSupportedChannelMaskHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetPreferredChannelMaskHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetPreferredChannelMaskHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); uint32_t channelMask = otPlatRadioGetPreferredChannelMask(threadHelper->GetInstance()); otError error = OT_ERROR_NONE; @@ -836,9 +869,9 @@ otError DBusThreadObject::GetPreferredChannelMaskHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetRloc16Handler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetRloc16Handler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; uint16_t rloc16 = otThreadGetRloc16(threadHelper->GetInstance()); @@ -848,9 +881,9 @@ otError DBusThreadObject::GetRloc16Handler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetExtendedAddressHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetExtendedAddressHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; const otExtAddress *addr = otLinkGetExtendedAddress(threadHelper->GetInstance()); uint64_t extendedAddress = ConvertOpenThreadUint64(addr->m8); @@ -861,9 +894,9 @@ otError DBusThreadObject::GetExtendedAddressHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetRouterIdHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetRouterIdHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; uint16_t rloc16 = otThreadGetRloc16(threadHelper->GetInstance()); otRouterInfo info; @@ -876,9 +909,9 @@ otError DBusThreadObject::GetRouterIdHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetLeaderDataHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetLeaderDataHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; struct otLeaderData data; LeaderData leaderData; @@ -895,10 +928,10 @@ otError DBusThreadObject::GetLeaderDataHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetNetworkDataHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetNetworkDataHandler(DBusMessageIter &aIter) { static constexpr size_t kNetworkDataMaxSize = 255; - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; uint8_t data[kNetworkDataMaxSize]; uint8_t len = sizeof(data); @@ -912,10 +945,10 @@ otError DBusThreadObject::GetNetworkDataHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetStableNetworkDataHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetStableNetworkDataHandler(DBusMessageIter &aIter) { static constexpr size_t kNetworkDataMaxSize = 255; - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; uint8_t data[kNetworkDataMaxSize]; uint8_t len = sizeof(data); @@ -929,9 +962,9 @@ otError DBusThreadObject::GetStableNetworkDataHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetLocalLeaderWeightHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetLocalLeaderWeightHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; uint8_t weight = otThreadGetLocalLeaderWeight(threadHelper->GetInstance()); @@ -941,10 +974,10 @@ otError DBusThreadObject::GetLocalLeaderWeightHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetChannelMonitorSampleCountHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetChannelMonitorSampleCountHandler(DBusMessageIter &aIter) { #if OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; uint32_t cnt = otChannelMonitorGetSampleCount(threadHelper->GetInstance()); @@ -958,10 +991,10 @@ otError DBusThreadObject::GetChannelMonitorSampleCountHandler(DBusMessageIter &a #endif // OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE } -otError DBusThreadObject::GetChannelMonitorAllChannelQualities(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetChannelMonitorAllChannelQualities(DBusMessageIter &aIter) { #if OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; uint32_t channelMask = otLinkGetSupportedChannelMask(threadHelper->GetInstance()); constexpr uint8_t kNumChannels = sizeof(channelMask) * 8; // 8 bit per byte @@ -987,9 +1020,9 @@ otError DBusThreadObject::GetChannelMonitorAllChannelQualities(DBusMessageIter & #endif // OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE } -otError DBusThreadObject::GetChildTableHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetChildTableHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; uint16_t childIndex = 0; otChildInfo childInfo; @@ -1023,9 +1056,9 @@ otError DBusThreadObject::GetChildTableHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetNeighborTableHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetNeighborTableHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; otNeighborInfoIterator iter = OT_NEIGHBOR_INFO_ITERATOR_INIT; otNeighborInfo neighborInfo; @@ -1059,9 +1092,9 @@ otError DBusThreadObject::GetNeighborTableHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetPartitionIDHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetPartitionIDHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; uint32_t partitionId = otThreadGetPartitionId(threadHelper->GetInstance()); @@ -1071,9 +1104,9 @@ otError DBusThreadObject::GetPartitionIDHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetInstantRssiHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetInstantRssiHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; int8_t rssi = otPlatRadioGetRssi(threadHelper->GetInstance()); @@ -1083,9 +1116,9 @@ otError DBusThreadObject::GetInstantRssiHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetRadioTxPowerHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetRadioTxPowerHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; int8_t txPower; @@ -1097,9 +1130,9 @@ otError DBusThreadObject::GetRadioTxPowerHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetExternalRoutesHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetExternalRoutesHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT; otExternalRouteConfig config; @@ -1126,9 +1159,9 @@ otError DBusThreadObject::GetExternalRoutesHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetOnMeshPrefixesHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetOnMeshPrefixesHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT; otBorderRouterConfig config; @@ -1160,9 +1193,9 @@ otError DBusThreadObject::GetOnMeshPrefixesHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::SetActiveDatasetTlvsHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::SetActiveDatasetTlvsHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); std::vector data; otOperationalDatasetTlvs datasetTlvs; otError error = OT_ERROR_NONE; @@ -1177,9 +1210,9 @@ otError DBusThreadObject::SetActiveDatasetTlvsHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetActiveDatasetTlvsHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetActiveDatasetTlvsHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; std::vector data; otOperationalDatasetTlvs datasetTlvs; @@ -1193,9 +1226,9 @@ otError DBusThreadObject::GetActiveDatasetTlvsHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetPendingDatasetTlvsHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetPendingDatasetTlvsHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; std::vector data; otOperationalDatasetTlvs datasetTlvs; @@ -1209,7 +1242,7 @@ otError DBusThreadObject::GetPendingDatasetTlvsHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::SetFeatureFlagListDataHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::SetFeatureFlagListDataHandler(DBusMessageIter &aIter) { #if OTBR_ENABLE_FEATURE_FLAGS otError error = OT_ERROR_NONE; @@ -1218,7 +1251,11 @@ otError DBusThreadObject::SetFeatureFlagListDataHandler(DBusMessageIter &aIter) VerifyOrExit(DBusMessageExtractFromVariant(&aIter, data) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); VerifyOrExit(featureFlagList.ParseFromString(std::string(data.begin(), data.end())), error = OT_ERROR_INVALID_ARGS); - VerifyOrExit((error = mHost->ApplyFeatureFlagList(featureFlagList)) == OT_ERROR_NONE); + // TODO: implement the feature flag handler at every component + mBorderAgent.SetEphemeralKeyEnabled(featureFlagList.enable_ephemeralkey()); + otbrLogInfo("Border Agent Ephemeral Key Feature has been %s by feature flag", + (featureFlagList.enable_ephemeralkey() ? "enable" : "disable")); + VerifyOrExit((error = mHost.ApplyFeatureFlagList(featureFlagList)) == OT_ERROR_NONE); exit: return error; #else @@ -1227,11 +1264,11 @@ otError DBusThreadObject::SetFeatureFlagListDataHandler(DBusMessageIter &aIter) #endif } -otError DBusThreadObject::GetFeatureFlagListDataHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetFeatureFlagListDataHandler(DBusMessageIter &aIter) { #if OTBR_ENABLE_FEATURE_FLAGS otError error = OT_ERROR_NONE; - const std::string appliedFeatureFlagListBytes = mHost->GetAppliedFeatureFlagListBytes(); + const std::string appliedFeatureFlagListBytes = mHost.GetAppliedFeatureFlagListBytes(); std::vector data(appliedFeatureFlagListBytes.begin(), appliedFeatureFlagListBytes.end()); VerifyOrExit(DBusMessageEncodeToVariant(&aIter, data) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); @@ -1244,9 +1281,9 @@ otError DBusThreadObject::GetFeatureFlagListDataHandler(DBusMessageIter &aIter) #endif } -otError DBusThreadObject::SetRadioRegionHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::SetRadioRegionHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); std::string radioRegion; uint16_t regionCode; otError error = OT_ERROR_NONE; @@ -1261,9 +1298,9 @@ otError DBusThreadObject::SetRadioRegionHandler(DBusMessageIter &aIter) return error; } -void DBusThreadObject::UpdateMeshCopTxtHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::UpdateMeshCopTxtHandler(DBusRequest &aRequest) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; std::map> update; std::vector updatedTxtEntries; @@ -1284,9 +1321,9 @@ void DBusThreadObject::UpdateMeshCopTxtHandler(DBusRequest &aRequest) aRequest.ReplyOtResult(error); } -otError DBusThreadObject::GetRadioRegionHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetRadioRegionHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; std::string radioRegion; uint16_t regionCode; @@ -1302,10 +1339,10 @@ otError DBusThreadObject::GetRadioRegionHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetSrpServerInfoHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetSrpServerInfoHandler(DBusMessageIter &aIter) { #if OTBR_ENABLE_SRP_ADVERTISING_PROXY - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); auto instance = threadHelper->GetInstance(); otError error = OT_ERROR_NONE; SrpServerInfo srpServerInfo{}; @@ -1371,7 +1408,7 @@ otError DBusThreadObject::GetSrpServerInfoHandler(DBusMessageIter &aIter) #endif // OTBR_ENABLE_SRP_ADVERTISING_PROXY } -otError DBusThreadObject::GetMdnsTelemetryInfoHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetMdnsTelemetryInfoHandler(DBusMessageIter &aIter) { otError error = OT_ERROR_NONE; @@ -1381,10 +1418,10 @@ otError DBusThreadObject::GetMdnsTelemetryInfoHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetDnssdCountersHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetDnssdCountersHandler(DBusMessageIter &aIter) { #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); auto instance = threadHelper->GetInstance(); otError error = OT_ERROR_NONE; DnssdCounters dnssdCounters; @@ -1410,10 +1447,10 @@ otError DBusThreadObject::GetDnssdCountersHandler(DBusMessageIter &aIter) #endif // OTBR_ENABLE_DNSSD_DISCOVERY_PROXY } -otError DBusThreadObject::GetTrelInfoHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetTrelInfoHandler(DBusMessageIter &aIter) { #if OTBR_ENABLE_TREL - auto instance = mHost->GetThreadHelper()->GetInstance(); + auto instance = mHost.GetThreadHelper()->GetInstance(); otError error = OT_ERROR_NONE; TrelInfo trelInfo; otTrelCounters otTrelCounters = *otTrelGetCounters(instance); @@ -1437,12 +1474,12 @@ otError DBusThreadObject::GetTrelInfoHandler(DBusMessageIter &aIter) #endif // OTBR_ENABLE_TREL } -otError DBusThreadObject::GetTelemetryDataHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetTelemetryDataHandler(DBusMessageIter &aIter) { #if OTBR_ENABLE_TELEMETRY_DATA_API otError error = OT_ERROR_NONE; threadnetwork::TelemetryData telemetryData; - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); if (threadHelper->RetrieveTelemetryData(mPublisher, telemetryData) != OT_ERROR_NONE) { @@ -1464,7 +1501,7 @@ otError DBusThreadObject::GetTelemetryDataHandler(DBusMessageIter &aIter) #endif } -otError DBusThreadObject::GetCapabilitiesHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetCapabilitiesHandler(DBusMessageIter &aIter) { otError error = OT_ERROR_NONE; otbr::Capabilities capabilities; @@ -1483,7 +1520,7 @@ otError DBusThreadObject::GetCapabilitiesHandler(DBusMessageIter &aIter) return error; } -void DBusThreadObject::GetPropertiesHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::GetPropertiesHandler(DBusRequest &aRequest) { UniqueDBusMessage reply(dbus_message_new_method_return(aRequest.GetMessage())); DBusMessageIter iter; @@ -1524,15 +1561,15 @@ void DBusThreadObject::GetPropertiesHandler(DBusRequest &aRequest) } } -void DBusThreadObject::RegisterGetPropertyHandler(const std::string &aInterfaceName, - const std::string &aPropertyName, - const PropertyHandlerType &aHandler) +void DBusThreadObjectRcp::RegisterGetPropertyHandler(const std::string &aInterfaceName, + const std::string &aPropertyName, + const PropertyHandlerType &aHandler) { DBusObject::RegisterGetPropertyHandler(aInterfaceName, aPropertyName, aHandler); mGetPropertyHandlers[aPropertyName] = aHandler; } -otError DBusThreadObject::GetOtbrVersionHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetOtbrVersionHandler(DBusMessageIter &aIter) { otError error = OT_ERROR_NONE; std::string version = OTBR_PACKAGE_VERSION; @@ -1543,7 +1580,7 @@ otError DBusThreadObject::GetOtbrVersionHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetOtHostVersionHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetOtHostVersionHandler(DBusMessageIter &aIter) { otError error = OT_ERROR_NONE; std::string version = otGetVersionString(); @@ -1554,9 +1591,9 @@ otError DBusThreadObject::GetOtHostVersionHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetEui64Handler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetEui64Handler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; otExtAddress extAddr; uint64_t eui64; @@ -1571,9 +1608,9 @@ otError DBusThreadObject::GetEui64Handler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetOtRcpVersionHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetOtRcpVersionHandler(DBusMessageIter &aIter) { - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); otError error = OT_ERROR_NONE; std::string version = otGetRadioVersionString(threadHelper->GetInstance()); @@ -1583,7 +1620,7 @@ otError DBusThreadObject::GetOtRcpVersionHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetThreadVersionHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetThreadVersionHandler(DBusMessageIter &aIter) { otError error = OT_ERROR_NONE; @@ -1593,7 +1630,7 @@ otError DBusThreadObject::GetThreadVersionHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetRadioSpinelMetricsHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetRadioSpinelMetricsHandler(DBusMessageIter &aIter) { otError error = OT_ERROR_NONE; RadioSpinelMetrics radioSpinelMetrics; @@ -1611,7 +1648,7 @@ otError DBusThreadObject::GetRadioSpinelMetricsHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetRcpInterfaceMetricsHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetRcpInterfaceMetricsHandler(DBusMessageIter &aIter) { otError error = OT_ERROR_NONE; RcpInterfaceMetrics rcpInterfaceMetrics; @@ -1633,11 +1670,11 @@ otError DBusThreadObject::GetRcpInterfaceMetricsHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetUptimeHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetUptimeHandler(DBusMessageIter &aIter) { otError error = OT_ERROR_NONE; - VerifyOrExit(DBusMessageEncodeToVariant(&aIter, otInstanceGetUptime(mHost->GetThreadHelper()->GetInstance())) == + VerifyOrExit(DBusMessageEncodeToVariant(&aIter, otInstanceGetUptime(mHost.GetThreadHelper()->GetInstance())) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); @@ -1645,13 +1682,13 @@ otError DBusThreadObject::GetUptimeHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetRadioCoexMetrics(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetRadioCoexMetrics(DBusMessageIter &aIter) { otError error = OT_ERROR_NONE; otRadioCoexMetrics otRadioCoexMetrics; RadioCoexMetrics radioCoexMetrics; - SuccessOrExit(error = otPlatRadioGetCoexMetrics(mHost->GetInstance(), &otRadioCoexMetrics)); + SuccessOrExit(error = otPlatRadioGetCoexMetrics(mHost.GetInstance(), &otRadioCoexMetrics)); radioCoexMetrics.mNumGrantGlitch = otRadioCoexMetrics.mNumGrantGlitch; radioCoexMetrics.mNumTxRequest = otRadioCoexMetrics.mNumTxRequest; @@ -1680,10 +1717,10 @@ otError DBusThreadObject::GetRadioCoexMetrics(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetBorderRoutingCountersHandler(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetBorderRoutingCountersHandler(DBusMessageIter &aIter) { #if OTBR_ENABLE_BORDER_ROUTING_COUNTERS - auto threadHelper = mHost->GetThreadHelper(); + auto threadHelper = mHost.GetThreadHelper(); auto instance = threadHelper->GetInstance(); otError error = OT_ERROR_NONE; BorderRoutingCounters borderRoutingCounters; @@ -1716,21 +1753,21 @@ otError DBusThreadObject::GetBorderRoutingCountersHandler(DBusMessageIter &aIter #endif } -void DBusThreadObject::ActiveDatasetChangeHandler(const otOperationalDatasetTlvs &aDatasetTlvs) +void DBusThreadObjectRcp::ActiveDatasetChangeHandler(const otOperationalDatasetTlvs &aDatasetTlvs) { std::vector value(aDatasetTlvs.mLength); std::copy(aDatasetTlvs.mTlvs, aDatasetTlvs.mTlvs + aDatasetTlvs.mLength, value.begin()); SignalPropertyChanged(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_ACTIVE_DATASET_TLVS, value); } -void DBusThreadObject::LeaveNetworkHandler(DBusRequest &aRequest) +void DBusThreadObjectRcp::LeaveNetworkHandler(DBusRequest &aRequest) { constexpr int kExitCodeShouldRestart = 7; - mHost->GetThreadHelper()->DetachGracefully([aRequest, this](otError error) mutable { + mHost.GetThreadHelper()->DetachGracefully([aRequest, this](otError error) mutable { SuccessOrExit(error); mPublisher->Stop(); - SuccessOrExit(error = otInstanceErasePersistentInfo(mHost->GetThreadHelper()->GetInstance())); + SuccessOrExit(error = otInstanceErasePersistentInfo(mHost.GetThreadHelper()->GetInstance())); exit: aRequest.ReplyOtResult(error); @@ -1743,28 +1780,27 @@ void DBusThreadObject::LeaveNetworkHandler(DBusRequest &aRequest) } #if OTBR_ENABLE_NAT64 -void DBusThreadObject::SetNat64Enabled(DBusRequest &aRequest) +void DBusThreadObjectRcp::SetNat64Enabled(DBusRequest &aRequest) { otError error = OT_ERROR_NONE; bool enable; auto args = std::tie(enable); VerifyOrExit(DBusMessageToTuple(*aRequest.GetMessage(), args) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); - otNat64SetEnabled(mHost->GetThreadHelper()->GetInstance(), enable); + otNat64SetEnabled(mHost.GetThreadHelper()->GetInstance(), enable); exit: aRequest.ReplyOtResult(error); } -otError DBusThreadObject::GetNat64State(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetNat64State(DBusMessageIter &aIter) { otError error = OT_ERROR_NONE; Nat64ComponentState state; - state.mPrefixManagerState = - GetNat64StateName(otNat64GetPrefixManagerState(mHost->GetThreadHelper()->GetInstance())); - state.mTranslatorState = GetNat64StateName(otNat64GetTranslatorState(mHost->GetThreadHelper()->GetInstance())); + state.mPrefixManagerState = GetNat64StateName(otNat64GetPrefixManagerState(mHost.GetThreadHelper()->GetInstance())); + state.mTranslatorState = GetNat64StateName(otNat64GetTranslatorState(mHost.GetThreadHelper()->GetInstance())); VerifyOrExit(DBusMessageEncodeToVariant(&aIter, state) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); @@ -1772,7 +1808,7 @@ otError DBusThreadObject::GetNat64State(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetNat64Mappings(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetNat64Mappings(DBusMessageIter &aIter) { otError error = OT_ERROR_NONE; @@ -1781,9 +1817,8 @@ otError DBusThreadObject::GetNat64Mappings(DBusMessageIter &aIter) otNat64AddressMapping otMapping; Nat64AddressMapping mapping; - otNat64InitAddressMappingIterator(mHost->GetThreadHelper()->GetInstance(), &iterator); - while (otNat64GetNextAddressMapping(mHost->GetThreadHelper()->GetInstance(), &iterator, &otMapping) == - OT_ERROR_NONE) + otNat64InitAddressMappingIterator(mHost.GetThreadHelper()->GetInstance(), &iterator); + while (otNat64GetNextAddressMapping(mHost.GetThreadHelper()->GetInstance(), &iterator, &otMapping) == OT_ERROR_NONE) { mapping.mId = otMapping.mId; std::copy(std::begin(otMapping.mIp4.mFields.m8), std::end(otMapping.mIp4.mFields.m8), mapping.mIp4.data()); @@ -1819,13 +1854,13 @@ otError DBusThreadObject::GetNat64Mappings(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetNat64ProtocolCounters(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetNat64ProtocolCounters(DBusMessageIter &aIter) { otError error = OT_ERROR_NONE; otNat64ProtocolCounters otCounters; Nat64ProtocolCounters counters; - otNat64GetCounters(mHost->GetThreadHelper()->GetInstance(), &otCounters); + otNat64GetCounters(mHost.GetThreadHelper()->GetInstance(), &otCounters); counters.mTotal.m4To6Packets = otCounters.mTotal.m4To6Packets; counters.mTotal.m4To6Bytes = otCounters.mTotal.m4To6Bytes; @@ -1850,13 +1885,13 @@ otError DBusThreadObject::GetNat64ProtocolCounters(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetNat64ErrorCounters(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetNat64ErrorCounters(DBusMessageIter &aIter) { otError error = OT_ERROR_NONE; otNat64ErrorCounters otCounters; Nat64ErrorCounters counters; - otNat64GetErrorCounters(mHost->GetThreadHelper()->GetInstance(), &otCounters); + otNat64GetErrorCounters(mHost.GetThreadHelper()->GetInstance(), &otCounters); counters.mUnknown.m4To6Packets = otCounters.mCount4To6[OT_NAT64_DROP_REASON_UNKNOWN]; counters.mUnknown.m6To4Packets = otCounters.mCount6To4[OT_NAT64_DROP_REASON_UNKNOWN]; @@ -1873,14 +1908,14 @@ otError DBusThreadObject::GetNat64ErrorCounters(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetNat64Cidr(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetNat64Cidr(DBusMessageIter &aIter) { otError error = OT_ERROR_NONE; otIp4Cidr cidr; char cidrString[OT_IP4_CIDR_STRING_SIZE]; - SuccessOrExit(error = otNat64GetCidr(mHost->GetThreadHelper()->GetInstance(), &cidr)); + SuccessOrExit(error = otNat64GetCidr(mHost.GetThreadHelper()->GetInstance(), &cidr)); otIp4CidrToString(&cidr, cidrString, sizeof(cidrString)); VerifyOrExit(DBusMessageEncodeToVariant(&aIter, std::string(cidrString)) == OTBR_ERROR_NONE, @@ -1890,7 +1925,7 @@ otError DBusThreadObject::GetNat64Cidr(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::SetNat64Cidr(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::SetNat64Cidr(DBusMessageIter &aIter) { otError error = OT_ERROR_NONE; std::string cidrString; @@ -1898,56 +1933,132 @@ otError DBusThreadObject::SetNat64Cidr(DBusMessageIter &aIter) VerifyOrExit(DBusMessageExtractFromVariant(&aIter, cidrString) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); SuccessOrExit(error = otIp4CidrFromString(cidrString.c_str(), &cidr)); - SuccessOrExit(error = otNat64SetIp4Cidr(mHost->GetThreadHelper()->GetInstance(), &cidr)); + SuccessOrExit(error = otNat64SetIp4Cidr(mHost.GetThreadHelper()->GetInstance(), &cidr)); exit: return error; } #else // OTBR_ENABLE_NAT64 -void DBusThreadObject::SetNat64Enabled(DBusRequest &aRequest) +void DBusThreadObjectRcp::SetNat64Enabled(DBusRequest &aRequest) { OTBR_UNUSED_VARIABLE(aRequest); aRequest.ReplyOtResult(OT_ERROR_NOT_IMPLEMENTED); } -otError DBusThreadObject::GetNat64State(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetNat64State(DBusMessageIter &aIter) { OTBR_UNUSED_VARIABLE(aIter); return OT_ERROR_NOT_IMPLEMENTED; } -otError DBusThreadObject::GetNat64Mappings(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetNat64Mappings(DBusMessageIter &aIter) { OTBR_UNUSED_VARIABLE(aIter); return OT_ERROR_NOT_IMPLEMENTED; } -otError DBusThreadObject::GetNat64ProtocolCounters(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetNat64ProtocolCounters(DBusMessageIter &aIter) { OTBR_UNUSED_VARIABLE(aIter); return OT_ERROR_NOT_IMPLEMENTED; } -otError DBusThreadObject::GetNat64ErrorCounters(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetNat64ErrorCounters(DBusMessageIter &aIter) { OTBR_UNUSED_VARIABLE(aIter); return OT_ERROR_NOT_IMPLEMENTED; } -otError DBusThreadObject::GetNat64Cidr(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetNat64Cidr(DBusMessageIter &aIter) { OTBR_UNUSED_VARIABLE(aIter); return OT_ERROR_NOT_IMPLEMENTED; } -otError DBusThreadObject::SetNat64Cidr(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::SetNat64Cidr(DBusMessageIter &aIter) { OTBR_UNUSED_VARIABLE(aIter); return OT_ERROR_NOT_IMPLEMENTED; } #endif // OTBR_ENABLE_NAT64 -otError DBusThreadObject::GetInfraLinkInfo(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetEphemeralKeyEnabled(DBusMessageIter &aIter) +{ + otError error = OT_ERROR_NONE; + + SuccessOrExit(DBusMessageEncodeToVariant(&aIter, mBorderAgent.GetEphemeralKeyEnabled()), + error = OT_ERROR_INVALID_ARGS); + +exit: + return error; +} + +otError DBusThreadObjectRcp::SetEphemeralKeyEnabled(DBusMessageIter &aIter) +{ + otError error = OT_ERROR_NONE; + bool enable; + + SuccessOrExit(DBusMessageExtractFromVariant(&aIter, enable), error = OT_ERROR_INVALID_ARGS); + mBorderAgent.SetEphemeralKeyEnabled(enable); + +exit: + return error; +} + +void DBusThreadObjectRcp::DeactivateEphemeralKeyModeHandler(DBusRequest &aRequest) +{ + otError error = OT_ERROR_NONE; + auto threadHelper = mHost.GetThreadHelper(); + + VerifyOrExit(mBorderAgent.GetEphemeralKeyEnabled(), error = OT_ERROR_NOT_CAPABLE); + + switch (otBorderAgentGetState(threadHelper->GetInstance())) + { + case OT_BORDER_AGENT_STATE_STOPPED: + error = OT_ERROR_FAILED; + break; + case OT_BORDER_AGENT_STATE_ACTIVE: + error = OT_ERROR_INVALID_STATE; + break; + case OT_BORDER_AGENT_STATE_STARTED: + otBorderAgentClearEphemeralKey(threadHelper->GetInstance()); + break; + } + +exit: + aRequest.ReplyOtResult(error); +} + +void DBusThreadObjectRcp::ActivateEphemeralKeyModeHandler(DBusRequest &aRequest) +{ + otError error = OT_ERROR_NONE; + auto threadHelper = mHost.GetThreadHelper(); + uint32_t lifetime = 0; + auto args = std::tie(lifetime); + std::string ePskc; + + VerifyOrExit(mBorderAgent.GetEphemeralKeyEnabled(), error = OT_ERROR_NOT_CAPABLE); + + SuccessOrExit(DBusMessageToTuple(*aRequest.GetMessage(), args), error = OT_ERROR_INVALID_ARGS); + + SuccessOrExit(mBorderAgent.CreateEphemeralKey(ePskc), error = OT_ERROR_INVALID_ARGS); + otbrLogInfo("Created Ephemeral Key: %s", ePskc.c_str()); + + SuccessOrExit(error = otBorderAgentSetEphemeralKey(threadHelper->GetInstance(), ePskc.c_str(), lifetime, + OTBR_CONFIG_BORDER_AGENT_MESHCOP_E_UDP_PORT)); + +exit: + if (error == OT_ERROR_NONE) + { + aRequest.Reply(std::tie(ePskc)); + } + else + { + aRequest.ReplyOtResult(error); + } +} + +otError DBusThreadObjectRcp::GetInfraLinkInfo(DBusMessageIter &aIter) { #if OTBR_ENABLE_BORDER_ROUTING otError error = OT_ERROR_NONE; @@ -1977,14 +2088,14 @@ otError DBusThreadObject::GetInfraLinkInfo(DBusMessageIter &aIter) #endif } -otError DBusThreadObject::SetDnsUpstreamQueryState(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::SetDnsUpstreamQueryState(DBusMessageIter &aIter) { #if OTBR_ENABLE_DNS_UPSTREAM_QUERY otError error = OT_ERROR_NONE; bool enable; VerifyOrExit(DBusMessageExtractFromVariant(&aIter, enable) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); - otDnssdUpstreamQuerySetEnabled(mHost->GetThreadHelper()->GetInstance(), enable); + otDnssdUpstreamQuerySetEnabled(mHost.GetThreadHelper()->GetInstance(), enable); exit: return error; @@ -1995,13 +2106,13 @@ otError DBusThreadObject::SetDnsUpstreamQueryState(DBusMessageIter &aIter) #endif } -otError DBusThreadObject::GetDnsUpstreamQueryState(DBusMessageIter &aIter) +otError DBusThreadObjectRcp::GetDnsUpstreamQueryState(DBusMessageIter &aIter) { #if OTBR_ENABLE_DNS_UPSTREAM_QUERY otError error = OT_ERROR_NONE; VerifyOrExit(DBusMessageEncodeToVariant( - &aIter, otDnssdUpstreamQueryIsEnabled(mHost->GetThreadHelper()->GetInstance())) == OTBR_ERROR_NONE, + &aIter, otDnssdUpstreamQueryIsEnabled(mHost.GetThreadHelper()->GetInstance())) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); exit: diff --git a/src/dbus/server/dbus_thread_object.hpp b/src/dbus/server/dbus_thread_object_rcp.hpp similarity index 88% rename from src/dbus/server/dbus_thread_object.hpp rename to src/dbus/server/dbus_thread_object_rcp.hpp index e3458cb306b..7e55907b703 100644 --- a/src/dbus/server/dbus_thread_object.hpp +++ b/src/dbus/server/dbus_thread_object_rcp.hpp @@ -31,8 +31,8 @@ * This file includes definitions for the d-bus object of OpenThread service. */ -#ifndef OTBR_DBUS_THREAD_OBJECT_HPP_ -#define OTBR_DBUS_THREAD_OBJECT_HPP_ +#ifndef OTBR_DBUS_THREAD_OBJECT_RCP_HPP_ +#define OTBR_DBUS_THREAD_OBJECT_RCP_HPP_ #include "openthread-br/config.h" @@ -40,6 +40,7 @@ #include +#include "border_agent/border_agent.hpp" #include "dbus/server/dbus_object.hpp" #include "mdns/mdns.hpp" #include "ncp/rcp_host.hpp" @@ -54,13 +55,9 @@ namespace DBus { * This module includes the dbus server api. * * @{ - * @} - * */ -class DBusAgent; - -class DBusThreadObject : public DBusObject +class DBusThreadObjectRcp : public DBusObject { public: /** @@ -70,12 +67,13 @@ class DBusThreadObject : public DBusObject * @param[in] aInterfaceName The dbus interface name. * @param[in] aHost The Thread controller * @param[in] aPublisher The Mdns::Publisher - * + * @param[in] aBorderAgent The Border Agent */ - DBusThreadObject(DBusConnection *aConnection, - const std::string &aInterfaceName, - otbr::Ncp::RcpHost *aHost, - Mdns::Publisher *aPublisher); + DBusThreadObjectRcp(DBusConnection &aConnection, + const std::string &aInterfaceName, + otbr::Ncp::RcpHost &aHost, + Mdns::Publisher *aPublisher, + otbr::BorderAgent &aBorderAgent); otbrError Init(void) override; @@ -85,6 +83,7 @@ class DBusThreadObject : public DBusObject private: void DeviceRoleHandler(otDeviceRole aDeviceRole); + void Dhcp6PdStateHandler(otBorderRoutingDhcp6PdState aDhcp6PdState); void ActiveDatasetChangeHandler(const otOperationalDatasetTlvs &aDatasetTlvs); void NcpResetHandler(void); @@ -107,6 +106,8 @@ class DBusThreadObject : public DBusObject void GetPropertiesHandler(DBusRequest &aRequest); void LeaveNetworkHandler(DBusRequest &aRequest); void SetNat64Enabled(DBusRequest &aRequest); + void ActivateEphemeralKeyModeHandler(DBusRequest &aRequest); + void DeactivateEphemeralKeyModeHandler(DBusRequest &aRequest); void IntrospectHandler(DBusRequest &aRequest); @@ -118,6 +119,7 @@ class DBusThreadObject : public DBusObject otError SetRadioRegionHandler(DBusMessageIter &aIter); otError SetDnsUpstreamQueryState(DBusMessageIter &aIter); otError SetNat64Cidr(DBusMessageIter &aIter); + otError SetEphemeralKeyEnabled(DBusMessageIter &aIter); otError GetLinkModeHandler(DBusMessageIter &aIter); otError GetDeviceRoleHandler(DBusMessageIter &aIter); @@ -170,6 +172,7 @@ class DBusThreadObject : public DBusObject otError GetNat64Mappings(DBusMessageIter &aIter); otError GetNat64ProtocolCounters(DBusMessageIter &aIter); otError GetNat64ErrorCounters(DBusMessageIter &aIter); + otError GetEphemeralKeyEnabled(DBusMessageIter &aIter); otError GetInfraLinkInfo(DBusMessageIter &aIter); otError GetDnsUpstreamQueryState(DBusMessageIter &aIter); otError GetTelemetryDataHandler(DBusMessageIter &aIter); @@ -178,12 +181,17 @@ class DBusThreadObject : public DBusObject void ReplyScanResult(DBusRequest &aRequest, otError aError, const std::vector &aResult); void ReplyEnergyScanResult(DBusRequest &aRequest, otError aError, const std::vector &aResult); - otbr::Ncp::RcpHost *mHost; + otbr::Ncp::RcpHost &mHost; std::unordered_map mGetPropertyHandlers; otbr::Mdns::Publisher *mPublisher; + otbr::BorderAgent &mBorderAgent; }; +/** + * @} + */ + } // namespace DBus } // namespace otbr -#endif // OTBR_DBUS_THREAD_OBJECT_HPP_ +#endif // OTBR_DBUS_THREAD_OBJECT_RCP_HPP_ diff --git a/src/dbus/server/error_helper.hpp b/src/dbus/server/error_helper.hpp index 6b35ac1d9d1..c8ba79027a1 100644 --- a/src/dbus/server/error_helper.hpp +++ b/src/dbus/server/error_helper.hpp @@ -52,7 +52,6 @@ namespace DBus { * @param[in] aError The otError value. * * @returns The string representation of an otError. - * */ const char *ConvertToDBusErrorName(otError aError); diff --git a/src/dbus/server/introspect.xml b/src/dbus/server/introspect.xml index c6f26012ba2..21b358e51e3 100644 --- a/src/dbus/server/introspect.xml +++ b/src/dbus/server/introspect.xml @@ -231,6 +231,25 @@ + + + + + + + + + + + + + + diff --git a/src/mdns/mdns.hpp b/src/mdns/mdns.hpp index ed2dc7c03bd..45dff98d29c 100644 --- a/src/mdns/mdns.hpp +++ b/src/mdns/mdns.hpp @@ -69,14 +69,12 @@ namespace Mdns { /** * This interface defines the functionality of mDNS publisher. - * */ class Publisher : private NonCopyable { public: /** * This structure represents a key/value pair of the TXT record. - * */ struct TxtEntry { @@ -127,7 +125,6 @@ class Publisher : private NonCopyable /** * This structure represents information of a discovered service instance. - * */ struct DiscoveredInstanceInfo { @@ -148,7 +145,6 @@ class Publisher : private NonCopyable /** * This structure represents information of a discovered host. - * */ struct DiscoveredHostInfo { @@ -163,21 +159,18 @@ class Publisher : private NonCopyable /** * This function is called to notify a discovered service instance. - * */ using DiscoveredServiceInstanceCallback = std::function; /** * This function is called to notify a discovered host. - * */ using DiscoveredHostCallback = std::function; /** * mDNS state values. - * */ enum class State { @@ -196,13 +189,11 @@ class Publisher : private NonCopyable * * @retval OTBR_ERROR_NONE Successfully started mDNS publisher; * @retval OTBR_ERROR_MDNS Failed to start mDNS publisher. - * */ virtual otbrError Start(void) = 0; /** * This method stops the mDNS publisher. - * */ virtual void Stop(void) = 0; @@ -211,7 +202,6 @@ class Publisher : private NonCopyable * * @retval true Already started. * @retval false Not started. - * */ virtual bool IsStarted(void) const = 0; @@ -233,7 +223,6 @@ class Publisher : private NonCopyable * failure. Specifically, `OTBR_ERROR_DUPLICATED` indicates that the name has * already been published and the caller can re-publish with a new name if an * alternative name is available/acceptable. - * */ void PublishService(const std::string &aHostName, const std::string &aName, @@ -249,7 +238,6 @@ class Publisher : private NonCopyable * @param[in] aName The name 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. - * */ virtual void UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback) = 0; @@ -266,7 +254,6 @@ class Publisher : private NonCopyable * failure. Specifically, `OTBR_ERROR_DUPLICATED` indicates that the name has * already been published and the caller can re-publish with a new name if an * alternative name is available/acceptable. - * */ void PublishHost(const std::string &aName, const AddressList &aAddresses, ResultCallback &&aCallback); @@ -275,7 +262,6 @@ class Publisher : private NonCopyable * * @param[in] aName A host name (MUST not end with dot). * @param[in] aCallback The callback for receiving the publishing result. - * */ virtual void UnpublishHost(const std::string &aName, ResultCallback &&aCallback) = 0; @@ -289,7 +275,6 @@ class Publisher : private NonCopyable * failure. Specifically, `OTBR_ERROR_DUPLICATED` indicates that the name has * already been published and the caller can re-publish with a new name if an * alternative name is available/acceptable. - * */ void PublishKey(const std::string &aName, const KeyData &aKeyData, ResultCallback &&aCallback); @@ -298,7 +283,6 @@ class Publisher : private NonCopyable * * @param[in] aName The name associated with key record. * @param[in] aCallback The callback for receiving the publishing result. - * */ virtual void UnpublishKey(const std::string &aName, ResultCallback &&aCallback) = 0; @@ -314,7 +298,6 @@ class Publisher : private NonCopyable * * @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. - * */ virtual void SubscribeService(const std::string &aType, const std::string &aInstanceName) = 0; @@ -328,7 +311,6 @@ class Publisher : private NonCopyable * * @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. - * */ virtual void UnsubscribeService(const std::string &aType, const std::string &aInstanceName) = 0; @@ -340,7 +322,6 @@ class Publisher : private NonCopyable * @note Discovery Proxy implementation guarantees no duplicate subscriptions for the same host. * * @param[in] aHostName The host name (without domain). - * */ virtual void SubscribeHost(const std::string &aHostName) = 0; @@ -350,7 +331,6 @@ class Publisher : private NonCopyable * @note Discovery Proxy implementation guarantees no redundant unsubscription for a host. * * @param[in] aHostName The host name (without domain). - * */ virtual void UnsubscribeHost(const std::string &aHostName) = 0; @@ -361,7 +341,6 @@ class Publisher : private NonCopyable * @param[in] aHostCallback The callback function to receive discovered hosts. * * @returns The Subscriber ID for the callbacks. - * */ uint64_t AddSubscriptionCallbacks(DiscoveredServiceInstanceCallback aInstanceCallback, DiscoveredHostCallback aHostCallback); @@ -370,7 +349,6 @@ class Publisher : private NonCopyable * This method cancels callbacks for subscriptions. * * @param[in] aSubscriberId The Subscriber ID previously returned by `AddSubscriptionCallbacks`. - * */ void RemoveSubscriptionCallbacks(uint64_t aSubscriberId); @@ -378,7 +356,6 @@ class Publisher : private NonCopyable * This method returns the mDNS statistics information of the publisher. * * @returns The MdnsTelemetryInfo of the publisher. - * */ const MdnsTelemetryInfo &GetMdnsTelemetryInfo(void) const { return mTelemetryInfo; } @@ -390,7 +367,6 @@ class Publisher : private NonCopyable * @param[in] aCallback The callback for receiving mDNS publisher state changes. * * @returns A pointer to the newly created mDNS publisher. - * */ static Publisher *Create(StateCallback aCallback); @@ -398,7 +374,6 @@ class Publisher : private NonCopyable * This function destroys the mDNS publisher. * * @param[in] aPublisher A pointer to the publisher. - * */ static void Destroy(Publisher *aPublisher); @@ -416,7 +391,6 @@ class Publisher : private NonCopyable * @retval OTBR_ERROR_INVALID_ARGS The @p aTxtList includes invalid TXT entry. * * @sa DecodeTxtData - * */ static otbrError EncodeTxtData(const TxtList &aTxtList, TxtData &aTxtData); @@ -434,7 +408,6 @@ class Publisher : private NonCopyable * @retval OTBR_ERROR_INVALID_ARGS The @p aTxtdata has invalid TXT format. * * @sa EncodeTxtData - * */ static otbrError DecodeTxtData(TxtList &aTxtList, const uint8_t *aTxtData, uint16_t aTxtLength); diff --git a/src/mdns/mdns_avahi.cpp b/src/mdns/mdns_avahi.cpp index 2f3984d739d..2d9719d6a5d 100644 --- a/src/mdns/mdns_avahi.cpp +++ b/src/mdns/mdns_avahi.cpp @@ -81,7 +81,6 @@ struct AvahiWatch * @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, AvahiPoller &aPoller) : mFd(aFd) @@ -96,7 +95,6 @@ struct AvahiWatch /** * This structure implements the AvahiTimeout. - * */ struct AvahiTimeout { @@ -115,7 +113,6 @@ struct AvahiTimeout * @param[in] aCallback The function to be called after timeout. * @param[in] aContext A pointer to application-specific context. * @param[in] aPoller The AvahiPoller this timeout belongs to. - * */ AvahiTimeout(const struct timeval *aTimeout, AvahiTimeoutCallback aCallback, void *aContext, AvahiPoller &aPoller) : mCallback(aCallback) diff --git a/src/mdns/mdns_avahi.hpp b/src/mdns/mdns_avahi.hpp index d42f9a2b595..5a76ca24381 100644 --- a/src/mdns/mdns_avahi.hpp +++ b/src/mdns/mdns_avahi.hpp @@ -68,7 +68,6 @@ class AvahiPoller; /** * This class implements mDNS publisher with avahi. - * */ class PublisherAvahi : public Publisher { diff --git a/src/mdns/mdns_mdnssd.cpp b/src/mdns/mdns_mdnssd.cpp index 689634a6fe6..22c13b2282e 100644 --- a/src/mdns/mdns_mdnssd.cpp +++ b/src/mdns/mdns_mdnssd.cpp @@ -312,9 +312,7 @@ void PublisherMDnsSd::Update(MainloopContext &aMainloop) assert(fd != -1); - FD_SET(fd, &aMainloop.mReadFdSet); - - aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd); + aMainloop.AddFdToReadSet(fd); } for (const auto &service : mSubscribedServices) @@ -419,8 +417,7 @@ void PublisherMDnsSd::DnssdServiceRegistration::Update(MainloopContext &aMainloo fd = DNSServiceRefSockFD(mServiceRef); VerifyOrExit(fd != -1); - FD_SET(fd, &aMainloop.mReadFdSet); - aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd); + aMainloop.AddFdToReadSet(fd); exit: return; @@ -1041,8 +1038,7 @@ void PublisherMDnsSd::ServiceRef::Update(MainloopContext &aMainloop) const fd = DNSServiceRefSockFD(mServiceRef); assert(fd != -1); - FD_SET(fd, &aMainloop.mReadFdSet); - aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd); + aMainloop.AddFdToReadSet(fd); exit: return; } diff --git a/src/mdns/mdns_mdnssd.hpp b/src/mdns/mdns_mdnssd.hpp index 068d7861e85..07e641b1303 100644 --- a/src/mdns/mdns_mdnssd.hpp +++ b/src/mdns/mdns_mdnssd.hpp @@ -56,7 +56,6 @@ namespace Mdns { /** * This class implements mDNS publisher with mDNSResponder. - * */ class PublisherMDnsSd : public MainloopProcessor, public Publisher { diff --git a/src/ncp/CMakeLists.txt b/src/ncp/CMakeLists.txt index 2bedb875d84..9e706ee0c5f 100644 --- a/src/ncp/CMakeLists.txt +++ b/src/ncp/CMakeLists.txt @@ -26,13 +26,24 @@ # POSSIBILITY OF SUCH DAMAGE. # +add_subdirectory(posix) + add_library(otbr-ncp + async_task.cpp + async_task.hpp + ncp_host.cpp + ncp_host.hpp + ncp_spinel.cpp + ncp_spinel.hpp rcp_host.cpp rcp_host.hpp + thread_host.cpp + thread_host.hpp ) target_link_libraries(otbr-ncp PRIVATE otbr-common + otbr-posix $<$:otbr-proto> $<$:otbr-proto> ) diff --git a/src/ncp/async_task.cpp b/src/ncp/async_task.cpp new file mode 100644 index 00000000000..94827d80a4b --- /dev/null +++ b/src/ncp/async_task.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2024, 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 "async_task.hpp" + +#include +#include + +#include "common/code_utils.hpp" + +namespace otbr { +namespace Ncp { + +AsyncTask::AsyncTask(const ResultHandler &aResultHandler) + : mResultHandler(aResultHandler) +{ +} + +AsyncTask::~AsyncTask() +{ + if (!mNext) + { + if (mResultHandler) + { + mResultHandler(OT_ERROR_FAILED, "AsyncTask ends without setting any result."); + } + } +} + +void AsyncTask::Run(void) +{ + SetResult(OT_ERROR_NONE, ""); +} + +void AsyncTask::SetResult(otError aError, const std::string &aErrorInfo) +{ + if (mNext) + { + if (aError == OT_ERROR_NONE) + { + mThen(std::move(mNext)); + } + else + { + mNext->SetResult(aError, aErrorInfo); + } + mThen = nullptr; + } + else + { + mResultHandler(aError, aErrorInfo); + mResultHandler = nullptr; + } +} + +AsyncTaskPtr &AsyncTask::First(const ThenHandler &aFirst) +{ + assert(mNext == nullptr); + + return Then(aFirst); +} + +AsyncTaskPtr &AsyncTask::Then(const ThenHandler &aThen) +{ + assert(mNext == nullptr); + + mNext = std::make_shared(mResultHandler); + mThen = aThen; + + return mNext; +} + +} // namespace Ncp +} // namespace otbr diff --git a/src/ncp/async_task.hpp b/src/ncp/async_task.hpp new file mode 100644 index 00000000000..371f1fa7dd3 --- /dev/null +++ b/src/ncp/async_task.hpp @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2024, 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 chained async task. + * The utility class is used to support the usage of a `Then`-style chained async operations. + */ + +#ifndef OTBR_AGENT_ASYNC_TASK_HPP_ +#define OTBR_AGENT_ASYNC_TASK_HPP_ + +#include +#include + +#include + +namespace otbr { +namespace Ncp { + +class AsyncTask; +using AsyncTaskPtr = std::shared_ptr; + +class AsyncTask +{ +public: + using ThenHandler = std::function; + using ResultHandler = std::function; + + /** + * Constructor. + * + * @param[in] The error handler called when the result is not OT_ERROR_NONE; + */ + AsyncTask(const ResultHandler &aResultHandler); + + /** + * Destructor. + */ + ~AsyncTask(void); + + /** + * Trigger the initial action of the chained async operations. + * + * This method should be called to trigger the chained async operations. + */ + void Run(void); + + /** + * Set the result of the previous async operation. + * + * This method should be called when the result of the previous async operation is ready. + * This method will pass the result to next operation. + * + * @param[in] aError The result for the previous async operation. + */ + void SetResult(otError aError, const std::string &aErrorInfo); + + /** + * Set the initial operation of the chained async operations. + * + * @param[in] aFirst A reference to a function object for the initial action. + * + * @returns A shared pointer to a AsyncTask object created in this method. + */ + AsyncTaskPtr &First(const ThenHandler &aFirst); + + /** + * Set the next operation of the chained async operations. + * + * @param[in] aThen A reference to a function object for the next action. + * + * @returns A shared pointer to a AsyncTask object created in this method. + */ + AsyncTaskPtr &Then(const ThenHandler &aThen); + +private: + union + { + ThenHandler mThen; // Only valid when `mNext` is not nullptr + ResultHandler mResultHandler; // Only valid when `mNext` is nullptr + }; + AsyncTaskPtr mNext; +}; + +} // namespace Ncp +} // namespace otbr + +#endif // OTBR_AGENT_ASYNC_TASK_HPP_ diff --git a/src/ncp/ncp_host.cpp b/src/ncp/ncp_host.cpp new file mode 100644 index 00000000000..84055875bef --- /dev/null +++ b/src/ncp/ncp_host.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2024, 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. + */ + +#define OTBR_LOG_TAG "NCP_HOST" + +#include "ncp_host.hpp" + +#include + +#include +#include + +#include + +#include "lib/spinel/spinel_driver.hpp" + +#include "ncp/async_task.hpp" + +namespace otbr { +namespace Ncp { + +// =============================== NcpNetworkProperties =============================== + +NcpNetworkProperties::NcpNetworkProperties(void) + : mDeviceRole(OT_DEVICE_ROLE_DISABLED) +{ +} + +otDeviceRole NcpNetworkProperties::GetDeviceRole(void) const +{ + return mDeviceRole; +} + +void NcpNetworkProperties::SetDeviceRole(otDeviceRole aRole) +{ + mDeviceRole = aRole; +} + +// ===================================== NcpHost ====================================== + +NcpHost::NcpHost(const char *aInterfaceName, bool aDryRun) + : mSpinelDriver(*static_cast(otSysGetSpinelDriver())) + , mNetif(mNcpSpinel) +{ + memset(&mConfig, 0, sizeof(mConfig)); + mConfig.mInterfaceName = aInterfaceName; + mConfig.mDryRun = aDryRun; + mConfig.mSpeedUpFactor = 1; +} + +const char *NcpHost::GetCoprocessorVersion(void) +{ + return mSpinelDriver.GetVersion(); +} + +void NcpHost::Init(void) +{ + otSysInit(&mConfig); + mNcpSpinel.Init(mSpinelDriver, *this); + mNetif.Init(mConfig.mInterfaceName); + + mNcpSpinel.Ip6SetAddressCallback( + [this](const std::vector &aAddrInfos) { mNetif.UpdateIp6UnicastAddresses(aAddrInfos); }); + mNcpSpinel.Ip6SetAddressMulticastCallback( + [this](const std::vector &aAddrs) { mNetif.UpdateIp6MulticastAddresses(aAddrs); }); + mNcpSpinel.NetifSetStateChangedCallback([this](bool aState) { mNetif.SetNetifState(aState); }); + mNcpSpinel.Ip6SetReceiveCallback( + [this](const uint8_t *aData, uint16_t aLength) { mNetif.Ip6Receive(aData, aLength); }); +} + +void NcpHost::Deinit(void) +{ + mNcpSpinel.Deinit(); + mNetif.Deinit(); + otSysDeinit(); +} + +void NcpHost::Join(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs, const AsyncResultReceiver &aReceiver) +{ + AsyncTaskPtr task; + auto errorHandler = [aReceiver](otError aError, const std::string &aErrorInfo) { aReceiver(aError, aErrorInfo); }; + + task = std::make_shared(errorHandler); + task->First([this, aActiveOpDatasetTlvs](AsyncTaskPtr aNext) { + mNcpSpinel.DatasetSetActiveTlvs(aActiveOpDatasetTlvs, std::move(aNext)); + }) + ->Then([this](AsyncTaskPtr aNext) { mNcpSpinel.Ip6SetEnabled(true, std::move(aNext)); }) + ->Then([this](AsyncTaskPtr aNext) { mNcpSpinel.ThreadSetEnabled(true, std::move(aNext)); }); + task->Run(); +} + +void NcpHost::Leave(const AsyncResultReceiver &aReceiver) +{ + AsyncTaskPtr task; + auto errorHandler = [aReceiver](otError aError, const std::string &aErrorInfo) { aReceiver(aError, aErrorInfo); }; + + task = std::make_shared(errorHandler); + task->First([this](AsyncTaskPtr aNext) { mNcpSpinel.ThreadDetachGracefully(std::move(aNext)); }) + ->Then([this](AsyncTaskPtr aNext) { mNcpSpinel.ThreadErasePersistentInfo(std::move(aNext)); }); + task->Run(); +} + +void NcpHost::ScheduleMigration(const otOperationalDatasetTlvs &aPendingOpDatasetTlvs, + const AsyncResultReceiver aReceiver) +{ + otDeviceRole role = GetDeviceRole(); + otError error = OT_ERROR_NONE; + auto errorHandler = [aReceiver](otError aError, const std::string &aErrorInfo) { aReceiver(aError, aErrorInfo); }; + + VerifyOrExit(role != OT_DEVICE_ROLE_DISABLED && role != OT_DEVICE_ROLE_DETACHED, error = OT_ERROR_INVALID_STATE); + + mNcpSpinel.DatasetMgmtSetPending(std::make_shared(aPendingOpDatasetTlvs), + std::make_shared(errorHandler)); + +exit: + if (error != OT_ERROR_NONE) + { + mTaskRunner.Post( + [aReceiver, error](void) { aReceiver(error, "Cannot schedule migration when this device is detached"); }); + } +} + +void NcpHost::Process(const MainloopContext &aMainloop) +{ + mSpinelDriver.Process(&aMainloop); + + mNetif.Process(&aMainloop); +} + +void NcpHost::Update(MainloopContext &aMainloop) +{ + mSpinelDriver.GetSpinelInterface()->UpdateFdSet(&aMainloop); + + if (mSpinelDriver.HasPendingFrame()) + { + aMainloop.mTimeout.tv_sec = 0; + aMainloop.mTimeout.tv_usec = 0; + } + + mNetif.UpdateFdSet(&aMainloop); +} + +} // namespace Ncp +} // namespace otbr diff --git a/src/ncp/ncp_host.hpp b/src/ncp/ncp_host.hpp new file mode 100644 index 00000000000..6bb18f77d07 --- /dev/null +++ b/src/ncp/ncp_host.hpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2024, 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 of OpenThead Host for NCP. + */ + +#ifndef OTBR_AGENT_NCP_HOST_HPP_ +#define OTBR_AGENT_NCP_HOST_HPP_ + +#include "lib/spinel/coprocessor_type.h" +#include "lib/spinel/spinel_driver.hpp" + +#include "common/mainloop.hpp" +#include "ncp/ncp_spinel.hpp" +#include "ncp/thread_host.hpp" +#include "posix/netif.hpp" + +namespace otbr { +namespace Ncp { + +/** + * This class implements the NetworkProperties under NCP mode. + */ +class NcpNetworkProperties : virtual public NetworkProperties, public PropsObserver +{ +public: + /** + * Constructor + */ + explicit NcpNetworkProperties(void); + + // NetworkProperties methods + otDeviceRole GetDeviceRole(void) const override; + +private: + // PropsObserver methods + void SetDeviceRole(otDeviceRole aRole) override; + + otDeviceRole mDeviceRole; +}; + +class NcpHost : public MainloopProcessor, public ThreadHost, public NcpNetworkProperties +{ +public: + /** + * Constructor. + * + * @param[in] aInterfaceName A string of the NCP interface name. + * @param[in] aDryRun TRUE to indicate dry-run mode. FALSE otherwise. + */ + NcpHost(const char *aInterfaceName, bool aDryRun); + + /** + * Destructor. + */ + ~NcpHost(void) override = default; + + // ThreadHost methods + void Join(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs, const AsyncResultReceiver &aReceiver) override; + void Leave(const AsyncResultReceiver &aReceiver) override; + void ScheduleMigration(const otOperationalDatasetTlvs &aPendingOpDatasetTlvs, + const AsyncResultReceiver aReceiver) override; + CoprocessorType GetCoprocessorType(void) override { return OT_COPROCESSOR_NCP; } + const char *GetCoprocessorVersion(void) override; + const char *GetInterfaceName(void) const override { return mConfig.mInterfaceName; } + void Init(void) override; + void Deinit(void) override; + + // MainloopProcessor methods + void Update(MainloopContext &aMainloop) override; + void Process(const MainloopContext &aMainloop) override; + +private: + ot::Spinel::SpinelDriver &mSpinelDriver; + otPlatformConfig mConfig; + NcpSpinel mNcpSpinel; + TaskRunner mTaskRunner; + Netif mNetif; +}; + +} // namespace Ncp +} // namespace otbr + +#endif // OTBR_AGENT_NCP_HOST_HPP_ diff --git a/src/ncp/ncp_spinel.cpp b/src/ncp/ncp_spinel.cpp new file mode 100644 index 00000000000..b9c6b45c71f --- /dev/null +++ b/src/ncp/ncp_spinel.cpp @@ -0,0 +1,758 @@ +/* + * Copyright (c) 2024, 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. + */ + +#define OTBR_LOG_TAG "NcpSpinel" + +#include "ncp_spinel.hpp" + +#include + +#include + +#include +#include + +#include "common/code_utils.hpp" +#include "common/logging.hpp" +#include "lib/spinel/spinel.h" +#include "lib/spinel/spinel_decoder.hpp" +#include "lib/spinel/spinel_driver.hpp" +#include "lib/spinel/spinel_helper.hpp" + +namespace otbr { +namespace Ncp { + +static constexpr char kSpinelDataUnpackFormat[] = "CiiD"; + +NcpSpinel::NcpSpinel(void) + : mSpinelDriver(nullptr) + , mCmdTidsInUse(0) + , mCmdNextTid(1) + , mNcpBuffer(mTxBuffer, kTxBufferSize) + , mEncoder(mNcpBuffer) + , mIid(SPINEL_HEADER_INVALID_IID) + , mPropsObserver(nullptr) +{ + std::fill_n(mWaitingKeyTable, SPINEL_PROP_LAST_STATUS, sizeof(mWaitingKeyTable)); + memset(mCmdTable, 0, sizeof(mCmdTable)); +} + +void NcpSpinel::Init(ot::Spinel::SpinelDriver &aSpinelDriver, PropsObserver &aObserver) +{ + mSpinelDriver = &aSpinelDriver; + mPropsObserver = &aObserver; + mIid = mSpinelDriver->GetIid(); + mSpinelDriver->SetFrameHandler(&HandleReceivedFrame, &HandleSavedFrame, this); +} + +void NcpSpinel::Deinit(void) +{ + mSpinelDriver = nullptr; + mIp6AddressTableCallback = nullptr; + mNetifStateChangedCallback = nullptr; +} + +otbrError NcpSpinel::SpinelDataUnpack(const uint8_t *aDataIn, spinel_size_t aDataLen, const char *aPackFormat, ...) +{ + otbrError error = OTBR_ERROR_NONE; + spinel_ssize_t unpacked; + va_list args; + + va_start(args, aPackFormat); + unpacked = spinel_datatype_vunpack(aDataIn, aDataLen, aPackFormat, args); + va_end(args); + + VerifyOrExit(unpacked > 0, error = OTBR_ERROR_PARSE); + +exit: + return error; +} + +void NcpSpinel::DatasetSetActiveTlvs(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs, AsyncTaskPtr aAsyncTask) +{ + otError error = OT_ERROR_NONE; + EncodingFunc encodingFunc = [this, &aActiveOpDatasetTlvs] { + return mEncoder.WriteData(aActiveOpDatasetTlvs.mTlvs, aActiveOpDatasetTlvs.mLength); + }; + + VerifyOrExit(mDatasetSetActiveTask == nullptr, error = OT_ERROR_BUSY); + + SuccessOrExit(error = SetProperty(SPINEL_PROP_THREAD_ACTIVE_DATASET_TLVS, encodingFunc)); + mDatasetSetActiveTask = aAsyncTask; + +exit: + if (error != OT_ERROR_NONE) + { + mTaskRunner.Post([aAsyncTask, error](void) { aAsyncTask->SetResult(error, "Failed to set active dataset!"); }); + } +} + +void NcpSpinel::DatasetMgmtSetPending(std::shared_ptr aPendingOpDatasetTlvsPtr, + AsyncTaskPtr aAsyncTask) +{ + otError error = OT_ERROR_NONE; + EncodingFunc encodingFunc = [this, aPendingOpDatasetTlvsPtr] { + return mEncoder.WriteData(aPendingOpDatasetTlvsPtr->mTlvs, aPendingOpDatasetTlvsPtr->mLength); + }; + + VerifyOrExit(mDatasetMgmtSetPendingTask == nullptr, error = OT_ERROR_BUSY); + + SuccessOrExit(error = SetProperty(SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS, encodingFunc)); + mDatasetMgmtSetPendingTask = aAsyncTask; + +exit: + if (error != OT_ERROR_NONE) + { + mTaskRunner.Post([aAsyncTask, error] { aAsyncTask->SetResult(error, "Failed to set pending dataset!"); }); + } +} + +void NcpSpinel::Ip6SetEnabled(bool aEnable, AsyncTaskPtr aAsyncTask) +{ + otError error = OT_ERROR_NONE; + EncodingFunc encodingFunc = [this, aEnable] { return mEncoder.WriteBool(aEnable); }; + + VerifyOrExit(mIp6SetEnabledTask == nullptr, error = OT_ERROR_BUSY); + + SuccessOrExit(error = SetProperty(SPINEL_PROP_NET_IF_UP, encodingFunc)); + mIp6SetEnabledTask = aAsyncTask; + +exit: + if (error != OT_ERROR_NONE) + { + mTaskRunner.Post( + [aAsyncTask, error](void) { aAsyncTask->SetResult(error, "Failed to enable the network interface!"); }); + } + return; +} + +otbrError NcpSpinel::Ip6Send(const uint8_t *aData, uint16_t aLength) +{ + otbrError error = OTBR_ERROR_NONE; + EncodingFunc encodingFunc = [this, aData, aLength] { return mEncoder.WriteDataWithLen(aData, aLength); }; + + SuccessOrExit(SetProperty(SPINEL_PROP_STREAM_NET, encodingFunc), error = OTBR_ERROR_OPENTHREAD); + +exit: + return error; +} + +void NcpSpinel::ThreadSetEnabled(bool aEnable, AsyncTaskPtr aAsyncTask) +{ + otError error = OT_ERROR_NONE; + EncodingFunc encodingFunc = [this, aEnable] { return mEncoder.WriteBool(aEnable); }; + + VerifyOrExit(mThreadSetEnabledTask == nullptr, error = OT_ERROR_BUSY); + + SuccessOrExit(error = SetProperty(SPINEL_PROP_NET_STACK_UP, encodingFunc)); + mThreadSetEnabledTask = aAsyncTask; + +exit: + if (error != OT_ERROR_NONE) + { + mTaskRunner.Post( + [aAsyncTask, error](void) { aAsyncTask->SetResult(error, "Failed to enable the Thread network!"); }); + } + return; +} + +void NcpSpinel::ThreadDetachGracefully(AsyncTaskPtr aAsyncTask) +{ + otError error = OT_ERROR_NONE; + EncodingFunc encodingFunc = [] { return OT_ERROR_NONE; }; + + VerifyOrExit(mThreadDetachGracefullyTask == nullptr, error = OT_ERROR_BUSY); + + SuccessOrExit(error = SetProperty(SPINEL_PROP_NET_LEAVE_GRACEFULLY, encodingFunc)); + mThreadDetachGracefullyTask = aAsyncTask; + +exit: + if (error != OT_ERROR_NONE) + { + mTaskRunner.Post([aAsyncTask, error](void) { aAsyncTask->SetResult(error, "Failed to detach gracefully!"); }); + } + return; +} + +void NcpSpinel::ThreadErasePersistentInfo(AsyncTaskPtr aAsyncTask) +{ + otError error = OT_ERROR_NONE; + spinel_tid_t tid = GetNextTid(); + + VerifyOrExit(mThreadErasePersistentInfoTask == nullptr, error = OT_ERROR_BUSY); + + SuccessOrExit(error = mSpinelDriver->SendCommand(SPINEL_CMD_NET_CLEAR, SPINEL_PROP_LAST_STATUS, tid)); + + mWaitingKeyTable[tid] = SPINEL_PROP_LAST_STATUS; + mCmdTable[tid] = SPINEL_CMD_NET_CLEAR; + mThreadErasePersistentInfoTask = aAsyncTask; + +exit: + if (error != OT_ERROR_NONE) + { + FreeTidTableItem(tid); + mTaskRunner.Post( + [aAsyncTask, error](void) { aAsyncTask->SetResult(error, "Failed to erase persistent info!"); }); + } +} + +void NcpSpinel::HandleReceivedFrame(const uint8_t *aFrame, + uint16_t aLength, + uint8_t aHeader, + bool &aSave, + void *aContext) +{ + static_cast(aContext)->HandleReceivedFrame(aFrame, aLength, aHeader, aSave); +} + +void NcpSpinel::HandleReceivedFrame(const uint8_t *aFrame, uint16_t aLength, uint8_t aHeader, bool &aShouldSaveFrame) +{ + spinel_tid_t tid = SPINEL_HEADER_GET_TID(aHeader); + + if (tid == 0) + { + HandleNotification(aFrame, aLength); + } + else if (tid < kMaxTids) + { + HandleResponse(tid, aFrame, aLength); + } + else + { + otbrLogCrit("Received unexpected tid: %u", tid); + } + + aShouldSaveFrame = false; +} + +void NcpSpinel::HandleSavedFrame(const uint8_t *aFrame, uint16_t aLength, void *aContext) +{ + /* Intentionally Empty */ + OT_UNUSED_VARIABLE(aFrame); + OT_UNUSED_VARIABLE(aLength); + OT_UNUSED_VARIABLE(aContext); +} + +void NcpSpinel::HandleNotification(const uint8_t *aFrame, uint16_t aLength) +{ + spinel_prop_key_t key; + spinel_size_t len = 0; + uint8_t *data = nullptr; + uint32_t cmd; + uint8_t header; + otbrError error = OTBR_ERROR_NONE; + + SuccessOrExit(error = SpinelDataUnpack(aFrame, aLength, kSpinelDataUnpackFormat, &header, &cmd, &key, &data, &len)); + VerifyOrExit(SPINEL_HEADER_GET_TID(header) == 0, error = OTBR_ERROR_PARSE); + VerifyOrExit(cmd == SPINEL_CMD_PROP_VALUE_IS); + HandleValueIs(key, data, static_cast(len)); + +exit: + otbrLogResult(error, "%s", __FUNCTION__); +} + +void NcpSpinel::HandleResponse(spinel_tid_t aTid, const uint8_t *aFrame, uint16_t aLength) +{ + spinel_prop_key_t key; + spinel_size_t len = 0; + uint8_t *data = nullptr; + uint32_t cmd; + uint8_t header; + otbrError error = OTBR_ERROR_NONE; + FailureHandler failureHandler = nullptr; + + SuccessOrExit(error = SpinelDataUnpack(aFrame, aLength, kSpinelDataUnpackFormat, &header, &cmd, &key, &data, &len)); + + switch (mCmdTable[aTid]) + { + case SPINEL_CMD_PROP_VALUE_SET: + { + error = HandleResponseForPropSet(aTid, key, data, len); + break; + } + case SPINEL_CMD_PROP_VALUE_INSERT: + { + error = HandleResponseForPropInsert(aTid, cmd, key, data, len); + break; + } + case SPINEL_CMD_PROP_VALUE_REMOVE: + { + error = HandleResponseForPropRemove(aTid, cmd, key, data, len); + break; + } + case SPINEL_CMD_NET_CLEAR: + { + spinel_status_t status = SPINEL_STATUS_OK; + + SuccessOrExit(error = SpinelDataUnpack(data, len, SPINEL_DATATYPE_UINT_PACKED_S, &status)); + CallAndClear(mThreadErasePersistentInfoTask, ot::Spinel::SpinelStatusToOtError(status)); + break; + } + default: + break; + } + +exit: + if (error == OTBR_ERROR_INVALID_STATE) + { + otbrLogCrit("Received unexpected response with (cmd:%u, key:%u), waiting (cmd:%u, key:%u) for tid:%u", cmd, key, + mCmdTable[aTid], mWaitingKeyTable[aTid], aTid); + } + else if (error == OTBR_ERROR_PARSE) + { + otbrLogCrit("Error parsing response with tid:%u", aTid); + } + FreeTidTableItem(aTid); +} + +void NcpSpinel::HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength) +{ + otbrError error = OTBR_ERROR_NONE; + + switch (aKey) + { + case SPINEL_PROP_LAST_STATUS: + { + spinel_status_t status = SPINEL_STATUS_OK; + + SuccessOrExit(error = SpinelDataUnpack(aBuffer, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status)); + + otbrLogInfo("NCP last status: %s", spinel_status_to_cstr(status)); + break; + } + + case SPINEL_PROP_NET_ROLE: + { + spinel_net_role_t role = SPINEL_NET_ROLE_DISABLED; + otDeviceRole deviceRole; + + SuccessOrExit(error = SpinelDataUnpack(aBuffer, aLength, SPINEL_DATATYPE_UINT8_S, &role)); + + deviceRole = SpinelRoleToDeviceRole(role); + mPropsObserver->SetDeviceRole(deviceRole); + + otbrLogInfo("Device role changed to %s", otThreadDeviceRoleToString(deviceRole)); + break; + } + + case SPINEL_PROP_NET_LEAVE_GRACEFULLY: + { + CallAndClear(mThreadDetachGracefullyTask, OT_ERROR_NONE); + break; + } + + case SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS: + { + spinel_status_t status = SPINEL_STATUS_OK; + + SuccessOrExit(error = SpinelDataUnpack(aBuffer, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status)); + CallAndClear(mDatasetMgmtSetPendingTask, ot::Spinel::SpinelStatusToOtError(status)); + break; + } + + case SPINEL_PROP_IPV6_ADDRESS_TABLE: + { + std::vector addressInfoTable; + + VerifyOrExit(ParseIp6AddressTable(aBuffer, aLength, addressInfoTable) == OT_ERROR_NONE, + error = OTBR_ERROR_PARSE); + SafeInvoke(mIp6AddressTableCallback, addressInfoTable); + break; + } + + case SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE: + { + std::vector addressTable; + + VerifyOrExit(ParseIp6MulticastAddresses(aBuffer, aLength, addressTable) == OT_ERROR_NONE, + error = OTBR_ERROR_PARSE); + SafeInvoke(mIp6MulticastAddressTableCallback, addressTable); + break; + } + + case SPINEL_PROP_NET_IF_UP: + { + bool isUp; + SuccessOrExit(error = SpinelDataUnpack(aBuffer, aLength, SPINEL_DATATYPE_BOOL_S, &isUp)); + SafeInvoke(mNetifStateChangedCallback, isUp); + break; + } + + case SPINEL_PROP_STREAM_NET: + { + const uint8_t *data; + uint16_t dataLen; + + SuccessOrExit(ParseIp6StreamNet(aBuffer, aLength, data, dataLen), error = OTBR_ERROR_PARSE); + SafeInvoke(mIp6ReceiveCallback, data, dataLen); + break; + } + + default: + otbrLogWarning("Received uncognized key: %u", aKey); + break; + } + +exit: + otbrLogResult(error, "NcpSpinel: %s", __FUNCTION__); + return; +} + +otbrError NcpSpinel::HandleResponseForPropSet(spinel_tid_t aTid, + spinel_prop_key_t aKey, + const uint8_t *aData, + uint16_t aLength) +{ + OTBR_UNUSED_VARIABLE(aData); + OTBR_UNUSED_VARIABLE(aLength); + + otbrError error = OTBR_ERROR_NONE; + + switch (mWaitingKeyTable[aTid]) + { + case SPINEL_PROP_THREAD_ACTIVE_DATASET_TLVS: + VerifyOrExit(aKey == SPINEL_PROP_THREAD_ACTIVE_DATASET_TLVS, error = OTBR_ERROR_INVALID_STATE); + CallAndClear(mDatasetSetActiveTask, OT_ERROR_NONE); + break; + + case SPINEL_PROP_NET_IF_UP: + VerifyOrExit(aKey == SPINEL_PROP_NET_IF_UP, error = OTBR_ERROR_INVALID_STATE); + CallAndClear(mIp6SetEnabledTask, OT_ERROR_NONE); + { + bool isUp; + SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_BOOL_S, &isUp)); + SafeInvoke(mNetifStateChangedCallback, isUp); + } + break; + + case SPINEL_PROP_NET_STACK_UP: + VerifyOrExit(aKey == SPINEL_PROP_NET_STACK_UP, error = OTBR_ERROR_INVALID_STATE); + CallAndClear(mThreadSetEnabledTask, OT_ERROR_NONE); + break; + + case SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS: + if (aKey == SPINEL_PROP_LAST_STATUS) + { // Failed case + spinel_status_t status = SPINEL_STATUS_OK; + + SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status)); + CallAndClear(mDatasetMgmtSetPendingTask, ot::Spinel::SpinelStatusToOtError(status)); + } + else if (aKey != SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS) + { + ExitNow(error = OTBR_ERROR_INVALID_STATE); + } + break; + + case SPINEL_PROP_STREAM_NET: + break; + + default: + VerifyOrExit(aKey == mWaitingKeyTable[aTid], error = OTBR_ERROR_INVALID_STATE); + break; + } + +exit: + return error; +} + +otbrError NcpSpinel::HandleResponseForPropInsert(spinel_tid_t aTid, + spinel_command_t aCmd, + spinel_prop_key_t aKey, + const uint8_t *aData, + uint16_t aLength) +{ + otbrError error = OTBR_ERROR_NONE; + + switch (mWaitingKeyTable[aTid]) + { + case SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE: + if (aCmd == SPINEL_CMD_PROP_VALUE_IS) + { + spinel_status_t status = SPINEL_STATUS_OK; + + VerifyOrExit(aKey == SPINEL_PROP_LAST_STATUS, error = OTBR_ERROR_INVALID_STATE); + SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status)); + otbrLogInfo("Failed to subscribe to multicast address on NCP, error:%s", spinel_status_to_cstr(status)); + } + else + { + error = aCmd == SPINEL_CMD_PROP_VALUE_INSERTED ? OTBR_ERROR_NONE : OTBR_ERROR_INVALID_STATE; + } + break; + default: + break; + } + +exit: + otbrLogResult(error, "HandleResponseForPropInsert, key:%u", mWaitingKeyTable[aTid]); + return error; +} + +otbrError NcpSpinel::HandleResponseForPropRemove(spinel_tid_t aTid, + spinel_command_t aCmd, + spinel_prop_key_t aKey, + const uint8_t *aData, + uint16_t aLength) +{ + otbrError error = OTBR_ERROR_NONE; + + switch (mWaitingKeyTable[aTid]) + { + case SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE: + if (aCmd == SPINEL_CMD_PROP_VALUE_IS) + { + spinel_status_t status = SPINEL_STATUS_OK; + + VerifyOrExit(aKey == SPINEL_PROP_LAST_STATUS, error = OTBR_ERROR_INVALID_STATE); + SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status)); + otbrLogInfo("Failed to unsubscribe to multicast address on NCP, error:%s", spinel_status_to_cstr(status)); + } + else + { + error = aCmd == SPINEL_CMD_PROP_VALUE_REMOVED ? OTBR_ERROR_NONE : OTBR_ERROR_INVALID_STATE; + } + break; + default: + break; + } + +exit: + otbrLogResult(error, "HandleResponseForPropRemove, key:%u", mWaitingKeyTable[aTid]); + return error; +} + +otbrError NcpSpinel::Ip6MulAddrUpdateSubscription(const otIp6Address &aAddress, bool aIsAdded) +{ + otbrError error = OTBR_ERROR_NONE; + EncodingFunc encodingFunc = [this, aAddress] { return mEncoder.WriteIp6Address(aAddress); }; + + if (aIsAdded) + { + SuccessOrExit(InsertProperty(SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE, encodingFunc), + error = OTBR_ERROR_OPENTHREAD); + } + else + { + SuccessOrExit(RemoveProperty(SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE, encodingFunc), + error = OTBR_ERROR_OPENTHREAD); + } + +exit: + return error; +} + +spinel_tid_t NcpSpinel::GetNextTid(void) +{ + spinel_tid_t tid = mCmdNextTid; + + while (((1 << tid) & mCmdTidsInUse) != 0) + { + tid = SPINEL_GET_NEXT_TID(tid); + + if (tid == mCmdNextTid) + { + // We looped back to `mCmdNextTid` indicating that all + // TIDs are in-use. + + ExitNow(tid = 0); + } + } + + mCmdTidsInUse |= (1 << tid); + mCmdNextTid = SPINEL_GET_NEXT_TID(tid); + +exit: + return tid; +} + +void NcpSpinel::FreeTidTableItem(spinel_tid_t aTid) +{ + mCmdTidsInUse &= ~(1 << aTid); + + mCmdTable[aTid] = SPINEL_CMD_NOOP; + mWaitingKeyTable[aTid] = SPINEL_PROP_LAST_STATUS; +} + +otError NcpSpinel::SendCommand(spinel_command_t aCmd, spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc) +{ + otError error = OT_ERROR_NONE; + spinel_tid_t tid = GetNextTid(); + uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID(mIid) | tid; + + VerifyOrExit(tid != 0, error = OT_ERROR_BUSY); + SuccessOrExit(error = mEncoder.BeginFrame(header, aCmd, aKey)); + SuccessOrExit(error = aEncodingFunc()); + SuccessOrExit(error = mEncoder.EndFrame()); + SuccessOrExit(error = SendEncodedFrame()); + + mCmdTable[tid] = aCmd; + mWaitingKeyTable[tid] = aKey; +exit: + if (error != OT_ERROR_NONE) + { + FreeTidTableItem(tid); + } + return error; +} + +otError NcpSpinel::SetProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc) +{ + return SendCommand(SPINEL_CMD_PROP_VALUE_SET, aKey, aEncodingFunc); +} + +otError NcpSpinel::InsertProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc) +{ + return SendCommand(SPINEL_CMD_PROP_VALUE_INSERT, aKey, aEncodingFunc); +} + +otError NcpSpinel::RemoveProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc) +{ + return SendCommand(SPINEL_CMD_PROP_VALUE_REMOVE, aKey, aEncodingFunc); +} + +otError NcpSpinel::SendEncodedFrame(void) +{ + otError error = OT_ERROR_NONE; + uint8_t frame[kTxBufferSize]; + uint16_t frameLength; + + SuccessOrExit(error = mNcpBuffer.OutFrameBegin()); + frameLength = mNcpBuffer.OutFrameGetLength(); + VerifyOrExit(mNcpBuffer.OutFrameRead(frameLength, frame) == frameLength, error = OT_ERROR_FAILED); + SuccessOrExit(error = mSpinelDriver->GetSpinelInterface()->SendFrame(frame, frameLength)); + +exit: + error = mNcpBuffer.OutFrameRemove(); + return error; +} + +otError NcpSpinel::ParseIp6AddressTable(const uint8_t *aBuf, + uint16_t aLength, + std::vector &aAddressTable) +{ + otError error = OT_ERROR_NONE; + ot::Spinel::Decoder decoder; + + VerifyOrExit(aBuf != nullptr, error = OT_ERROR_INVALID_ARGS); + decoder.Init(aBuf, aLength); + + while (!decoder.IsAllReadInStruct()) + { + Ip6AddressInfo cur; + const otIp6Address *addr; + uint8_t prefixLength; + uint32_t preferredLifetime; + uint32_t validLifetime; + + SuccessOrExit(error = decoder.OpenStruct()); + SuccessOrExit(error = decoder.ReadIp6Address(addr)); + memcpy(&cur.mAddress, addr, sizeof(otIp6Address)); + SuccessOrExit(error = decoder.ReadUint8(prefixLength)); + cur.mPrefixLength = prefixLength; + SuccessOrExit(error = decoder.ReadUint32(preferredLifetime)); + cur.mPreferred = preferredLifetime ? true : false; + SuccessOrExit(error = decoder.ReadUint32(validLifetime)); + OTBR_UNUSED_VARIABLE(validLifetime); + SuccessOrExit((error = decoder.CloseStruct())); + + aAddressTable.push_back(cur); + } + +exit: + return error; +} + +otError NcpSpinel::ParseIp6MulticastAddresses(const uint8_t *aBuf, uint8_t aLen, std::vector &aAddressList) +{ + otError error = OT_ERROR_NONE; + ot::Spinel::Decoder decoder; + + VerifyOrExit(aBuf != nullptr, error = OT_ERROR_INVALID_ARGS); + + decoder.Init(aBuf, aLen); + + while (!decoder.IsAllReadInStruct()) + { + const otIp6Address *addr; + + SuccessOrExit(error = decoder.OpenStruct()); + SuccessOrExit(error = decoder.ReadIp6Address(addr)); + aAddressList.emplace_back(Ip6Address(*addr)); + SuccessOrExit((error = decoder.CloseStruct())); + } + +exit: + return error; +} + +otError NcpSpinel::ParseIp6StreamNet(const uint8_t *aBuf, uint8_t aLen, const uint8_t *&aData, uint16_t &aDataLen) +{ + otError error = OT_ERROR_NONE; + ot::Spinel::Decoder decoder; + + VerifyOrExit(aBuf != nullptr, error = OT_ERROR_INVALID_ARGS); + + decoder.Init(aBuf, aLen); + error = decoder.ReadDataWithLen(aData, aDataLen); + +exit: + return error; +} + +otDeviceRole NcpSpinel::SpinelRoleToDeviceRole(spinel_net_role_t aRole) +{ + otDeviceRole role = OT_DEVICE_ROLE_DISABLED; + + switch (aRole) + { + case SPINEL_NET_ROLE_DISABLED: + role = OT_DEVICE_ROLE_DISABLED; + break; + case SPINEL_NET_ROLE_DETACHED: + role = OT_DEVICE_ROLE_DETACHED; + break; + case SPINEL_NET_ROLE_CHILD: + role = OT_DEVICE_ROLE_CHILD; + break; + case SPINEL_NET_ROLE_ROUTER: + role = OT_DEVICE_ROLE_ROUTER; + break; + case SPINEL_NET_ROLE_LEADER: + role = OT_DEVICE_ROLE_LEADER; + break; + default: + otbrLogWarning("Unsupported spinel net role: %u", aRole); + break; + } + + return role; +} + +} // namespace Ncp +} // namespace otbr diff --git a/src/ncp/ncp_spinel.hpp b/src/ncp/ncp_spinel.hpp new file mode 100644 index 00000000000..571a063ab11 --- /dev/null +++ b/src/ncp/ncp_spinel.hpp @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2024, 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 the spinel based Thread controller. + */ + +#ifndef OTBR_AGENT_NCP_SPINEL_HPP_ +#define OTBR_AGENT_NCP_SPINEL_HPP_ + +#include +#include + +#include +#include +#include +#include + +#include "lib/spinel/spinel.h" +#include "lib/spinel/spinel_buffer.hpp" +#include "lib/spinel/spinel_driver.hpp" +#include "lib/spinel/spinel_encoder.hpp" + +#include "common/task_runner.hpp" +#include "common/types.hpp" +#include "ncp/async_task.hpp" +#include "ncp/posix/netif.hpp" + +namespace otbr { +namespace Ncp { + +/** + * This interface is an observer to subscribe the network properties from NCP. + */ +class PropsObserver +{ +public: + /** + * Updates the device role. + * + * @param[in] aRole The device role. + */ + virtual void SetDeviceRole(otDeviceRole aRole) = 0; + + /** + * The destructor. + */ + virtual ~PropsObserver(void) = default; +}; + +/** + * The class provides methods for controlling the Thread stack on the network co-processor (NCP). + */ +class NcpSpinel : public Netif::Dependencies +{ +public: + using Ip6AddressTableCallback = std::function &)>; + using Ip6MulticastAddressTableCallback = std::function &)>; + using NetifStateChangedCallback = std::function; + using Ip6ReceiveCallback = std::function; + + /** + * Constructor. + */ + NcpSpinel(void); + + /** + * Do the initialization. + * + * @param[in] aSpinelDriver A reference to the SpinelDriver instance that this object depends. + * @param[in] aObserver A reference to the Network properties observer. + */ + void Init(ot::Spinel::SpinelDriver &aSpinelDriver, PropsObserver &aObserver); + + /** + * Do the de-initialization. + */ + void Deinit(void); + + /** + * Returns the Co-processor version string. + */ + const char *GetCoprocessorVersion(void) { return mSpinelDriver->GetVersion(); } + + /** + * This method sets the active dataset on the NCP. + * + * If this method is called again before the previous call completed, no action will be taken. + * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY. + * + * @param[in] aActiveOpDatasetTlvs A reference to the active operational dataset of the Thread network. + * @param[in] aAsyncTask A pointer to an async result to receive the result of this operation. + */ + void DatasetSetActiveTlvs(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs, AsyncTaskPtr aAsyncTask); + + /** + * This method instructs the NCP to send a MGMT_SET to set Thread Pending Operational Dataset. + * + * If this method is called again before the previous call completed, no action will be taken. + * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY. + * + * @param[in] aPendingOpDatasetTlvsPtr A shared pointer to the pending operational dataset of the Thread network. + * @param[in] aAsyncTask A pointer to an async result to receive the result of this operation. + */ + void DatasetMgmtSetPending(std::shared_ptr aPendingOpDatasetTlvsPtr, + AsyncTaskPtr aAsyncTask); + + /** + * This method enableds/disables the IP6 on the NCP. + * + * If this method is called again before the previous call completed, no action will be taken. + * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY. + * + * @param[in] aEnable TRUE to enable and FALSE to disable. + * @param[in] aAsyncTask A pointer to an async result to receive the result of this operation. + */ + void Ip6SetEnabled(bool aEnable, AsyncTaskPtr aAsyncTask); + + /** + * This method sets the callback to receive the IPv6 address table from the NCP. + * + * The callback will be invoked when receiving an IPv6 address table from the NCP. When the + * callback is invoked, the callback MUST copy the otIp6AddressInfo objects and maintain it + * if it's not used immediately (within the callback). + * + * @param[in] aCallback The callback to handle the IP6 address table. + */ + void Ip6SetAddressCallback(const Ip6AddressTableCallback &aCallback) { mIp6AddressTableCallback = aCallback; } + + /** + * This method sets the callback to receive the IPv6 multicast address table from the NCP. + * + * @param[in] aCallback The callback to handle the IPv6 address table. + * + * The callback will be invoked when receiving an IPv6 multicast address table from the NCP. + * When the callback is invoked, the callback MUST copy the otIp6Address objects and maintain it + * if it's not used immediately (within the callback). + */ + void Ip6SetAddressMulticastCallback(const Ip6MulticastAddressTableCallback &aCallback) + { + mIp6MulticastAddressTableCallback = aCallback; + } + + /** + * This method sets the callback to receive IP6 datagrams. + * + * @param[in] aCallback The callback to receive IP6 datagrams. + */ + void Ip6SetReceiveCallback(const Ip6ReceiveCallback &aCallback) { mIp6ReceiveCallback = aCallback; } + + /** + * This methods sends an IP6 datagram through the NCP. + * + * @param[in] aData A pointer to the beginning of the IP6 datagram. + * @param[in] aLength The length of the datagram. + * + * @retval OTBR_ERROR_NONE The datagram is sent to NCP successfully. + * @retval OTBR_ERROR_BUSY NcpSpinel is busy with other requests. + */ + otbrError Ip6Send(const uint8_t *aData, uint16_t aLength) override; + + /** + * This method enableds/disables the Thread network on the NCP. + * + * If this method is called again before the previous call completed, no action will be taken. + * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY. + * + * @param[in] aEnable TRUE to enable and FALSE to disable. + * @param[in] aAsyncTask A pointer to an async result to receive the result of this operation. + */ + void ThreadSetEnabled(bool aEnable, AsyncTaskPtr aAsyncTask); + + /** + * This method instructs the device to leave the current network gracefully. + * + * If this method is called again before the previous call completed, no action will be taken. + * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY. + * + * @param[in] aAsyncTask A pointer to an async result to receive the result of this operation. + */ + void ThreadDetachGracefully(AsyncTaskPtr aAsyncTask); + + /** + * This method instructs the NCP to erase the persistent network info. + * + * If this method is called again before the previous call completed, no action will be taken. + * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY. + * + * @param[in] aAsyncTask A pointer to an async result to receive the result of this operation. + */ + void ThreadErasePersistentInfo(AsyncTaskPtr aAsyncTask); + + /** + * This method sets the callback invoked when the network interface state changes. + * + * @param[in] aCallback The callback invoked when the network interface state changes. + */ + void NetifSetStateChangedCallback(const NetifStateChangedCallback &aCallback) + { + mNetifStateChangedCallback = aCallback; + } + +private: + using FailureHandler = std::function; + + static constexpr uint8_t kMaxTids = 16; + + template static void SafeInvoke(Function &aFunc, Args &&...aArgs) + { + if (aFunc) + { + aFunc(std::forward(aArgs)...); + } + } + + static void CallAndClear(AsyncTaskPtr &aResult, otError aError, const std::string &aErrorInfo = "") + { + if (aResult) + { + aResult->SetResult(aError, aErrorInfo); + aResult = nullptr; + } + } + + static otbrError SpinelDataUnpack(const uint8_t *aDataIn, spinel_size_t aDataLen, const char *aPackFormat, ...); + + static void HandleReceivedFrame(const uint8_t *aFrame, + uint16_t aLength, + uint8_t aHeader, + bool &aSave, + void *aContext); + void HandleReceivedFrame(const uint8_t *aFrame, uint16_t aLength, uint8_t aHeader, bool &aShouldSaveFrame); + static void HandleSavedFrame(const uint8_t *aFrame, uint16_t aLength, void *aContext); + + static otDeviceRole SpinelRoleToDeviceRole(spinel_net_role_t aRole); + + void HandleNotification(const uint8_t *aFrame, uint16_t aLength); + void HandleResponse(spinel_tid_t aTid, const uint8_t *aFrame, uint16_t aLength); + void HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength); + otbrError HandleResponseForPropSet(spinel_tid_t aTid, + spinel_prop_key_t aKey, + const uint8_t *aData, + uint16_t aLength); + otbrError HandleResponseForPropInsert(spinel_tid_t aTid, + spinel_command_t aCmd, + spinel_prop_key_t aKey, + const uint8_t *aData, + uint16_t aLength); + otbrError HandleResponseForPropRemove(spinel_tid_t aTid, + spinel_command_t aCmd, + spinel_prop_key_t aKey, + const uint8_t *aData, + uint16_t aLength); + + otbrError Ip6MulAddrUpdateSubscription(const otIp6Address &aAddress, bool aIsAdded) override; + + spinel_tid_t GetNextTid(void); + void FreeTidTableItem(spinel_tid_t aTid); + + using EncodingFunc = std::function; + otError SendCommand(spinel_command_t aCmd, spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc); + otError SetProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc); + otError InsertProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc); + otError RemoveProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc); + + otError SendEncodedFrame(void); + + otError ParseIp6AddressTable(const uint8_t *aBuf, uint16_t aLength, std::vector &aAddressTable); + otError ParseIp6MulticastAddresses(const uint8_t *aBuf, uint8_t aLen, std::vector &aAddressList); + otError ParseIp6StreamNet(const uint8_t *aBuf, uint8_t aLen, const uint8_t *&aData, uint16_t &aDataLen); + + ot::Spinel::SpinelDriver *mSpinelDriver; + uint16_t mCmdTidsInUse; ///< Used transaction ids. + spinel_tid_t mCmdNextTid; ///< Next available transaction id. + + spinel_prop_key_t mWaitingKeyTable[kMaxTids]; ///< The property keys of ongoing transactions. + spinel_command_t mCmdTable[kMaxTids]; ///< The mapping of spinel command and tids when the response + ///< is LAST_STATUS. + + static constexpr uint16_t kTxBufferSize = 2048; + uint8_t mTxBuffer[kTxBufferSize]; + ot::Spinel::Buffer mNcpBuffer; + ot::Spinel::Encoder mEncoder; + spinel_iid_t mIid; /// < Interface Id used to in Spinel header + + TaskRunner mTaskRunner; + + PropsObserver *mPropsObserver; + + AsyncTaskPtr mDatasetSetActiveTask; + AsyncTaskPtr mDatasetMgmtSetPendingTask; + AsyncTaskPtr mIp6SetEnabledTask; + AsyncTaskPtr mThreadSetEnabledTask; + AsyncTaskPtr mThreadDetachGracefullyTask; + AsyncTaskPtr mThreadErasePersistentInfoTask; + + Ip6AddressTableCallback mIp6AddressTableCallback; + Ip6MulticastAddressTableCallback mIp6MulticastAddressTableCallback; + Ip6ReceiveCallback mIp6ReceiveCallback; + NetifStateChangedCallback mNetifStateChangedCallback; +}; + +} // namespace Ncp +} // namespace otbr + +#endif // OTBR_AGENT_NCP_SPINEL_HPP_ diff --git a/tests/unit/CMakeLists.txt b/src/ncp/posix/CMakeLists.txt similarity index 67% rename from tests/unit/CMakeLists.txt rename to src/ncp/posix/CMakeLists.txt index a368f39a2e3..1f03fd3c18c 100644 --- a/tests/unit/CMakeLists.txt +++ b/src/ncp/posix/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, The OpenThread Authors. +# Copyright (c) 2024, The OpenThread Authors. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -26,31 +26,14 @@ # POSSIBILITY OF SUCH DAMAGE. # -add_executable(otbr-test-unit - $<$:test_dbus_message.cpp> - $<$:test_mdns_mdnssd.cpp> - main.cpp - test_common_types.cpp - test_dns_utils.cpp - test_logging.cpp - test_once_callback.cpp - test_pskc.cpp - test_task_runner.cpp +add_library(otbr-posix + netif.cpp + netif_linux.cpp + netif_unix.cpp + netif.hpp ) -target_include_directories(otbr-test-unit PRIVATE - ${CPPUTEST_INCLUDE_DIRS} -) -target_link_libraries(otbr-test-unit - $<$:otbr-dbus-common> - $<$:otbr-mdns> - $<$:-L$> - ${CPPUTEST_LIBRARIES} - mbedtls + +target_link_libraries(otbr-posix otbr-common otbr-utils - pthread -) -add_test( - NAME unit - COMMAND otbr-test-unit ) diff --git a/src/ncp/posix/netif.cpp b/src/ncp/posix/netif.cpp new file mode 100644 index 00000000000..13957a01e2d --- /dev/null +++ b/src/ncp/posix/netif.cpp @@ -0,0 +1,501 @@ +/* + * Copyright (c) 2024, 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. + */ + +#define OTBR_LOG_TAG "NETIF" + +#include "netif.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common/code_utils.hpp" +#include "common/logging.hpp" +#include "common/types.hpp" +#include "utils/socket_utils.hpp" + +namespace otbr { + +otbrError Netif::Dependencies::Ip6Send(const uint8_t *aData, uint16_t aLength) +{ + OTBR_UNUSED_VARIABLE(aData); + OTBR_UNUSED_VARIABLE(aLength); + + return OTBR_ERROR_NONE; +} + +otbrError Netif::Dependencies::Ip6MulAddrUpdateSubscription(const otIp6Address &aAddress, bool aIsAdd) +{ + OTBR_UNUSED_VARIABLE(aAddress); + OTBR_UNUSED_VARIABLE(aIsAdd); + + return OTBR_ERROR_NONE; +} + +OT_TOOL_PACKED_BEGIN +struct Mldv2Header +{ + uint8_t mType; + uint8_t _rsv0; + uint16_t mChecksum; + uint16_t _rsv1; + uint16_t mNumRecords; +} OT_TOOL_PACKED_END; + +OT_TOOL_PACKED_BEGIN +struct Mldv2Record +{ + uint8_t mRecordType; + uint8_t mAuxDataLen; + uint16_t mNumSources; + struct in6_addr mMulticastAddress; +} OT_TOOL_PACKED_END; + +enum +{ + kIcmpv6Mldv2Type = 143, + kIcmpv6Mldv2ModeIsIncludeType = 1, + kIcmpv6Mldv2ModeIsExcludeType = 2, + kIcmpv6Mldv2RecordChangeToIncludeType = 3, + kIcmpv6Mldv2RecordChangeToExcludeType = 4, +}; + +Netif::Netif(Dependencies &aDependencies) + : mTunFd(-1) + , mIpFd(-1) + , mNetlinkFd(-1) + , mMldFd(-1) + , mNetlinkSequence(0) + , mNetifIndex(0) + , mDeps(aDependencies) +{ +} + +otbrError Netif::Init(const std::string &aInterfaceName) +{ + otbrError error = OTBR_ERROR_NONE; + + mIpFd = SocketWithCloseExec(AF_INET6, SOCK_DGRAM, IPPROTO_IP, kSocketNonBlock); + VerifyOrExit(mIpFd >= 0, error = OTBR_ERROR_ERRNO); + + SuccessOrExit(error = CreateTunDevice(aInterfaceName)); + SuccessOrExit(error = InitNetlink()); + + mNetifIndex = if_nametoindex(mNetifName.c_str()); + VerifyOrExit(mNetifIndex > 0, error = OTBR_ERROR_INVALID_STATE); + + SuccessOrExit(error = InitMldListener()); + + PlatformSpecificInit(); + +exit: + if (error != OTBR_ERROR_NONE) + { + Clear(); + } + return error; +} + +void Netif::Deinit(void) +{ + Clear(); +} + +void Netif::Process(const MainloopContext *aContext) +{ + if (FD_ISSET(mTunFd, &aContext->mErrorFdSet)) + { + close(mTunFd); + DieNow("Error on Tun Fd!"); + } + + if (FD_ISSET(mMldFd, &aContext->mErrorFdSet)) + { + close(mMldFd); + DieNow("Error on MLD Fd!"); + } + + if (FD_ISSET(mTunFd, &aContext->mReadFdSet)) + { + ProcessIp6Send(); + } + + if (FD_ISSET(mMldFd, &aContext->mReadFdSet)) + { + ProcessMldEvent(); + } +} + +void Netif::UpdateFdSet(MainloopContext *aContext) +{ + assert(aContext != nullptr); + assert(mTunFd >= 0); + assert(mIpFd >= 0); + assert(mMldFd >= 0); + + aContext->AddFdToSet(mTunFd, MainloopContext::kErrorFdSet | MainloopContext::kReadFdSet); + aContext->AddFdToSet(mMldFd, MainloopContext::kErrorFdSet | MainloopContext::kReadFdSet); +} + +void Netif::UpdateIp6UnicastAddresses(const std::vector &aAddrInfos) +{ + // Remove stale addresses + for (const Ip6AddressInfo &addrInfo : mIp6UnicastAddresses) + { + if (std::find(aAddrInfos.begin(), aAddrInfos.end(), addrInfo) == aAddrInfos.end()) + { + otbrLogInfo("Remove address: %s", Ip6Address(addrInfo.mAddress).ToString().c_str()); + // TODO: Verify success of the addition or deletion in Netlink response. + ProcessUnicastAddressChange(addrInfo, false); + } + } + + // Add new addresses + for (const Ip6AddressInfo &addrInfo : aAddrInfos) + { + if (std::find(mIp6UnicastAddresses.begin(), mIp6UnicastAddresses.end(), addrInfo) == mIp6UnicastAddresses.end()) + { + otbrLogInfo("Add address: %s", Ip6Address(addrInfo.mAddress).ToString().c_str()); + // TODO: Verify success of the addition or deletion in Netlink response. + ProcessUnicastAddressChange(addrInfo, true); + } + } + + mIp6UnicastAddresses.assign(aAddrInfos.begin(), aAddrInfos.end()); +} + +otbrError Netif::UpdateIp6MulticastAddresses(const std::vector &aAddrs) +{ + otbrError error = OTBR_ERROR_NONE; + + // Remove stale addresses + for (const Ip6Address &address : mIp6MulticastAddresses) + { + if (std::find(aAddrs.begin(), aAddrs.end(), address) == aAddrs.end()) + { + otbrLogInfo("Remove address: %s", Ip6Address(address).ToString().c_str()); + SuccessOrExit(error = ProcessMulticastAddressChange(address, /* aIsAdded */ false)); + } + } + + // Add new addresses + for (const Ip6Address &address : aAddrs) + { + if (std::find(mIp6MulticastAddresses.begin(), mIp6MulticastAddresses.end(), address) == + mIp6MulticastAddresses.end()) + { + otbrLogInfo("Add address: %s", Ip6Address(address).ToString().c_str()); + SuccessOrExit(error = ProcessMulticastAddressChange(address, /* aIsAdded */ true)); + } + } + + mIp6MulticastAddresses.assign(aAddrs.begin(), aAddrs.end()); + +exit: + if (error != OTBR_ERROR_NONE) + { + mIp6MulticastAddresses.clear(); + } + return error; +} + +otbrError Netif::ProcessMulticastAddressChange(const Ip6Address &aAddress, bool aIsAdded) +{ + struct ipv6_mreq mreq; + otbrError error = OTBR_ERROR_NONE; + int err; + + VerifyOrExit(mIpFd >= 0, error = OTBR_ERROR_INVALID_STATE); + memcpy(&mreq.ipv6mr_multiaddr, &aAddress, sizeof(mreq.ipv6mr_multiaddr)); + mreq.ipv6mr_interface = mNetifIndex; + + err = setsockopt(mIpFd, IPPROTO_IPV6, (aIsAdded ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP), &mreq, sizeof(mreq)); + + if (err != 0) + { + otbrLogWarning("%s failure (%d)", aIsAdded ? "IPV6_JOIN_GROUP" : "IPV6_LEAVE_GROUP", errno); + ExitNow(error = OTBR_ERROR_ERRNO); + } + + otbrLogInfo("%s multicast address %s", aIsAdded ? "Added" : "Removed", Ip6Address(aAddress).ToString().c_str()); + +exit: + return error; +} + +void Netif::SetNetifState(bool aState) +{ + otbrError error = OTBR_ERROR_NONE; + struct ifreq ifr; + bool ifState = false; + + VerifyOrExit(mIpFd >= 0); + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, mNetifName.c_str(), IFNAMSIZ - 1); + VerifyOrExit(ioctl(mIpFd, SIOCGIFFLAGS, &ifr) == 0, error = OTBR_ERROR_ERRNO); + + ifState = ((ifr.ifr_flags & IFF_UP) == IFF_UP) ? true : false; + + otbrLogInfo("Changing interface state to %s%s.", aState ? "up" : "down", + (ifState == aState) ? " (already done, ignoring)" : ""); + + if (ifState != aState) + { + ifr.ifr_flags = aState ? (ifr.ifr_flags | IFF_UP) : (ifr.ifr_flags & ~IFF_UP); + VerifyOrExit(ioctl(mIpFd, SIOCSIFFLAGS, &ifr) == 0, error = OTBR_ERROR_ERRNO); + } + +exit: + if (error != OTBR_ERROR_NONE) + { + otbrLogWarning("Failed to update state %s", otbrErrorString(error)); + } +} + +void Netif::Ip6Receive(const uint8_t *aBuf, uint16_t aLen) +{ + otbrError error = OTBR_ERROR_NONE; + + VerifyOrExit(aLen <= kIp6Mtu, error = OTBR_ERROR_DROPPED); + VerifyOrExit(mTunFd > 0, error = OTBR_ERROR_INVALID_STATE); + + otbrLogInfo("Packet from NCP (%u bytes)", aLen); + VerifyOrExit(write(mTunFd, aBuf, aLen) == aLen, error = OTBR_ERROR_ERRNO); + +exit: + if (error != OTBR_ERROR_NONE) + { + otbrLogWarning("Failed to receive, error:%s", otbrErrorString(error)); + } +} + +void Netif::ProcessIp6Send(void) +{ + ssize_t rval; + uint8_t packet[kIp6Mtu]; + otbrError error = OTBR_ERROR_NONE; + + rval = read(mTunFd, packet, sizeof(packet)); + VerifyOrExit(rval > 0, error = OTBR_ERROR_ERRNO); + + otbrLogInfo("Send packet (%hu bytes)", static_cast(rval)); + + error = mDeps.Ip6Send(packet, rval); +exit: + if (error == OTBR_ERROR_ERRNO) + { + otbrLogInfo("Error reading from Tun Fd: %s", strerror(errno)); + } +} + +void Netif::Clear(void) +{ + if (mTunFd != -1) + { + close(mTunFd); + mTunFd = -1; + } + + if (mIpFd != -1) + { + close(mIpFd); + mIpFd = -1; + } + + if (mNetlinkFd != -1) + { + close(mNetlinkFd); + mNetlinkFd = -1; + } + + if (mMldFd != -1) + { + close(mMldFd); + mMldFd = -1; + } + + mNetifIndex = 0; + mIp6UnicastAddresses.clear(); + mIp6MulticastAddresses.clear(); +} + +static const otIp6Address kMldv2MulticastAddress = { + {{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16}}}; +static const otIp6Address kAllRouterLocalMulticastAddress = { + {{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}}}; + +static bool IsMulAddrFiltered(const otIp6Address &aAddr) +{ + return Ip6Address(aAddr) == Ip6Address(kMldv2MulticastAddress) || + Ip6Address(aAddr) == Ip6Address(kAllRouterLocalMulticastAddress); +} + +otbrError Netif::InitMldListener(void) +{ + otbrError error = OTBR_ERROR_NONE; + struct ipv6_mreq mreq6; + + mMldFd = SocketWithCloseExec(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, kSocketNonBlock); + VerifyOrExit(mMldFd != -1, error = OTBR_ERROR_ERRNO); + + mreq6.ipv6mr_interface = mNetifIndex; + memcpy(&mreq6.ipv6mr_multiaddr, kMldv2MulticastAddress.mFields.m8, sizeof(kMldv2MulticastAddress.mFields.m8)); + + VerifyOrExit(setsockopt(mMldFd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6)) == 0, + error = OTBR_ERROR_ERRNO); +#ifdef __linux__ + VerifyOrExit(setsockopt(mMldFd, SOL_SOCKET, SO_BINDTODEVICE, mNetifName.c_str(), + static_cast(mNetifName.length())) == 0, + error = OTBR_ERROR_ERRNO); +#endif + +exit: + return error; +} + +void Netif::ProcessMldEvent(void) +{ + const size_t kMaxMldEvent = 8192; + uint8_t buffer[kMaxMldEvent]; + ssize_t bufferLen = -1; + struct sockaddr_in6 srcAddr; + socklen_t addrLen = sizeof(srcAddr); + bool fromSelf = false; + Mldv2Header *hdr = reinterpret_cast(buffer); + size_t offset; + uint8_t type; + struct ifaddrs *ifAddrs = nullptr; + char addressString[INET6_ADDRSTRLEN + 1]; + + bufferLen = recvfrom(mMldFd, buffer, sizeof(buffer), 0, reinterpret_cast(&srcAddr), &addrLen); + VerifyOrExit(bufferLen > 0); + + type = buffer[0]; + VerifyOrExit(type == kIcmpv6Mldv2Type && bufferLen >= static_cast(sizeof(Mldv2Header))); + + // Check whether it is sent by self + VerifyOrExit(getifaddrs(&ifAddrs) == 0); + for (struct ifaddrs *ifAddr = ifAddrs; ifAddr != nullptr; ifAddr = ifAddr->ifa_next) + { + if (ifAddr->ifa_addr != nullptr && ifAddr->ifa_addr->sa_family == AF_INET6 && + strncmp(mNetifName.c_str(), ifAddr->ifa_name, IFNAMSIZ) == 0) + { + struct sockaddr_in6 *addr6 = reinterpret_cast(ifAddr->ifa_addr); + + if (memcmp(&addr6->sin6_addr, &srcAddr.sin6_addr, sizeof(in6_addr)) == 0) + { + fromSelf = true; + break; + } + } + } + VerifyOrExit(fromSelf); + + hdr = reinterpret_cast(buffer); + offset = sizeof(Mldv2Header); + + for (size_t i = 0; i < ntohs(hdr->mNumRecords) && offset < static_cast(bufferLen); i++) + { + if (static_cast(bufferLen) >= (sizeof(Mldv2Record) + offset)) + { + Mldv2Record *record = reinterpret_cast(&buffer[offset]); + + otbrError error = OTBR_ERROR_DROPPED; + otIp6Address address; + + memcpy(&address, &record->mMulticastAddress, sizeof(address)); + if (IsMulAddrFiltered(address)) + { + continue; + } + + inet_ntop(AF_INET6, &record->mMulticastAddress, addressString, sizeof(addressString)); + + switch (record->mRecordType) + { + case kIcmpv6Mldv2ModeIsIncludeType: + case kIcmpv6Mldv2ModeIsExcludeType: + error = OTBR_ERROR_NONE; + break; + ///< Only update subscription on NCP when the target multicast address is not in `mIp6MulticastAddresses`. + ///< This indicates that this is the first time the multicast address subscription needs to be updated. + case kIcmpv6Mldv2RecordChangeToIncludeType: + if (record->mNumSources == 0) + { + if (std::find(mIp6MulticastAddresses.begin(), mIp6MulticastAddresses.end(), Ip6Address(address)) != + mIp6MulticastAddresses.end()) + { + error = mDeps.Ip6MulAddrUpdateSubscription(address, /* isAdd */ false); + } + else + { + error = OTBR_ERROR_NONE; + } + } + break; + case kIcmpv6Mldv2RecordChangeToExcludeType: + if (std::find(mIp6MulticastAddresses.begin(), mIp6MulticastAddresses.end(), Ip6Address(address)) == + mIp6MulticastAddresses.end()) + { + error = mDeps.Ip6MulAddrUpdateSubscription(address, /* isAdd */ true); + } + else + { + error = OTBR_ERROR_NONE; + } + break; + } + + offset += sizeof(Mldv2Record) + sizeof(in6_addr) * ntohs(record->mNumSources); + + if (error != OTBR_ERROR_NONE) + { + otbrLogWarning("Failed to Update multicast subscription: %s", otbrErrorString(error)); + } + } + } + +exit: + if (ifAddrs) + { + freeifaddrs(ifAddrs); + } +} + +} // namespace otbr diff --git a/src/ncp/posix/netif.hpp b/src/ncp/posix/netif.hpp new file mode 100644 index 00000000000..0c590f5b996 --- /dev/null +++ b/src/ncp/posix/netif.hpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2024, 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 of the posix Netif of otbr-agent. + */ + +#ifndef OTBR_AGENT_POSIX_NETIF_HPP_ +#define OTBR_AGENT_POSIX_NETIF_HPP_ + +#include + +#include +#include + +#include + +#include "common/mainloop.hpp" +#include "common/types.hpp" + +namespace otbr { + +class Netif +{ +public: + class Dependencies + { + public: + virtual ~Dependencies(void) = default; + + virtual otbrError Ip6Send(const uint8_t *aData, uint16_t aLength); + virtual otbrError Ip6MulAddrUpdateSubscription(const otIp6Address &aAddress, bool aIsAdded); + }; + + Netif(Dependencies &aDependencies); + + otbrError Init(const std::string &aInterfaceName); + void Deinit(void); + + void Process(const MainloopContext *aContext); + void UpdateFdSet(MainloopContext *aContext); + void UpdateIp6UnicastAddresses(const std::vector &aAddrInfos); + otbrError UpdateIp6MulticastAddresses(const std::vector &aAddrs); + void SetNetifState(bool aState); + + void Ip6Receive(const uint8_t *aBuf, uint16_t aLen); + +private: + // TODO: Retrieve the Maximum Ip6 size from the coprocessor. + static constexpr size_t kIp6Mtu = 1280; + + void Clear(void); + + otbrError CreateTunDevice(const std::string &aInterfaceName); + otbrError InitNetlink(void); + otbrError InitMldListener(void); + + void PlatformSpecificInit(void); + void SetAddrGenModeToNone(void); + void ProcessUnicastAddressChange(const Ip6AddressInfo &aAddressInfo, bool aIsAdded); + otbrError ProcessMulticastAddressChange(const Ip6Address &aAddress, bool aIsAdded); + void ProcessIp6Send(void); + void ProcessMldEvent(void); + + int mTunFd; ///< Used to exchange IPv6 packets. + int mIpFd; ///< Used to manage IPv6 stack on the network interface. + int mNetlinkFd; ///< Used to receive netlink events. + int mMldFd; ///< Used to receive MLD events. + uint32_t mNetlinkSequence; ///< Netlink message sequence. + + unsigned int mNetifIndex; + std::string mNetifName; + + std::vector mIp6UnicastAddresses; + std::vector mIp6MulticastAddresses; + Dependencies &mDeps; +}; + +} // namespace otbr + +#endif // OTBR_AGENT_POSIX_NETIF_HPP_ diff --git a/src/ncp/posix/netif_linux.cpp b/src/ncp/posix/netif_linux.cpp new file mode 100644 index 00000000000..37db5d8d3fb --- /dev/null +++ b/src/ncp/posix/netif_linux.cpp @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2024, 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. + */ + +#ifdef __linux__ + +#define OTBR_LOG_TAG "NETIF" + +#include "netif.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/code_utils.hpp" +#include "common/logging.hpp" +#include "common/types.hpp" +#include "utils/socket_utils.hpp" + +#ifndef OTBR_POSIX_TUN_DEVICE +#define OTBR_POSIX_TUN_DEVICE "/dev/net/tun" +#endif + +namespace otbr { + +static struct rtattr *AddRtAttr(nlmsghdr *aHeader, uint32_t aMaxLen, uint8_t aType, const void *aData, uint8_t aLen) +{ + uint8_t len = RTA_LENGTH(aLen); + rtattr *rta; + + assert(NLMSG_ALIGN(aHeader->nlmsg_len) + RTA_ALIGN(len) <= aMaxLen); + OTBR_UNUSED_VARIABLE(aMaxLen); + + rta = reinterpret_cast(reinterpret_cast(aHeader) + NLMSG_ALIGN((aHeader)->nlmsg_len)); + rta->rta_type = aType; + rta->rta_len = len; + if (aLen) + { + memcpy(RTA_DATA(rta), aData, aLen); + } + aHeader->nlmsg_len = NLMSG_ALIGN(aHeader->nlmsg_len) + RTA_ALIGN(len); + + return rta; +} + +otbrError Netif::CreateTunDevice(const std::string &aInterfaceName) +{ + ifreq ifr; + otbrError error = OTBR_ERROR_NONE; + + VerifyOrExit(aInterfaceName.size() < IFNAMSIZ, error = OTBR_ERROR_INVALID_ARGS); + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TUN | IFF_NO_PI; + if (aInterfaceName.size() > 0) + { + strncpy(ifr.ifr_name, aInterfaceName.c_str(), aInterfaceName.size()); + } + else + { + strncpy(ifr.ifr_name, "wpan%d", IFNAMSIZ); + } + + mTunFd = open(OTBR_POSIX_TUN_DEVICE, O_RDWR | O_CLOEXEC | O_NONBLOCK); + VerifyOrExit(mTunFd >= 0, error = OTBR_ERROR_ERRNO); + + VerifyOrExit(ioctl(mTunFd, TUNSETIFF, &ifr) == 0, error = OTBR_ERROR_ERRNO); + + mNetifName.assign(ifr.ifr_name, strlen(ifr.ifr_name)); + otbrLogInfo("Netif name: %s", mNetifName.c_str()); + + VerifyOrExit(ioctl(mTunFd, TUNSETLINK, ARPHRD_NONE) == 0, error = OTBR_ERROR_ERRNO); + + ifr.ifr_mtu = static_cast(kIp6Mtu); + VerifyOrExit(ioctl(mIpFd, SIOCSIFMTU, &ifr) == 0, error = OTBR_ERROR_ERRNO); + +exit: + return error; +} + +otbrError Netif::InitNetlink(void) +{ + otbrError error = OTBR_ERROR_NONE; + + mNetlinkFd = SocketWithCloseExec(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, kSocketNonBlock); + VerifyOrExit(mNetlinkFd >= 0, error = OTBR_ERROR_ERRNO); + +#if defined(SOL_NETLINK) + { + int enable = 1; + +#if defined(NETLINK_EXT_ACK) + if (setsockopt(mNetlinkFd, SOL_NETLINK, NETLINK_EXT_ACK, &enable, sizeof(enable)) != 0) + { + otbrLogWarning("Failed to enable NETLINK_EXT_ACK: %s", strerror(errno)); + } +#endif +#if defined(NETLINK_CAP_ACK) + if (setsockopt(mNetlinkFd, SOL_NETLINK, NETLINK_CAP_ACK, &enable, sizeof(enable)) != 0) + { + otbrLogWarning("Failed to enable NETLINK_CAP_ACK: %s", strerror(errno)); + } +#endif + } +#endif + + { + sockaddr_nl sa; + + memset(&sa, 0, sizeof(sa)); + sa.nl_family = AF_NETLINK; + sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV6_IFADDR; + VerifyOrExit(bind(mNetlinkFd, reinterpret_cast(&sa), sizeof(sa)) == 0, error = OTBR_ERROR_ERRNO); + } + +exit: + return error; +} + +void Netif::PlatformSpecificInit(void) +{ + SetAddrGenModeToNone(); +} + +void Netif::SetAddrGenModeToNone(void) +{ + struct + { + nlmsghdr nh; + ifinfomsg ifi; + char buf[512]; + } req; + + const uint8_t mode = IN6_ADDR_GEN_MODE_NONE; + + memset(&req, 0, sizeof(req)); + + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(ifinfomsg)); + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + req.nh.nlmsg_type = RTM_NEWLINK; + req.nh.nlmsg_pid = 0; + req.nh.nlmsg_seq = ++mNetlinkSequence; + + req.ifi.ifi_index = static_cast(mNetifIndex); + req.ifi.ifi_change = 0xffffffff; + req.ifi.ifi_flags = IFF_MULTICAST | IFF_NOARP; + + { + rtattr *afSpec = AddRtAttr(&req.nh, sizeof(req), IFLA_AF_SPEC, 0, 0); + rtattr *afInet6 = AddRtAttr(&req.nh, sizeof(req), AF_INET6, 0, 0); + rtattr *inet6AddrGenMode = AddRtAttr(&req.nh, sizeof(req), IFLA_INET6_ADDR_GEN_MODE, &mode, sizeof(mode)); + + afInet6->rta_len += inet6AddrGenMode->rta_len; + afSpec->rta_len += afInet6->rta_len; + } + + if (send(mNetlinkFd, &req, req.nh.nlmsg_len, 0) != -1) + { + otbrLogInfo("Sent request#%u to set addr_gen_mode to %d", mNetlinkSequence, mode); + } + else + { + otbrLogWarning("Failed to send request#%u to set addr_gen_mode to %d", mNetlinkSequence, mode); + } +} + +void Netif::ProcessUnicastAddressChange(const Ip6AddressInfo &aAddressInfo, bool aIsAdded) +{ + struct + { + nlmsghdr nh; + ifaddrmsg ifa; + char buf[512]; + } req; + + assert(mIpFd >= 0); + memset(&req, 0, sizeof(req)); + + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg)); + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | (aIsAdded ? (NLM_F_CREATE | NLM_F_EXCL) : 0); + req.nh.nlmsg_type = aIsAdded ? RTM_NEWADDR : RTM_DELADDR; + req.nh.nlmsg_pid = 0; + req.nh.nlmsg_seq = ++mNetlinkSequence; + + req.ifa.ifa_family = AF_INET6; + req.ifa.ifa_prefixlen = aAddressInfo.mPrefixLength; + req.ifa.ifa_flags = IFA_F_NODAD; + req.ifa.ifa_scope = aAddressInfo.mScope; + req.ifa.ifa_index = mNetifIndex; + + AddRtAttr(&req.nh, sizeof(req), IFA_LOCAL, &aAddressInfo.mAddress, sizeof(aAddressInfo.mAddress)); + + if (!aAddressInfo.mPreferred || aAddressInfo.mMeshLocal) + { + ifa_cacheinfo cacheinfo; + + memset(&cacheinfo, 0, sizeof(cacheinfo)); + cacheinfo.ifa_valid = UINT32_MAX; + + AddRtAttr(&req.nh, sizeof(req), IFA_CACHEINFO, &cacheinfo, sizeof(cacheinfo)); + } + + if (send(mNetlinkFd, &req, req.nh.nlmsg_len, 0) != -1) + { + otbrLogInfo("Sent request#%u to %s %s/%u", mNetlinkSequence, (aIsAdded ? "add" : "remove"), + Ip6Address(aAddressInfo.mAddress).ToString().c_str(), aAddressInfo.mPrefixLength); + } + else + { + otbrLogWarning("Failed to send request#%u to %s %s/%u", mNetlinkSequence, (aIsAdded ? "add" : "remove"), + Ip6Address(aAddressInfo.mAddress).ToString().c_str(), aAddressInfo.mPrefixLength); + } +} + +} // namespace otbr + +#endif // __linux__ diff --git a/src/ncp/thread_controller.hpp b/src/ncp/posix/netif_unix.cpp similarity index 63% rename from src/ncp/thread_controller.hpp rename to src/ncp/posix/netif_unix.cpp index d89a6922f61..7a7a4987328 100644 --- a/src/ncp/thread_controller.hpp +++ b/src/ncp/posix/netif_unix.cpp @@ -26,48 +26,44 @@ * POSSIBILITY OF SUCH DAMAGE. */ -/** - * @file - * This file includes definitions of Thead Controller Interface. - */ +#if defined(__APPLE__) || defined(__NetBSD__) || defined(__OpenBSD__) -#ifndef OTBR_AGENT_THREAD_CONTROLLER_HPP_ -#define OTBR_AGENT_THREAD_CONTROLLER_HPP_ +#define OTBR_LOG_TAG "NETIF" -#include +#include "netif.hpp" -#include -#include +#include "common/code_utils.hpp" -#include "lib/spinel/coprocessor_type.h" +namespace otbr { -#include "common/logging.hpp" +// TODO: implement platform netif functionalities on unix platforms: APPLE, NetBSD, OpenBSD +// +// Currently we let otbr-agent can be compiled on unix platforms and can work under RCP mode +// but NCP mode cannot be used on unix platforms. It will crash at code here. -namespace otbr { -namespace Ncp { +otbrError Netif::CreateTunDevice(const std::string &aInterfaceName) +{ + OTBR_UNUSED_VARIABLE(aInterfaceName); + DieNow("OTBR posix not supported on this platform"); + return OTBR_ERROR_NONE; +} -/** - * This class is an interface which provides a set of async APIs to control the - * Thread network. - * - * The APIs are unified for both NCP and RCP cases. - * - */ -class ThreadController +otbrError Netif::InitNetlink(void) { -public: - using DeviceRoleHandler = std::function; + return OTBR_ERROR_NONE; +} - /** - * This method gets the device role and returns the role through the handler. - * - * @param[in] aHandler A handler to return the role. - * - */ - virtual void GetDeviceRole(DeviceRoleHandler aHandler) = 0; -}; +void Netif::PlatformSpecificInit(void) +{ + /* Empty */ +} + +void Netif::ProcessUnicastAddressChange(const Ip6AddressInfo &aAddressInfo, bool aIsAdded) +{ + OTBR_UNUSED_VARIABLE(aAddressInfo); + OTBR_UNUSED_VARIABLE(aIsAdded); +} -} // namespace Ncp } // namespace otbr -#endif // OTBR_AGENT_THREAD_CONTROLLER_HPP_ +#endif // __APPLE__ || __NetBSD__ || __OpenBSD__ diff --git a/src/ncp/rcp_host.cpp b/src/ncp/rcp_host.cpp index cea31e9e79d..97d6c7306ef 100644 --- a/src/ncp/rcp_host.cpp +++ b/src/ncp/rcp_host.cpp @@ -26,7 +26,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#define OTBR_LOG_TAG "NCP" +#define OTBR_LOG_TAG "RCP_HOST" #include "ncp/rcp_host.hpp" @@ -66,6 +66,25 @@ static const uint16_t kThreadVersion12 = 3; ///< Thread Version 1.2 static const uint16_t kThreadVersion13 = 4; ///< Thread Version 1.3 static const uint16_t kThreadVersion14 = 5; ///< Thread Version 1.4 +// =============================== OtNetworkProperties =============================== + +OtNetworkProperties::OtNetworkProperties(void) + : mInstance(nullptr) +{ +} + +otDeviceRole OtNetworkProperties::GetDeviceRole(void) const +{ + return otThreadGetDeviceRole(mInstance); +} + +void OtNetworkProperties::SetInstance(otInstance *aInstance) +{ + mInstance = aInstance; +} + +// =============================== RcpHost =============================== + RcpHost::RcpHost(const char *aInterfaceName, const std::vector &aRadioUrls, const char *aBackboneInterfaceName, @@ -164,36 +183,6 @@ otbrLogLevel ConvertProtoToOtbrLogLevel(ProtoLogLevel aProtoLogLevel) } #endif -otLogLevel RcpHost::ConvertToOtLogLevel(otbrLogLevel aLevel) -{ - otLogLevel level; - - switch (aLevel) - { - case OTBR_LOG_EMERG: - case OTBR_LOG_ALERT: - case OTBR_LOG_CRIT: - level = OT_LOG_LEVEL_CRIT; - break; - case OTBR_LOG_ERR: - case OTBR_LOG_WARNING: - level = OT_LOG_LEVEL_WARN; - break; - case OTBR_LOG_NOTICE: - level = OT_LOG_LEVEL_NOTE; - break; - case OTBR_LOG_INFO: - level = OT_LOG_LEVEL_INFO; - break; - case OTBR_LOG_DEBUG: - default: - level = OT_LOG_LEVEL_DEBG; - break; - } - - return level; -} - otError RcpHost::SetOtbrAndOtLogLevel(otbrLogLevel aLevel) { otError error = OT_ERROR_NONE; @@ -251,10 +240,12 @@ void RcpHost::Init(void) #endif #endif // OTBR_ENABLE_FEATURE_FLAGS - mThreadHelper = std::unique_ptr(new otbr::agent::ThreadHelper(mInstance, this)); + mThreadHelper = MakeUnique(mInstance, this); + + OtNetworkProperties::SetInstance(mInstance); exit: - SuccessOrDie(error, "Failed to initialize NCP!"); + SuccessOrDie(error, "Failed to initialize the RCP Host!"); } #if OTBR_ENABLE_FEATURE_FLAGS @@ -301,6 +292,7 @@ void RcpHost::Deinit(void) otSysDeinit(); mInstance = nullptr; + OtNetworkProperties::SetInstance(nullptr); mThreadStateChangedCallbacks.clear(); mResetHandlers.clear(); } @@ -393,7 +385,7 @@ const char *RcpHost::GetThreadVersion(void) version = "1.3.0"; break; case kThreadVersion14: - version = "1.4"; + version = "1.4.0"; break; default: otbrLogEmerg("Unexpected thread version %hu", otThreadGetVersion()); @@ -402,10 +394,27 @@ const char *RcpHost::GetThreadVersion(void) return version; } -void RcpHost::GetDeviceRole(const DeviceRoleHandler aHandler) +void RcpHost::Join(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs, const AsyncResultReceiver &aReceiver) { - otDeviceRole role = otThreadGetDeviceRole(mInstance); - aHandler(OT_ERROR_NONE, role); + OT_UNUSED_VARIABLE(aActiveOpDatasetTlvs); + + // TODO: Implement Join under RCP mode. + mTaskRunner.Post([aReceiver](void) { aReceiver(OT_ERROR_NOT_IMPLEMENTED, "Not implemented!"); }); +} + +void RcpHost::Leave(const AsyncResultReceiver &aReceiver) +{ + // TODO: Implement Leave under RCP mode. + mTaskRunner.Post([aReceiver](void) { aReceiver(OT_ERROR_NOT_IMPLEMENTED, "Not implemented!"); }); +} + +void RcpHost::ScheduleMigration(const otOperationalDatasetTlvs &aPendingOpDatasetTlvs, + const AsyncResultReceiver aReceiver) +{ + OT_UNUSED_VARIABLE(aPendingOpDatasetTlvs); + + // TODO: Implement ScheduleMigration under RCP mode. + mTaskRunner.Post([aReceiver](void) { aReceiver(OT_ERROR_NOT_IMPLEMENTED, "Not implemented!"); }); } /* diff --git a/src/ncp/rcp_host.hpp b/src/ncp/rcp_host.hpp index fb61d5a8ddd..79f441a16af 100644 --- a/src/ncp/rcp_host.hpp +++ b/src/ncp/rcp_host.hpp @@ -49,7 +49,7 @@ #include "common/mainloop.hpp" #include "common/task_runner.hpp" #include "common/types.hpp" -#include "ncp/thread_controller.hpp" +#include "ncp/thread_host.hpp" #include "utils/thread_helper.hpp" namespace otbr { @@ -60,11 +60,31 @@ class FeatureFlagList; namespace Ncp { +/** + * This class implements the NetworkProperties for architectures where OT APIs are directly accessible. + */ +class OtNetworkProperties : virtual public NetworkProperties +{ +public: + /** + * Constructor. + */ + explicit OtNetworkProperties(void); + + // NetworkProperties methods + otDeviceRole GetDeviceRole(void) const override; + + // Set the otInstance + void SetInstance(otInstance *aInstance); + +private: + otInstance *mInstance; +}; + /** * This interface defines OpenThread Controller under RCP mode. - * */ -class RcpHost : public MainloopProcessor, public ThreadController +class RcpHost : public MainloopProcessor, public ThreadHost, public OtNetworkProperties { public: using ThreadStateChangedCallback = std::function; @@ -77,7 +97,6 @@ class RcpHost : public MainloopProcessor, public ThreadController * @param[in] aBackboneInterfaceName The Backbone network interface name. * @param[in] aDryRun TRUE to indicate dry-run mode. FALSE otherwise. * @param[in] aEnableAutoAttach Whether or not to automatically attach to the saved network. - * */ RcpHost(const char *aInterfaceName, const std::vector &aRadioUrls, @@ -86,16 +105,14 @@ class RcpHost : public MainloopProcessor, public ThreadController bool aEnableAutoAttach); /** - * This method initialize the NCP controller. - * + * This method initialize the Thread controller. */ - void Init(void); + void Init(void) override; /** - * This method deinitialize the NCP controller. - * + * This method deinitialize the Thread controller. */ - void Deinit(void); + void Deinit(void) override; /** * Returns an OpenThread instance. @@ -109,7 +126,6 @@ class RcpHost : public MainloopProcessor, public ThreadController * This method gets the thread functionality helper. * * @retval The pointer to the helper object. - * */ otbr::agent::ThreadHelper *GetThreadHelper(void) { @@ -125,7 +141,6 @@ class RcpHost : public MainloopProcessor, public ThreadController * * @param[in] aDelay The delay in milliseconds before executing the task. * @param[in] aTask The task function. - * */ void PostTimerTask(Milliseconds aDelay, TaskRunner::Task aTask); @@ -133,7 +148,6 @@ class RcpHost : public MainloopProcessor, public ThreadController * This method registers a reset handler. * * @param[in] aHandler The handler function. - * */ void RegisterResetHandler(std::function aHandler); @@ -141,13 +155,11 @@ class RcpHost : public MainloopProcessor, public ThreadController * This method adds a event listener for Thread state changes. * * @param[in] aCallback The callback to receive Thread state changed events. - * */ void AddThreadStateChangedCallback(ThreadStateChangedCallback aCallback); /** * This method resets the OpenThread instance. - * */ void Reset(void); @@ -155,7 +167,6 @@ class RcpHost : public MainloopProcessor, public ThreadController * This method returns the Thread protocol version as a string. * * @returns A pointer to the Thread version string. - * */ static const char *GetThreadVersion(void); @@ -163,9 +174,8 @@ class RcpHost : public MainloopProcessor, public ThreadController * This method returns the Thread network interface name. * * @returns A pointer to the Thread network interface name string. - * */ - const char *GetInterfaceName(void) const { return mConfig.mInterfaceName; } + const char *GetInterfaceName(void) const override { return mConfig.mInterfaceName; } static otbrLogLevel ConvertToOtbrLogLevel(otLogLevel aLogLevel); @@ -176,7 +186,6 @@ class RcpHost : public MainloopProcessor, public ThreadController * @param[in] aFeatureFlagList The feature flag list to be applied to OpenThread. * * @returns The error value of underlying OpenThread API calls. - * */ otError ApplyFeatureFlagList(const FeatureFlagList &aFeatureFlagList); @@ -184,7 +193,6 @@ class RcpHost : public MainloopProcessor, public ThreadController * This method returns the applied FeatureFlagList in ApplyFeatureFlagList call. * * @returns the applied FeatureFlagList's serialized bytes. - * */ const std::string &GetAppliedFeatureFlagListBytes(void) { @@ -194,8 +202,21 @@ class RcpHost : public MainloopProcessor, public ThreadController ~RcpHost(void) override; - // Thread Control APIs - void GetDeviceRole(const DeviceRoleHandler aHandler) override; + // Thread Control virtual methods + void Join(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs, const AsyncResultReceiver &aRecevier) override; + void Leave(const AsyncResultReceiver &aRecevier) override; + void ScheduleMigration(const otOperationalDatasetTlvs &aPendingOpDatasetTlvs, + const AsyncResultReceiver aReceiver) override; + + CoprocessorType GetCoprocessorType(void) override + { + return OT_COPROCESSOR_RCP; + } + + const char *GetCoprocessorVersion(void) override + { + return otPlatRadioGetVersionString(mInstance); + } private: static void HandleStateChanged(otChangedFlags aFlags, void *aContext) @@ -220,8 +241,6 @@ class RcpHost : public MainloopProcessor, public ThreadController bool IsAutoAttachEnabled(void); void DisableAutoAttach(void); - static otLogLevel ConvertToOtLogLevel(otbrLogLevel aLevel); - otError SetOtbrAndOtLogLevel(otbrLogLevel aLevel); otInstance *mInstance; @@ -232,6 +251,7 @@ class RcpHost : public MainloopProcessor, public ThreadController TaskRunner mTaskRunner; std::vector mThreadStateChangedCallbacks; bool mEnableAutoAttach = false; + #if OTBR_ENABLE_FEATURE_FLAGS // The applied FeatureFlagList in ApplyFeatureFlagList call, used for debugging purpose. std::string mAppliedFeatureFlagListBytes; diff --git a/src/ncp/thread_host.cpp b/src/ncp/thread_host.cpp new file mode 100644 index 00000000000..294060a3619 --- /dev/null +++ b/src/ncp/thread_host.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2024, 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. + */ + +#define OTBR_LOG_TAG "CTRLR" + +#include "thread_host.hpp" + +#include +#include + +#include "lib/spinel/coprocessor_type.h" + +#include "ncp_host.hpp" +#include "rcp_host.hpp" + +namespace otbr { +namespace Ncp { + +std::unique_ptr ThreadHost::Create(const char *aInterfaceName, + const std::vector &aRadioUrls, + const char *aBackboneInterfaceName, + bool aDryRun, + bool aEnableAutoAttach) +{ + CoprocessorType coprocessorType; + otPlatformCoprocessorUrls urls; + std::unique_ptr host; + otLogLevel level = ConvertToOtLogLevel(otbrLogGetLevel()); + + VerifyOrDie(aRadioUrls.size() <= OT_PLATFORM_CONFIG_MAX_RADIO_URLS, "Too many Radio URLs!"); + + urls.mNum = 0; + for (const char *url : aRadioUrls) + { + urls.mUrls[urls.mNum++] = url; + } + + VerifyOrDie(otLoggingSetLevel(level) == OT_ERROR_NONE, "Failed to set OT log Level!"); + + coprocessorType = otSysInitCoprocessor(&urls); + + switch (coprocessorType) + { + case OT_COPROCESSOR_RCP: + host = MakeUnique(aInterfaceName, aRadioUrls, aBackboneInterfaceName, aDryRun, aEnableAutoAttach); + break; + + case OT_COPROCESSOR_NCP: + host = MakeUnique(aInterfaceName, aDryRun); + break; + + default: + DieNow("Unknown coprocessor type!"); + break; + } + + return host; +} + +otLogLevel ThreadHost::ConvertToOtLogLevel(otbrLogLevel aLevel) +{ + otLogLevel level; + + switch (aLevel) + { + case OTBR_LOG_EMERG: + case OTBR_LOG_ALERT: + case OTBR_LOG_CRIT: + level = OT_LOG_LEVEL_CRIT; + break; + case OTBR_LOG_ERR: + case OTBR_LOG_WARNING: + level = OT_LOG_LEVEL_WARN; + break; + case OTBR_LOG_NOTICE: + level = OT_LOG_LEVEL_NOTE; + break; + case OTBR_LOG_INFO: + level = OT_LOG_LEVEL_INFO; + break; + case OTBR_LOG_DEBUG: + default: + level = OT_LOG_LEVEL_DEBG; + break; + } + + return level; +} + +} // namespace Ncp +} // namespace otbr diff --git a/src/ncp/thread_host.hpp b/src/ncp/thread_host.hpp new file mode 100644 index 00000000000..30b8e45a03d --- /dev/null +++ b/src/ncp/thread_host.hpp @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2024, 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 of Thead Controller Interface. + */ + +#ifndef OTBR_AGENT_THREAD_HOST_HPP_ +#define OTBR_AGENT_THREAD_HOST_HPP_ + +#include +#include + +#include +#include +#include + +#include "lib/spinel/coprocessor_type.h" + +#include "common/logging.hpp" + +namespace otbr { +namespace Ncp { + +/** + * This interface provides access to some Thread network properties in a sync way. + * + * The APIs are unified for both NCP and RCP cases. + */ +class NetworkProperties +{ +public: + /** + * Returns the device role. + * + * @returns the device role. + */ + virtual otDeviceRole GetDeviceRole(void) const = 0; + + /** + * The destructor. + */ + virtual ~NetworkProperties(void) = default; +}; + +/** + * This class is an interface which provides a set of async APIs to control the + * Thread network. + * + * The APIs are unified for both NCP and RCP cases. + */ +class ThreadHost : virtual public NetworkProperties +{ +public: + using AsyncResultReceiver = std::function; + using DeviceRoleHandler = std::function; + + /** + * Create a Thread Controller Instance. + * + * This is a factory method that will decide which implementation class will be created. + * + * @param[in] aInterfaceName A string of the Thread interface name. + * @param[in] aRadioUrls The radio URLs (can be IEEE802.15.4 or TREL radio). + * @param[in] aBackboneInterfaceName The Backbone network interface name. + * @param[in] aDryRun TRUE to indicate dry-run mode. FALSE otherwise. + * @param[in] aEnableAutoAttach Whether or not to automatically attach to the saved network. + * + * @returns Non-null OpenThread Controller instance. + */ + static std::unique_ptr Create(const char *aInterfaceName, + const std::vector &aRadioUrls, + const char *aBackboneInterfaceName, + bool aDryRun, + bool aEnableAutoAttach); + + /** + * This method joins this device to the network specified by @p aActiveOpDatasetTlvs. + * + * If there is an ongoing 'Join' operation, no action will be taken and @p aReceiver will be + * called after the request is completed. The previous @p aReceiver will also be called. + * + * @param[in] aActiveOpDatasetTlvs A reference to the active operational dataset of the Thread network. + * @param[in] aReceiver A receiver to get the async result of this operation. + */ + virtual void Join(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs, const AsyncResultReceiver &aRecevier) = 0; + + /** + * This method instructs the device to leave the current network gracefully. + * + * 1. If there is already an ongoing 'Leave' operation, no action will be taken and @p aReceiver + * will be called after the previous request is completed. The previous @p aReceiver will also + * be called. + * 2. If this device is not in disabled state, OTBR sends Address Release Notification (i.e. ADDR_REL.ntf) + * to gracefully detach from the current network and it takes 1 second to finish. + * 3. Then Operational Dataset will be removed from persistent storage. + * 4. If everything goes fine, @p aReceiver will be invoked with OT_ERROR_NONE. Otherwise, other errors + * will be passed to @p aReceiver when the error happens. + * + * @param[in] aReceiver A receiver to get the async result of this operation. + */ + virtual void Leave(const AsyncResultReceiver &aRecevier) = 0; + + /** + * This method migrates this device to the new network specified by @p aPendingOpDatasetTlvs. + * + * @param[in] aPendingOpDatasetTlvs A reference to the pending operational dataset of the Thread network. + * @param[in] aReceiver A receiver to get the async result of this operation. + */ + virtual void ScheduleMigration(const otOperationalDatasetTlvs &aPendingOpDatasetTlvs, + const AsyncResultReceiver aReceiver) = 0; + + /** + * Returns the co-processor type. + */ + virtual CoprocessorType GetCoprocessorType(void) = 0; + + /** + * Returns the co-processor version string. + */ + virtual const char *GetCoprocessorVersion(void) = 0; + + /** + * This method returns the Thread network interface name. + * + * @returns A pointer to the Thread network interface name string. + */ + virtual const char *GetInterfaceName(void) const = 0; + + /** + * Initializes the Thread controller. + */ + virtual void Init(void) = 0; + + /** + * Deinitializes the Thread controller. + */ + virtual void Deinit(void) = 0; + + /** + * The destructor. + */ + virtual ~ThreadHost(void) = default; + +protected: + static otLogLevel ConvertToOtLogLevel(otbrLogLevel aLevel); +}; + +} // namespace Ncp +} // namespace otbr + +#endif // OTBR_AGENT_THREAD_HOST_HPP_ diff --git a/src/openwrt/ubus/otubus.cpp b/src/openwrt/ubus/otubus.cpp index b1f86b50c1d..ef762d0db95 100644 --- a/src/openwrt/ubus/otubus.cpp +++ b/src/openwrt/ubus/otubus.cpp @@ -1824,13 +1824,7 @@ void UBusAgent::Update(MainloopContext &aMainloop) { VerifyOrExit(otbr::ubus::sUbusEfd != -1); - FD_SET(otbr::ubus::sUbusEfd, &aMainloop.mReadFdSet); - - if (aMainloop.mMaxFd < otbr::ubus::sUbusEfd) - { - aMainloop.mMaxFd = otbr::ubus::sUbusEfd; - } - + aMainloop.AddFdToReadSet(otbr::ubus::sUbusEfd); exit: mThreadMutex.unlock(); return; diff --git a/src/openwrt/ubus/otubus.hpp b/src/openwrt/ubus/otubus.hpp index 8c44255ea3a..f9131c731d6 100644 --- a/src/openwrt/ubus/otubus.hpp +++ b/src/openwrt/ubus/otubus.hpp @@ -68,7 +68,6 @@ namespace ubus { * * @brief * This namespace contains definitions for ubus related instance. - * */ class UbusServer @@ -86,13 +85,11 @@ class UbusServer * This method return the instance of the global UbusServer. * * @retval The reference of the UbusServer Instance. - * */ static UbusServer &GetInstance(void); /** * This method install ubus object onto OpenWRT. - * */ void InstallUbusObject(void); @@ -106,7 +103,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusScanHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -124,7 +120,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusChannelHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -142,7 +137,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusSetChannelHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -160,7 +154,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusNetworknameHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -178,7 +171,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusSetNetworknameHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -196,7 +188,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusStateHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -214,7 +205,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusMacfilterSetStateHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -232,7 +222,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusPanIdHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -250,7 +239,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusSetPanIdHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -268,7 +256,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusPskcHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -286,7 +273,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusSetPskcHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -304,7 +290,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusNetworkkeyHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -322,7 +307,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusSetNetworkkeyHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -340,7 +324,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusRloc16Handler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -358,7 +341,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusExtPanIdHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -376,7 +358,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusSetExtPanIdHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -394,7 +375,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusModeHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -412,7 +392,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusSetModeHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -430,7 +409,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusPartitionIdHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -448,7 +426,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusLeaderdataHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -466,7 +443,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusNetworkdataHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -484,7 +460,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusParentHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -502,7 +477,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusNeighborHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -520,7 +494,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusThreadStartHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -538,7 +511,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusThreadStopHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -556,7 +528,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusLeaveHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -574,7 +545,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusMacfilterAddrHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -592,7 +562,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusMacfilterStateHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -610,7 +579,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusMacfilterAddHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -628,7 +596,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusMacfilterClearHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -646,7 +613,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusMacfilterRemoveHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -664,7 +630,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusCommissionerStartHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -682,7 +647,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusJoinerAddHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -700,7 +664,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusJoinerRemoveHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -718,7 +681,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusJoinerNumHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -736,7 +698,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusMgmtsetHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -754,7 +715,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ static int UbusInterfaceNameHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -769,7 +729,6 @@ class UbusServer * @param[in] aMessage A pointer to the message. * @param[in] aMessageInfo A pointer to the message information. * @param[in] aContext A pointer to the context. - * */ static void HandleDiagnosticGetResponse(otError aError, otMessage *aMessage, @@ -782,7 +741,6 @@ class UbusServer * @param[in] aError A error of receiving the diagnostic response. * @param[in] aMessage A pointer to the message. * @param[in] aMessageInfo A pointer to the message information. - * */ void HandleDiagnosticGetResponse(otError aError, otMessage *aMessage, const otMessageInfo *aMessageInfo); @@ -810,7 +768,6 @@ class UbusServer /** * This method start scan. - * */ void ProcessScan(void); @@ -824,7 +781,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ int UbusScanHandlerDetail(struct ubus_context *aContext, struct ubus_object *aObj, @@ -837,7 +793,6 @@ class UbusServer * * @param[in] aResult A pointer to result. * @param[in] aContext A pointer to context. - * */ static void HandleActiveScanResult(otActiveScanResult *aResult, void *aContext); @@ -845,7 +800,6 @@ class UbusServer * This method detailly handler the scan result, called by HandleActiveScanResult. * * @param[in] aResult A pointer to result. - * */ void HandleActiveScanResultDetail(otActiveScanResult *aResult); @@ -859,7 +813,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ int UbusNeighborHandlerDetail(struct ubus_context *aContext, struct ubus_object *aObj, @@ -877,7 +830,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ int UbusParentHandlerDetail(struct ubus_context *aContext, struct ubus_object *aObj, @@ -895,7 +847,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ int UbusMgmtset(struct ubus_context *aContext, struct ubus_object *aObj, @@ -913,7 +864,6 @@ class UbusServer * @param[in] aMsg A pointer to the ubus message. * * @retval 0 Successfully handler the request. - * */ int UbusLeaveHandlerDetail(struct ubus_context *aContext, struct ubus_object *aObj, @@ -932,7 +882,6 @@ class UbusServer * @param[in] aAction A pointer to the action needed. * * @retval 0 Successfully handler the request. - * */ int UbusThreadHandler(struct ubus_context *aContext, struct ubus_object *aObj, @@ -952,7 +901,6 @@ class UbusServer * @param[in] aAction A pointer to the action needed. * * @retval 0 Successfully handler the request. - * */ int UbusGetInformation(struct ubus_context *aContext, struct ubus_object *aObj, @@ -972,7 +920,6 @@ class UbusServer * @param[in] aAction A pointer to the action needed. * * @retval 0 Successfully handler the request. - * */ int UbusSetInformation(struct ubus_context *aContext, struct ubus_object *aObj, @@ -992,7 +939,6 @@ class UbusServer * @param[in] aAction A pointer to the action needed. * * @retval 0 Successfully handler the request. - * */ int UbusCommissioner(struct ubus_context *aContext, struct ubus_object *aObj, @@ -1006,7 +952,6 @@ class UbusServer * * @param[in] aState The state of commissioner. * @param[in] aContext A pointer to the ubus context. - * */ static void HandleStateChanged(otCommissionerState aState, void *aContext); @@ -1014,7 +959,6 @@ class UbusServer * This method handle conmmissione state change. * * @param[in] aState The state of commissioner. - * */ void HandleStateChanged(otCommissionerState aState); @@ -1025,7 +969,6 @@ class UbusServer * @param[in] aJoinerInfo A pointer to the Joiner Info. * @param[in] aJoinerId A pointer to the Joiner ID (if not known, it will be NULL). * @param[in] aContext A pointer to application-specific context. - * */ static void HandleJoinerEvent(otCommissionerJoinerEvent aEvent, const otJoinerInfo *aJoinerInfo, @@ -1038,7 +981,6 @@ class UbusServer * @param[in] aEvent The joiner event type. * @param[in] aJoinerInfo A pointer to the Joiner Info. * @param[in] aJoinerId A pointer to the Joiner ID (if not known, it will be NULL). - * */ void HandleJoinerEvent(otCommissionerJoinerEvent aEvent, const otJoinerInfo *aJoinerInfo, @@ -1049,13 +991,11 @@ class UbusServer * * @param[in] aInstance A pointer to the instance. * @param[out] aState A pointer to the string address. - * */ void GetState(otInstance *aInstance, char *aState); /** * This method add fd of ubus object. - * */ void UbusAddFd(void); @@ -1063,7 +1003,6 @@ class UbusServer * This method set ubus reconnect time. * * @param[in] aTimeout A pointer to the timeout. - * */ static void UbusReconnTimer(struct uloop_timeout *aTimeout); @@ -1071,7 +1010,6 @@ class UbusServer * This method detailly handle ubus reconnect time. * * @param[in] aTimeout A pointer to the timeout. - * */ void UbusReconnTimerDetail(struct uloop_timeout *aTimeout); @@ -1079,7 +1017,6 @@ class UbusServer * This method handle ubus connection lost. * * @param[in] aContext A pointer to the context. - * */ static void UbusConnectionLost(struct ubus_context *aContext); @@ -1089,13 +1026,11 @@ class UbusServer * @param[in] aPath A pointer to the ubus server path(default is nullptr). * * @retval 0 Successfully handler the request. - * */ int DisplayUbusInit(const char *aPath); /** * This method disconnect and display ubus. - * */ void DisplayUbusDone(void); @@ -1107,7 +1042,6 @@ class UbusServer * * @retval OT_ERROR_NONE Successfully parsed the ASCII string. * @retval OT_ERROR_PARSE Could not parse the ASCII string. - * */ otError ParseLong(char *aString, long &aLong); @@ -1128,7 +1062,6 @@ class UbusServer * @param[in] aBytes A pointer to the bytes need to be convert. * @param[in] aLength The length of the bytes. * @param[out] aOutput A pointer to the char* string. - * */ void OutputBytes(const uint8_t *aBytes, uint8_t aLength, char *aOutput); @@ -1138,7 +1071,6 @@ class UbusServer * @param[in] aError The error type of the message. * @param[in] aContext A pointer to the context. * @param[in] aRequest A pointer to the request. - * */ void AppendResult(otError aError, struct ubus_context *aContext, struct ubus_request_data *aRequest); }; @@ -1150,7 +1082,6 @@ class UBusAgent : public MainloopProcessor * The constructor to initialize the UBus agent. * * @param[in] aHost A reference to the Thread controller. - * */ UBusAgent(otbr::Ncp::RcpHost &aHost) : mHost(aHost) @@ -1160,7 +1091,6 @@ class UBusAgent : public MainloopProcessor /** * This method initializes the UBus agent. - * */ void Init(void); diff --git a/src/proto/CMakeLists.txt b/src/proto/CMakeLists.txt index 3659b515e71..81b397c4b0d 100644 --- a/src/proto/CMakeLists.txt +++ b/src/proto/CMakeLists.txt @@ -1,9 +1,9 @@ # Config brew protobuf version for Mac, see .github/workflows/macOS.yml if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(Protobuf_PREFIX_PATH - "/usr/local/opt/protobuf@21/include" - "/usr/local/opt/protobuf@21/lib" - "/usr/local/opt/protobuf@21/bin") + "/opt/homebrew/opt/protobuf@21/include" + "/opt/homebrew/opt/protobuf@21/lib" + "/opt/homebrew/opt/protobuf@21/bin") list(APPEND CMAKE_PREFIX_PATH "${Protobuf_PREFIX_PATH}") endif() find_package(Protobuf REQUIRED) diff --git a/src/proto/feature_flag.proto b/src/proto/feature_flag.proto index e900defacd4..c156dfc40ee 100644 --- a/src/proto/feature_flag.proto +++ b/src/proto/feature_flag.proto @@ -66,4 +66,6 @@ message FeatureFlagList { optional bool enable_dhcp6_pd = 6 [default = false]; // Whether to enable link metrics manager. optional bool enable_link_metrics_manager = 7 [default = false]; + // Whether to enable the ePSKc feature. + optional bool enable_ephemeralkey = 8 [default = false]; } diff --git a/src/proto/thread_telemetry.proto b/src/proto/thread_telemetry.proto index 1a556dd6fea..f8ef9f4f51c 100644 --- a/src/proto/thread_telemetry.proto +++ b/src/proto/thread_telemetry.proto @@ -115,6 +115,8 @@ message TelemetryData { optional uint32 neighbor_table_size = 15; optional int32 instant_rssi = 16; optional uint64 extended_pan_id = 17; + // Indicates the number peer BR in Thread mesh network (from network data) + optional uint32 peer_br_count = 18; } message TopoEntry { @@ -494,6 +496,8 @@ message TelemetryData { optional uint32 link_local_address_count = 5; optional uint32 unique_local_address_count = 6; optional uint32 global_unicast_address_count = 7; + // Indicates how many peer BRs (connected to the same Thread mesh network) are on the infra link. + optional uint32 peer_br_count = 8; } // Message to indicate the information of external routes in network data. @@ -509,6 +513,61 @@ message TelemetryData { optional bool has_others_route_added = 3; } + message BorderAgentCounters { + // The number of ePSKc activations + optional uint32 epskc_activations = 1; + + // The number of ePSKc deactivations due to cleared via API + optional uint32 epskc_deactivation_clears = 2; + + // The number of ePSKc deactivations due to timeout + optional uint32 epskc_deactivation_timeouts = 3; + + // The number of ePSKc deactivations due to max connection attempts reached + optional uint32 epskc_deactivation_max_attempts = 4; + + // The number of ePSKc deactivations due to commissioner disconnected + optional uint32 epskc_deactivation_disconnects = 5; + + // The number of ePSKc activation failures caused by invalid border agent state + optional uint32 epskc_invalid_ba_state_errors = 6; + + // The number of ePSKc activation failures caused by invalid argument + optional uint32 epskc_invalid_args_errors = 7; + + // The number of ePSKc activation failures caused by failed to start secure session + optional uint32 epskc_start_secure_session_errors = 8; + + // The number of successful secure session establishment with ePSKc + optional uint32 epskc_secure_session_successes = 9; + + // The number of failed secure session establishement with ePSKc + optional uint32 epskc_secure_session_failures = 10; + + // The number of active commissioner petitioned over secure session establishment with ePSKc + optional uint32 epskc_commissioner_petitions = 11; + + // The number of successful secure session establishment with PSKc + optional uint32 pskc_secure_session_successes = 12; + + // The number of failed secure session establishement with PSKc + optional uint32 pskc_secure_session_failures = 13; + + // The number of active commissioner petitioned over secure session establishment with PSKc + optional uint32 pskc_commissioner_petitions = 14; + + // The number of MGMT_ACTIVE_GET.req received + optional uint32 mgmt_active_get_reqs = 15; + + // The number of MGMT_PENDING_GET.req received + optional uint32 mgmt_pending_get_reqs = 16; + } + + message BorderAgentInfo { + // The border agent counters + optional BorderAgentCounters border_agent_counters = 1; + } + message WpanBorderRouter { // Border routing counters optional BorderRoutingCounters border_routing_counters = 1; @@ -548,6 +607,9 @@ message TelemetryData { // Information about the external routes in network data. optional ExternalRoutes external_route_info = 13; + + // Information about the Border Agent + optional BorderAgentInfo border_agent_info = 14; } message RcpStabilityStatistics { diff --git a/src/rest/connection.hpp b/src/rest/connection.hpp index 728c2b7e2fd..9ac30373122 100644 --- a/src/rest/connection.hpp +++ b/src/rest/connection.hpp @@ -50,7 +50,6 @@ namespace rest { /** * This class implements a Connection class of each socket connection. - * */ class Connection : public MainloopProcessor { @@ -64,20 +63,16 @@ class Connection : public MainloopProcessor * state. * @param[in] aResource A pointer to the resource handler. * @param[in] aFd The file descriptor for the connection. - * */ Connection(steady_clock::time_point aStartTime, Resource *aResource, int aFd); /** * The desctructor destroys the connection instance. - * */ ~Connection(void) override; /** * This method initializes the connection. - * - * */ void Init(void); @@ -89,7 +84,6 @@ class Connection : public MainloopProcessor * * @retval TRUE This connection could be released in next loop. * @retval FALSE This connection still needs to be processed in next loop. - * */ bool IsComplete(void) const; diff --git a/src/rest/json.hpp b/src/rest/json.hpp index 7df74db5ab0..22cc0f94615 100644 --- a/src/rest/json.hpp +++ b/src/rest/json.hpp @@ -49,7 +49,6 @@ namespace rest { /** * The functions within this namespace provides a tranformation from an object/string/number to a serialized Json * string. - * */ namespace Json { @@ -59,7 +58,6 @@ namespace Json { * @param[in] aNumber An integer need to be format. * * @returns A string of serialized Json number. - * */ std::string Number2JsonString(const uint32_t &aNumber); @@ -69,7 +67,6 @@ std::string Number2JsonString(const uint32_t &aNumber); * @param[in] aBytes A Bytes array representing a hex number. * * @returns A string of serialized Json string. - * */ std::string Bytes2HexJsonString(const uint8_t *aBytes, uint8_t aLength); @@ -81,7 +78,6 @@ std::string Bytes2HexJsonString(const uint8_t *aBytes, uint8_t aLength); * @param[in] aMaxLength Maximum length to parse (in bytes). * * @returns Number of bytes effectively parsed. - * */ int Hex2BytesJsonString(const std::string &aHexString, uint8_t *aBytes, uint8_t aMaxLength); @@ -91,7 +87,6 @@ int Hex2BytesJsonString(const std::string &aHexString, uint8_t *aBytes, uint8_t * @param[in] aCString A char pointer pointing to a C string. * * @returns A string of serialized Json string. - * */ std::string CString2JsonString(const char *aCString); @@ -101,7 +96,6 @@ std::string CString2JsonString(const char *aCString); * @param[in] aString A string. * * @returns A string of serialized Json string. - * */ std::string String2JsonString(const std::string &aString); @@ -121,7 +115,6 @@ bool JsonString2String(const std::string &aJsonString, std::string &aString); * @param[in] aNode A Node object. * * @returns A string of serialized Json object. - * */ std::string Node2JsonString(const NodeInfo &aNode); @@ -131,7 +124,6 @@ std::string Node2JsonString(const NodeInfo &aNode); * @param[in] aDiagSet A vector of diagnostic objects. * * @returns A string of serialized Json array. - * */ std::string Diag2JsonString(const std::vector> &aDiagSet); @@ -141,7 +133,6 @@ std::string Diag2JsonString(const std::vector> &aD * @param[in] aAddress An Ip6Address object. * * @returns A string of serialized Json string. - * */ std::string IpAddr2JsonString(const otIp6Address &aAddress); @@ -151,7 +142,6 @@ std::string IpAddr2JsonString(const otIp6Address &aAddress); * @param[in] aMode A LinkModeConfig object. * * @returns A string of serialized Json object. - * */ std::string Mode2JsonString(const otLinkModeConfig &aMode); @@ -161,7 +151,6 @@ std::string Mode2JsonString(const otLinkModeConfig &aMode); * @param[in] aConnectivity A Connectivity object. * * @returns A string of serialized Json object. - * */ std::string Connectivity2JsonString(const otNetworkDiagConnectivity &aConnectivity); @@ -171,7 +160,6 @@ std::string Connectivity2JsonString(const otNetworkDiagConnectivity &aConnectivi * @param[in] aRoute A Route object. * * @returns A string of serialized Json object. - * */ std::string Route2JsonString(const otNetworkDiagRoute &aRoute); @@ -181,7 +169,6 @@ std::string Route2JsonString(const otNetworkDiagRoute &aRoute); * @param[in] aRouteData A RouteData object. * * @returns A string of serialized Json object. - * */ std::string RouteData2JsonString(const otNetworkDiagRouteData &aRouteData); @@ -191,7 +178,6 @@ std::string RouteData2JsonString(const otNetworkDiagRouteData &aRouteData); * @param[in] aLeaderData A LeaderData object. * * @returns A string of serialized Json object. - * */ std::string LeaderData2JsonString(const otLeaderData &aLeaderData); @@ -201,7 +187,6 @@ std::string LeaderData2JsonString(const otLeaderData &aLeaderData); * @param[in] aMacCounters A MacCounters object. * * @returns A string of serialized Json object. - * */ std::string MacCounters2JsonString(const otNetworkDiagMacCounters &aMacCounters); @@ -211,7 +196,6 @@ std::string MacCounters2JsonString(const otNetworkDiagMacCounters &aMacCounters) * @param[in] aChildEntry A ChildEntry object. * * @returns A string of serialized Json object. - * */ std::string ChildTableEntry2JsonString(const otNetworkDiagChildEntry &aChildEntry); @@ -222,7 +206,6 @@ std::string ChildTableEntry2JsonString(const otNetworkDiagChildEntry &aChildEntr * @param[in] aErrorMessage Error message such as '404 Not Found'. * * @returns A string of serialized Json object. - * */ std::string Error2JsonString(HttpStatusCode aErrorCode, std::string aErrorMessage); @@ -232,7 +215,6 @@ std::string Error2JsonString(HttpStatusCode aErrorCode, std::string aErrorMessag * @param[in] aDataset A dataset struct. * * @returns A string of serialized Json object. - * */ std::string ActiveDataset2JsonString(const otOperationalDataset &aDataset); @@ -242,7 +224,6 @@ std::string ActiveDataset2JsonString(const otOperationalDataset &aDataset); * @param[in] aDataset A dataset struct. * * @returns A string of serialized Json object. - * */ std::string PendingDataset2JsonString(const otOperationalDataset &aPendingDataset); @@ -255,7 +236,6 @@ std::string PendingDataset2JsonString(const otOperationalDataset &aPendingDatase * @param[in] aDataset The dataset struct to be filled. * * @returns If the Json string has been successfully parsed. - * */ bool JsonActiveDatasetString2Dataset(const std::string &aJsonActiveDataset, otOperationalDataset &aDataset); @@ -268,7 +248,6 @@ bool JsonActiveDatasetString2Dataset(const std::string &aJsonActiveDataset, otOp * @param[in] aDataset The dataset struct to be filled. * * @returns If the Json string has been successfully parsed. - * */ bool JsonPendingDatasetString2Dataset(const std::string &aJsonPendingDataset, otOperationalDataset &aDataset); diff --git a/src/rest/parser.hpp b/src/rest/parser.hpp index b79d79a83c5..f54378787e3 100644 --- a/src/rest/parser.hpp +++ b/src/rest/parser.hpp @@ -51,7 +51,6 @@ namespace rest { /** * This class implements Parser class in OTBR-REST which is used to parse the data from read buffer and form a request. - * */ class Parser { @@ -60,13 +59,11 @@ class Parser * The constructor of a http request parser instance. * * @param[in] aRequest A pointer to a request instance. - * */ Parser(Request *aRequest); /** * This method initializea the http-parser. - * */ void Init(void); @@ -75,7 +72,6 @@ class Parser * * @param[in] aBuf A pointer pointing to read buffer. * @param[in] aLength An integer indicates how much data is to be processed by parser. - * */ void Process(const char *aBuf, size_t aLength); diff --git a/src/rest/request.hpp b/src/rest/request.hpp index ceb92a5f2e4..ccae84f5ab2 100644 --- a/src/rest/request.hpp +++ b/src/rest/request.hpp @@ -47,14 +47,12 @@ namespace rest { /** * This class implements an instance to host services used by border router. - * */ class Request { public: /** * The constructor is to initialize Request instance. - * */ Request(void); @@ -63,7 +61,6 @@ class Request * * @param[in] aString A pointer points to url string. * @param[in] aLength Length of the url string - * */ void SetUrl(const char *aString, size_t aLength); @@ -72,7 +69,6 @@ class Request * * @param[in] aString A pointer points to body string. * @param[in] aLength Length of the body string - * */ void SetBody(const char *aString, size_t aLength); @@ -80,7 +76,6 @@ class Request * This method sets the content-length field of a request. * * @param[in] aContentLength An unsigned integer representing content-length. - * */ void SetContentLength(size_t aContentLength); @@ -88,7 +83,6 @@ class Request * This method sets the method of the parsed request. * * @param[in] aMethod An integer representing request method. - * */ void SetMethod(int32_t aMethod); @@ -97,7 +91,6 @@ class Request * * @param[in] aString A pointer points to body string. * @param[in] aLength Length of the body string - * */ void SetNextHeaderField(const char *aString, size_t aLength); @@ -106,19 +99,16 @@ class Request * * @param[in] aString A pointer points to body string. * @param[in] aLength Length of the body string - * */ void SetHeaderValue(const char *aString, size_t aLength); /** * This method labels the request as complete which means it no longer need to be parsed one more time . - * */ void SetReadComplete(void); /** * This method resets the request then it could be set by parser from start. - * */ void ResetReadComplete(void); @@ -153,8 +143,6 @@ class Request /** * This method indicates whether this request is parsed completely. - * - * */ bool IsComplete(void) const; diff --git a/src/rest/resource.hpp b/src/rest/resource.hpp index 0929dbcc50c..7982843b3a6 100644 --- a/src/rest/resource.hpp +++ b/src/rest/resource.hpp @@ -58,7 +58,6 @@ namespace rest { /** * This class implements the Resource handler for OTBR-REST. - * */ class Resource { @@ -67,14 +66,11 @@ class Resource * The constructor initializes the resource handler instance. * * @param[in] aHost A pointer to the Thread controller. - * */ Resource(RcpHost *aHost); /** * This method initialize the Resource handler. - * - * */ void Init(void); @@ -84,7 +80,6 @@ class Resource * * @param[in] aRequest A request instance referred by the Resource handler. * @param[in,out] aResponse A response instance will be set by the Resource handler. - * */ void Handle(Request &aRequest, Response &aResponse) const; @@ -93,7 +88,6 @@ class Resource * * @param[in] aRequest A request instance referred by the Resource handler. * @param[in,out] aResponse A response instance will be set by the Resource handler. - * */ void HandleCallback(Request &aRequest, Response &aResponse); @@ -103,14 +97,12 @@ class Resource * * @param[in] aRequest A request instance referred by the Resource handler. * @param[in,out] aErrorCode An enum class represents the status code. - * */ void ErrorHandler(Response &aResponse, HttpStatusCode aErrorCode) const; private: /** * This enumeration represents the Dataset type (active or pending). - * */ enum class DatasetType : uint8_t { diff --git a/src/rest/response.hpp b/src/rest/response.hpp index 2bab14c638b..1f544b65301 100644 --- a/src/rest/response.hpp +++ b/src/rest/response.hpp @@ -53,15 +53,12 @@ namespace rest { /** * This class implements a response class for OTBR_REST, it could be manipulated by connection instance and resource * handler. - * */ class Response { public: /** * The constructor to initialize a response instance. - * - * */ Response(void); @@ -69,7 +66,6 @@ class Response * This method set the response body. * * @param[in] aBody A string to be set as response body. - * */ void SetBody(std::string &aBody); @@ -84,7 +80,6 @@ class Response * This method set the response code. * * @param[in] aCode A string representing response code such as "404 not found". - * */ void SetResponsCode(std::string &aCode); @@ -92,14 +87,11 @@ class Response * This method sets the content type. * * @param[in] aCode A string representing response content type such as text/plain. - * */ void SetContentType(const std::string &aContentType); /** * This method labels the response as need callback. - * - * */ void SetCallback(void); @@ -112,7 +104,6 @@ class Response /** * This method labels the response as complete which means all fields has been successfully set. - * */ void SetComplete(); diff --git a/src/rest/rest_web_server.cpp b/src/rest/rest_web_server.cpp index 3c3429762be..4e17acf6794 100644 --- a/src/rest/rest_web_server.cpp +++ b/src/rest/rest_web_server.cpp @@ -79,8 +79,7 @@ void RestWebServer::Init(void) void RestWebServer::Update(MainloopContext &aMainloop) { - FD_SET(mListenFd, &aMainloop.mReadFdSet); - aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, mListenFd); + aMainloop.AddFdToReadSet(mListenFd); return; } diff --git a/src/rest/rest_web_server.hpp b/src/rest/rest_web_server.hpp index 20e4a5b674e..08074c54108 100644 --- a/src/rest/rest_web_server.hpp +++ b/src/rest/rest_web_server.hpp @@ -51,7 +51,6 @@ namespace rest { /** * This class implements a REST server. - * */ class RestWebServer : public MainloopProcessor { @@ -60,19 +59,16 @@ class RestWebServer : public MainloopProcessor * The constructor to initialize a REST server. * * @param[in] aHost A reference to the Thread controller. - * */ RestWebServer(RcpHost &aHost, const std::string &aRestListenAddress, int aRestListenPort); /** * The destructor destroys the server instance. - * */ ~RestWebServer(void) override; /** * This method initializes the REST server. - * */ void Init(void); diff --git a/src/sdp_proxy/advertising_proxy.cpp b/src/sdp_proxy/advertising_proxy.cpp index b0505cc3c64..ea9dc316e91 100644 --- a/src/sdp_proxy/advertising_proxy.cpp +++ b/src/sdp_proxy/advertising_proxy.cpp @@ -51,48 +51,6 @@ namespace otbr { -static otError OtbrErrorToOtError(otbrError aError) -{ - otError error; - - switch (aError) - { - case OTBR_ERROR_NONE: - error = OT_ERROR_NONE; - break; - - case OTBR_ERROR_NOT_FOUND: - error = OT_ERROR_NOT_FOUND; - break; - - case OTBR_ERROR_PARSE: - error = OT_ERROR_PARSE; - break; - - case OTBR_ERROR_NOT_IMPLEMENTED: - error = OT_ERROR_NOT_IMPLEMENTED; - break; - - case OTBR_ERROR_INVALID_ARGS: - error = OT_ERROR_INVALID_ARGS; - break; - - case OTBR_ERROR_DUPLICATED: - error = OT_ERROR_DUPLICATED; - break; - - case OTBR_ERROR_INVALID_STATE: - error = OT_ERROR_INVALID_STATE; - break; - - default: - error = OT_ERROR_FAILED; - break; - } - - return error; -} - AdvertisingProxy::AdvertisingProxy(Ncp::RcpHost &aHost, Mdns::Publisher &aPublisher) : mHost(aHost) , mPublisher(aPublisher) diff --git a/src/sdp_proxy/advertising_proxy.hpp b/src/sdp_proxy/advertising_proxy.hpp index 4b1931d0112..2077d35010e 100644 --- a/src/sdp_proxy/advertising_proxy.hpp +++ b/src/sdp_proxy/advertising_proxy.hpp @@ -51,7 +51,6 @@ namespace otbr { /** * This class implements the Advertising Proxy. - * */ class AdvertisingProxy : private NonCopyable { @@ -61,7 +60,6 @@ class AdvertisingProxy : private NonCopyable * * @param[in] aHost A reference to the NCP controller. * @param[in] aPublisher A reference to the mDNS publisher. - * */ explicit AdvertisingProxy(Ncp::RcpHost &aHost, Mdns::Publisher &aPublisher); @@ -69,13 +67,11 @@ class AdvertisingProxy : private NonCopyable * This method enables/disables the Advertising Proxy. * * @param[in] aIsEnabled Whether to enable the Advertising Proxy. - * */ void SetEnabled(bool aIsEnabled); /** * This method publishes all registered hosts and services. - * */ void PublishAllHostsAndServices(void); @@ -83,7 +79,6 @@ class AdvertisingProxy : private NonCopyable * This method handles mDNS publisher's state changes. * * @param[in] aState The state of mDNS publisher. - * */ void HandleMdnsState(Mdns::Publisher::State aState); @@ -122,7 +117,6 @@ class AdvertisingProxy : private NonCopyable * * @retval OTBR_ERROR_NONE Successfully published the host and its services. * @retval ... Failed to publish the host and/or its services. - * */ otbrError PublishHostAndItsServices(const otSrpServerHost *aHost, OutstandingUpdate *aUpdate); diff --git a/src/sdp_proxy/discovery_proxy.hpp b/src/sdp_proxy/discovery_proxy.hpp index 188a81bff37..9278cf49667 100644 --- a/src/sdp_proxy/discovery_proxy.hpp +++ b/src/sdp_proxy/discovery_proxy.hpp @@ -55,7 +55,6 @@ namespace Dnssd { /** * This class implements the DNS-SD Discovery Proxy. - * */ class DiscoveryProxy : private NonCopyable { @@ -65,7 +64,6 @@ class DiscoveryProxy : private NonCopyable * * @param[in] aHost A reference to the OpenThread Controller instance. * @param[in] aPublisher A reference to the mDNS Publisher. - * */ explicit DiscoveryProxy(Ncp::RcpHost &aHost, Mdns::Publisher &aPublisher); @@ -73,7 +71,6 @@ class DiscoveryProxy : private NonCopyable * This method enables/disables the Discovery Proxy. * * @param[in] aIsEnabled Whether to enable the Discovery Proxy. - * */ void SetEnabled(bool aIsEnabled); @@ -81,7 +78,6 @@ class DiscoveryProxy : private NonCopyable * This method handles mDNS publisher's state changes. * * @param[in] aState The state of mDNS publisher. - * */ void HandleMdnsState(Mdns::Publisher::State aState) { diff --git a/src/trel_dnssd/trel_dnssd.hpp b/src/trel_dnssd/trel_dnssd.hpp index 6c8555c90b0..d6856b1d8ae 100644 --- a/src/trel_dnssd/trel_dnssd.hpp +++ b/src/trel_dnssd/trel_dnssd.hpp @@ -68,7 +68,6 @@ class TrelDnssd * * @param[in] aHost A reference to the OpenThread Controller instance. * @param[in] aPublisher A reference to the mDNS Publisher. - * */ explicit TrelDnssd(Ncp::RcpHost &aHost, Mdns::Publisher &aPublisher); @@ -76,19 +75,16 @@ class TrelDnssd * This method initializes the TrelDnssd instance. * * @param[in] aTrelNetif The network interface for discovering TREL peers. - * */ void Initialize(std::string aTrelNetif); /** * This method starts browsing for TREL peers. - * */ void StartBrowse(void); /** * This method stops browsing for TREL peers. - * */ void StopBrowse(void); @@ -98,13 +94,11 @@ class TrelDnssd * @param[in] aPort The UDP port of TREL service. * @param[in] aTxtData The TXT data of TREL service. * @param[in] aTxtLength The TXT length of TREL service. - * */ void RegisterService(uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength); /** * This method removes the TREL service from DNS-SD. - * */ void UnregisterService(void); @@ -112,7 +106,6 @@ class TrelDnssd * This method handles mDNS publisher's state changes. * * @param[in] aState The state of mDNS publisher. - * */ void HandleMdnsState(Mdns::Publisher::State aState); diff --git a/src/utils/crc16.hpp b/src/utils/crc16.hpp index 6d2167c01d4..19ae8c6050f 100644 --- a/src/utils/crc16.hpp +++ b/src/utils/crc16.hpp @@ -42,7 +42,6 @@ namespace otbr { /** * This class implements CRC16 computations. - * */ class Crc16 { @@ -57,13 +56,11 @@ class Crc16 * This constructor initializes the object. * * @param[in] aPolynomial The polynomial value. - * */ Crc16(Polynomial aPolynomial); /** * This method initializes the CRC16 computation. - * */ void Init(void) { mCrc = 0; } @@ -71,7 +68,6 @@ class Crc16 * This method feeds a byte value into the CRC16 computation. * * @param[in] aByte The byte value. - * */ void Update(uint8_t aByte); @@ -79,7 +75,6 @@ class Crc16 * This method gets the current CRC16 value. * * @returns The current CRC16 value. - * */ uint16_t Get(void) const { return mCrc; } diff --git a/src/utils/dns_utils.hpp b/src/utils/dns_utils.hpp index 9addf66f74b..829112bcb78 100644 --- a/src/utils/dns_utils.hpp +++ b/src/utils/dns_utils.hpp @@ -51,7 +51,6 @@ namespace DnsUtils { * @param[in] aName The DNS Service Instance name to unescape. * * @returns The unescaped DNS Service Instance name. - * */ std::string UnescapeInstanceName(const std::string &aName); @@ -62,7 +61,6 @@ std::string UnescapeInstanceName(const std::string &aName); * The host name must ends with dot. * * @param[in] aHostName The host name to check. - * */ void CheckHostnameSanity(const std::string &aHostName); @@ -74,7 +72,6 @@ void CheckHostnameSanity(const std::string &aHostName); * The service name must not end with dot. * * @param[in] aServiceName The service name to check. - * */ void CheckServiceNameSanity(const std::string &aServiceName); diff --git a/src/utils/infra_link_selector.cpp b/src/utils/infra_link_selector.cpp index 0f2760bec1d..ac239ab9ff6 100644 --- a/src/utils/infra_link_selector.cpp +++ b/src/utils/infra_link_selector.cpp @@ -235,8 +235,7 @@ void InfraLinkSelector::Update(MainloopContext &aMainloop) { if (mNetlinkSocket != -1) { - FD_SET(mNetlinkSocket, &aMainloop.mReadFdSet); - aMainloop.mMaxFd = std::max(mNetlinkSocket, aMainloop.mMaxFd); + aMainloop.AddFdToReadSet(mNetlinkSocket); } } diff --git a/src/utils/infra_link_selector.hpp b/src/utils/infra_link_selector.hpp index f2bcd832908..5697fd48e03 100644 --- a/src/utils/infra_link_selector.hpp +++ b/src/utils/infra_link_selector.hpp @@ -56,7 +56,6 @@ * * This function should return the infrastructure link that is selected by platform specific rules. * If the function returns nullptr, the generic infrastructure link selections rules will be applied. - * */ extern "C" const char *otbrVendorInfraLinkSelect(void); #endif @@ -66,7 +65,6 @@ namespace Utils { /** * This class implements Infrastructure Link Selector. - * */ class InfraLinkSelector : public MainloopProcessor, private NonCopyable { @@ -75,13 +73,11 @@ class InfraLinkSelector : public MainloopProcessor, private NonCopyable * This constructor initializes the InfraLinkSelector instance. * * @param[in] aInfraLinkNames A list of infrastructure link candidates to select from. - * */ explicit InfraLinkSelector(std::vector aInfraLinkNames); /** * This destructor destroys the InfraLinkSelector instance. - * */ ~InfraLinkSelector(void); @@ -98,14 +94,12 @@ class InfraLinkSelector : public MainloopProcessor, private NonCopyable * The interface has been `up and running` within last 10 seconds * * @returns The selected infrastructure link. - * */ const char *Select(void); private: /** * This enumeration infrastructure link states. - * */ enum LinkState : uint8_t { diff --git a/src/utils/pskc.hpp b/src/utils/pskc.hpp index 3a037e6c5c8..ed26701cd53 100644 --- a/src/utils/pskc.hpp +++ b/src/utils/pskc.hpp @@ -67,7 +67,6 @@ class Pskc * @param[in] aPassphrase A pointer to passphrase. * * @returns The pointer to PSKc value. - * */ const uint8_t *ComputePskc(const uint8_t *aExtPanId, const char *aNetworkName, const char *aPassphrase); diff --git a/src/utils/sha256.hpp b/src/utils/sha256.hpp index df90a846a38..24f119eb6b6 100644 --- a/src/utils/sha256.hpp +++ b/src/utils/sha256.hpp @@ -45,19 +45,16 @@ 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 { @@ -68,26 +65,22 @@ class Sha256 * 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); @@ -96,7 +89,6 @@ class Sha256 * * @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); @@ -104,7 +96,6 @@ class Sha256 * This method finalizes the hash computation. * * @param[out] aHash A reference to a `Hash` to output the calculated hash. - * */ void Finish(Hash &aHash); diff --git a/src/utils/socket_utils.hpp b/src/utils/socket_utils.hpp index 33986d3e829..7893ac4ec74 100644 --- a/src/utils/socket_utils.hpp +++ b/src/utils/socket_utils.hpp @@ -54,7 +54,6 @@ enum SocketBlockOption * * @retval -1 Failed to create socket. * @retval ... The file descriptor of the created socket. - * */ int SocketWithCloseExec(int aDomain, int aType, int aProtocol, SocketBlockOption aBlockOption); @@ -65,7 +64,6 @@ int SocketWithCloseExec(int aDomain, int aType, int aProtocol, SocketBlockOption * * @retval -1 Failed to create the netlink socket. * @retval ... The file descriptor of the created netlink socket. - * */ int CreateNetLinkRouteSocket(uint32_t aNlGroups); diff --git a/src/utils/steering_data.hpp b/src/utils/steering_data.hpp index 481b9a4d368..1c43840faef 100644 --- a/src/utils/steering_data.hpp +++ b/src/utils/steering_data.hpp @@ -43,7 +43,6 @@ namespace otbr { /** * This class represents Steering Data - * */ class SteeringData { @@ -58,19 +57,16 @@ class SteeringData * This method initializes the bloom filter. * * @param[in] aLength The length of the bloom filter in bytes. - * */ void Init(uint8_t aLength); /** * This method sets all bits in the bloom filter to zero. - * */ void Clear(void) { memset(mBloomFilter, 0, sizeof(mBloomFilter)); } /** * Ths method sets all bits in the bloom filter to one. - * */ void Set(void) { memset(mBloomFilter, 0xff, sizeof(mBloomFilter)); } @@ -78,7 +74,6 @@ class SteeringData * This method sets bit @p aBit. * * @param[in] aBit The bit offset. - * */ void SetBit(uint8_t aBit) { mBloomFilter[mLength - 1 - (aBit / 8)] |= 1 << (aBit % 8); } @@ -86,7 +81,6 @@ class SteeringData * This method computes the Bloom Filter. * * @param[in] aJoinerId Extended address - * */ void ComputeBloomFilter(const uint8_t *aJoinerId); @@ -95,7 +89,6 @@ class SteeringData * * @param[in] aEui64 A pointer to EUI64. * @param[out] aJoinerId A pointer to receive joiner id. This pointer can be the same as @p aEui64. - * */ static void ComputeJoinerId(const uint8_t *aEui64, uint8_t *aJoinerId); @@ -103,13 +96,11 @@ class SteeringData * This method returns a pointer to the bloom filter. * * @returns A pointer to the computed bloom filter. - * */ const uint8_t *GetBloomFilter(void) const { return mBloomFilter; } /** * This method returns the length of the bloom filter. - * */ uint8_t GetLength(void) const { return mLength; } diff --git a/src/utils/string_utils.hpp b/src/utils/string_utils.hpp index 06255ead70f..21fb792212a 100644 --- a/src/utils/string_utils.hpp +++ b/src/utils/string_utils.hpp @@ -50,7 +50,6 @@ namespace StringUtils { * @param[in] aString2 The second string. * * @returns Whether the two strings are equal in a case-insensitive manner. - * */ bool EqualCaseInsensitive(const std::string &aString1, const std::string &aString2); @@ -60,7 +59,6 @@ bool EqualCaseInsensitive(const std::string &aString1, const std::string &aStrin * @param[in] aString The string to convert. * * @returns A copy of @p aString with all letters converted to lowercase. - * */ std::string ToLowercase(const std::string &aString); diff --git a/src/utils/system_utils.hpp b/src/utils/system_utils.hpp index 2af1ae2eb15..dff9938ad12 100644 --- a/src/utils/system_utils.hpp +++ b/src/utils/system_utils.hpp @@ -50,7 +50,6 @@ extern "C" { * @param[in] ... Arguments for the format specification. * * @returns The command exit code. - * */ int ExecuteCommand(const char *aFormat, ...); diff --git a/src/utils/thread_helper.cpp b/src/utils/thread_helper.cpp index bed81f0db4b..7722f1a4c3d 100644 --- a/src/utils/thread_helper.cpp +++ b/src/utils/thread_helper.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -248,7 +249,7 @@ void ThreadHelper::StateChangedCallback(otChangedFlags aFlags) { if (aFlags & OT_CHANGED_THREAD_ROLE) { - otDeviceRole role = otThreadGetDeviceRole(mInstance); + otDeviceRole role = mHost->GetDeviceRole(); for (const auto &handler : mDeviceRoleHandlers) { @@ -426,6 +427,29 @@ void ThreadHelper::ActiveScanHandler(otActiveScanResult *aResult) } } +#if OTBR_ENABLE_DHCP6_PD +void ThreadHelper::SetDhcp6PdStateCallback(Dhcp6PdStateCallback aCallback) +{ + mDhcp6PdCallback = std::move(aCallback); + otBorderRoutingDhcp6PdSetRequestCallback(mInstance, &ThreadHelper::BorderRoutingDhcp6PdCallback, this); +} + +void ThreadHelper::BorderRoutingDhcp6PdCallback(otBorderRoutingDhcp6PdState aState, void *aThreadHelper) +{ + ThreadHelper *helper = static_cast(aThreadHelper); + + helper->BorderRoutingDhcp6PdCallback(aState); +} + +void ThreadHelper::BorderRoutingDhcp6PdCallback(otBorderRoutingDhcp6PdState aState) +{ + if (mDhcp6PdCallback != nullptr) + { + mDhcp6PdCallback(aState); + } +} +#endif // OTBR_ENABLE_DHCP6_PD + void ThreadHelper::EnergyScanCallback(otEnergyScanResult *aResult, void *aThreadHelper) { ThreadHelper *helper = static_cast(aThreadHelper); @@ -647,7 +671,7 @@ otError ThreadHelper::TryResumeNetwork(void) { otError error = OT_ERROR_NONE; - if (otLinkGetPanId(mInstance) != UINT16_MAX && otThreadGetDeviceRole(mInstance) == OT_DEVICE_ROLE_DISABLED) + if (otLinkGetPanId(mInstance) != UINT16_MAX && mHost->GetDeviceRole() == OT_DEVICE_ROLE_DISABLED) { if (!otIp6IsEnabled(mInstance)) { @@ -685,10 +709,7 @@ void ThreadHelper::AttachAllNodesTo(const std::vector &aDatasetTlvs, At otOperationalDatasetTlvs datasetTlvs; otOperationalDataset dataset; otOperationalDataset emptyDataset{}; - otDeviceRole role = otThreadGetDeviceRole(mInstance); - Tlv *tlv; - uint64_t pendingTimestamp = 0; - timespec currentTime; + otDeviceRole role = mHost->GetDeviceRole(); if (aHandler == nullptr) { @@ -713,30 +734,7 @@ void ThreadHelper::AttachAllNodesTo(const std::vector &aDatasetTlvs, At VerifyOrExit(dataset.mComponents.mIsSecurityPolicyPresent, error = OT_ERROR_INVALID_ARGS); VerifyOrExit(dataset.mComponents.mIsChannelMaskPresent, error = OT_ERROR_INVALID_ARGS); - VerifyOrExit(FindTlv(OT_MESHCOP_TLV_PENDINGTIMESTAMP, datasetTlvs.mTlvs, datasetTlvs.mLength) == nullptr && - FindTlv(OT_MESHCOP_TLV_DELAYTIMER, datasetTlvs.mTlvs, datasetTlvs.mLength) == nullptr, - error = OT_ERROR_INVALID_ARGS); - - // There must be sufficient space for a Pending Timestamp TLV and a Delay Timer TLV. - VerifyOrExit( - static_cast(datasetTlvs.mLength + - (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint64_t)) // Pending Timestamp TLV (10 bytes) - + (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t))) // Delay Timer TLV (6 bytes) - <= int{sizeof(datasetTlvs.mTlvs)}, - error = OT_ERROR_INVALID_ARGS); - - tlv = reinterpret_cast(datasetTlvs.mTlvs + datasetTlvs.mLength); - tlv->SetType(OT_MESHCOP_TLV_PENDINGTIMESTAMP); - clock_gettime(CLOCK_REALTIME, ¤tTime); - pendingTimestamp |= (static_cast(currentTime.tv_sec) << 16); - pendingTimestamp |= (((static_cast(currentTime.tv_nsec) * 32768 / 1000000000) & 0x7fff) << 1); - tlv->SetValue(pendingTimestamp); - - tlv = tlv->GetNext(); - tlv->SetType(OT_MESHCOP_TLV_DELAYTIMER); - tlv->SetValue(kDelayTimerMilliseconds); - - datasetTlvs.mLength = reinterpret_cast(tlv->GetNext()) - datasetTlvs.mTlvs; + SuccessOrExit(error = ProcessDatasetForMigration(datasetTlvs, kDelayTimerMilliseconds)); assert(datasetTlvs.mLength > 0); @@ -921,7 +919,44 @@ void ThreadHelper::DetachGracefullyCallback(void) #if OTBR_ENABLE_TELEMETRY_DATA_API #if OTBR_ENABLE_BORDER_ROUTING -void ThreadHelper::RetrieveExternalRouteInfo(threadnetwork::TelemetryData::ExternalRoutes *aExternalRouteInfo) +void ThreadHelper::RetrieveInfraLinkInfo(threadnetwork::TelemetryData::InfraLinkInfo &aInfraLinkInfo) +{ + { + otSysInfraNetIfAddressCounters addressCounters; + uint32_t ifrFlags = otSysGetInfraNetifFlags(); + + otSysCountInfraNetifAddresses(&addressCounters); + + aInfraLinkInfo.set_name(otSysGetInfraNetifName()); + aInfraLinkInfo.set_is_up((ifrFlags & IFF_UP) != 0); + aInfraLinkInfo.set_is_running((ifrFlags & IFF_RUNNING) != 0); + aInfraLinkInfo.set_is_multicast((ifrFlags & IFF_MULTICAST) != 0); + aInfraLinkInfo.set_link_local_address_count(addressCounters.mLinkLocalAddresses); + aInfraLinkInfo.set_unique_local_address_count(addressCounters.mUniqueLocalAddresses); + aInfraLinkInfo.set_global_unicast_address_count(addressCounters.mGlobalUnicastAddresses); + } + + //---- peer_br_count + { + uint32_t count = 0; + otBorderRoutingPrefixTableIterator iterator; + otBorderRoutingRouterEntry entry; + + otBorderRoutingPrefixTableInitIterator(mInstance, &iterator); + + while (otBorderRoutingGetNextRouterEntry(mInstance, &iterator, &entry) == OT_ERROR_NONE) + { + if (entry.mIsPeerBr) + { + count++; + } + } + + aInfraLinkInfo.set_peer_br_count(count); + } +} + +void ThreadHelper::RetrieveExternalRouteInfo(threadnetwork::TelemetryData::ExternalRoutes &aExternalRouteInfo) { bool isDefaultRouteAdded = false; bool isUlaRouteAdded = false; @@ -954,9 +989,9 @@ void ThreadHelper::RetrieveExternalRouteInfo(threadnetwork::TelemetryData::Exter } } - aExternalRouteInfo->set_has_default_route_added(isDefaultRouteAdded); - aExternalRouteInfo->set_has_ula_route_added(isUlaRouteAdded); - aExternalRouteInfo->set_has_others_route_added(isOthersRouteAdded); + aExternalRouteInfo.set_has_default_route_added(isDefaultRouteAdded); + aExternalRouteInfo.set_has_ula_route_added(isUlaRouteAdded); + aExternalRouteInfo.set_has_others_route_added(isOthersRouteAdded); } #endif // OTBR_ENABLE_BORDER_ROUTING @@ -1025,6 +1060,33 @@ void ThreadHelper::RetrievePdProcessedRaInfo(threadnetwork::TelemetryData::PdPro } #endif // OTBR_ENABLE_DHCP6_PD +#if OTBR_ENABLE_BORDER_AGENT +void ThreadHelper::RetrieveBorderAgentInfo(threadnetwork::TelemetryData::BorderAgentInfo *aBorderAgentInfo) +{ + auto baCounters = aBorderAgentInfo->mutable_border_agent_counters(); + auto otBorderAgentCounters = *otBorderAgentGetCounters(mInstance); + + baCounters->set_epskc_activations(otBorderAgentCounters.mEpskcActivations); + baCounters->set_epskc_deactivation_clears(otBorderAgentCounters.mEpskcDeactivationClears); + baCounters->set_epskc_deactivation_timeouts(otBorderAgentCounters.mEpskcDeactivationTimeouts); + baCounters->set_epskc_deactivation_max_attempts(otBorderAgentCounters.mEpskcDeactivationMaxAttempts); + baCounters->set_epskc_deactivation_disconnects(otBorderAgentCounters.mEpskcDeactivationDisconnects); + baCounters->set_epskc_invalid_ba_state_errors(otBorderAgentCounters.mEpskcInvalidBaStateErrors); + baCounters->set_epskc_invalid_args_errors(otBorderAgentCounters.mEpskcInvalidArgsErrors); + baCounters->set_epskc_start_secure_session_errors(otBorderAgentCounters.mEpskcStartSecureSessionErrors); + baCounters->set_epskc_secure_session_successes(otBorderAgentCounters.mEpskcSecureSessionSuccesses); + baCounters->set_epskc_secure_session_failures(otBorderAgentCounters.mEpskcSecureSessionFailures); + baCounters->set_epskc_commissioner_petitions(otBorderAgentCounters.mEpskcCommissionerPetitions); + + baCounters->set_pskc_secure_session_successes(otBorderAgentCounters.mPskcSecureSessionSuccesses); + baCounters->set_pskc_secure_session_failures(otBorderAgentCounters.mPskcSecureSessionFailures); + baCounters->set_pskc_commissioner_petitions(otBorderAgentCounters.mPskcCommissionerPetitions); + + baCounters->set_mgmt_active_get_reqs(otBorderAgentCounters.mMgmtActiveGets); + baCounters->set_mgmt_pending_get_reqs(otBorderAgentCounters.mMgmtPendingGets); +} +#endif + otError ThreadHelper::RetrieveTelemetryData(Mdns::Publisher *aPublisher, threadnetwork::TelemetryData &telemetryData) { otError error = OT_ERROR_NONE; @@ -1034,7 +1096,7 @@ otError ThreadHelper::RetrieveTelemetryData(Mdns::Publisher *aPublisher, threadn auto wpanStats = telemetryData.mutable_wpan_stats(); { - otDeviceRole role = otThreadGetDeviceRole(mInstance); + otDeviceRole role = mHost->GetDeviceRole(); otLinkModeConfig otCfg = otThreadGetLinkMode(mInstance); wpanStats->set_node_type(TelemetryNodeTypeFromRoleAndLinkMode(role, otCfg)); @@ -1211,6 +1273,9 @@ otError ThreadHelper::RetrieveTelemetryData(Mdns::Publisher *aPublisher, threadn extPanIdVal = ConvertOpenThreadUint64(extPanId->m8); wpanTopoFull->set_extended_pan_id(extPanIdVal); +#if OTBR_ENABLE_BORDER_ROUTING + wpanTopoFull->set_peer_br_count(otBorderRoutingCountPeerBrs(mInstance, /*minAge=*/nullptr)); +#endif // End of WpanTopoFull section. // Begin of TopoEntry section. @@ -1369,27 +1434,8 @@ otError ThreadHelper::RetrieveTelemetryData(Mdns::Publisher *aPublisher, threadn #endif // OTBR_ENABLE_TREL #if OTBR_ENABLE_BORDER_ROUTING - // Begin of InfraLinkInfo section. - { - auto infraLinkInfo = wpanBorderRouter->mutable_infra_link_info(); - otSysInfraNetIfAddressCounters addressCounters; - uint32_t ifrFlags = otSysGetInfraNetifFlags(); - - otSysCountInfraNetifAddresses(&addressCounters); - - infraLinkInfo->set_name(otSysGetInfraNetifName()); - infraLinkInfo->set_is_up((ifrFlags & IFF_UP) != 0); - infraLinkInfo->set_is_running((ifrFlags & IFF_RUNNING) != 0); - infraLinkInfo->set_is_multicast((ifrFlags & IFF_MULTICAST) != 0); - infraLinkInfo->set_link_local_address_count(addressCounters.mLinkLocalAddresses); - infraLinkInfo->set_unique_local_address_count(addressCounters.mUniqueLocalAddresses); - infraLinkInfo->set_global_unicast_address_count(addressCounters.mGlobalUnicastAddresses); - } - // End of InfraLinkInfo section. - - // ExternalRoutes section - RetrieveExternalRouteInfo(wpanBorderRouter->mutable_external_route_info()); - + RetrieveInfraLinkInfo(*wpanBorderRouter->mutable_infra_link_info()); + RetrieveExternalRouteInfo(*wpanBorderRouter->mutable_external_route_info()); #endif #if OTBR_ENABLE_SRP_ADVERTISING_PROXY @@ -1553,6 +1599,9 @@ otError ThreadHelper::RetrieveTelemetryData(Mdns::Publisher *aPublisher, threadn #if OTBR_ENABLE_DHCP6_PD RetrievePdInfo(wpanBorderRouter); #endif // OTBR_ENABLE_DHCP6_PD +#if OTBR_ENABLE_BORDER_AGENT + RetrieveBorderAgentInfo(wpanBorderRouter->mutable_border_agent_info()); +#endif // OTBR_ENABLE_BORDER_AGENT // End of WpanBorderRouter section. // Start of WpanRcp section. @@ -1650,5 +1699,51 @@ otError ThreadHelper::RetrieveTelemetryData(Mdns::Publisher *aPublisher, threadn return error; } #endif // OTBR_ENABLE_TELEMETRY_DATA_API + +otError ThreadHelper::ProcessDatasetForMigration(otOperationalDatasetTlvs &aDatasetTlvs, uint32_t aDelayMilli) +{ + otError error = OT_ERROR_NONE; + Tlv *tlv; + timespec currentTime; + uint64_t pendingTimestamp = 0; + + VerifyOrExit(FindTlv(OT_MESHCOP_TLV_PENDINGTIMESTAMP, aDatasetTlvs.mTlvs, aDatasetTlvs.mLength) == nullptr, + error = OT_ERROR_INVALID_ARGS); + VerifyOrExit(FindTlv(OT_MESHCOP_TLV_DELAYTIMER, aDatasetTlvs.mTlvs, aDatasetTlvs.mLength) == nullptr, + error = OT_ERROR_INVALID_ARGS); + + // There must be sufficient space for a Pending Timestamp TLV and a Delay Timer TLV. + VerifyOrExit( + static_cast(aDatasetTlvs.mLength + + (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint64_t)) // Pending Timestamp TLV (10 bytes) + + (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t))) // Delay Timer TLV (6 bytes) + <= int{sizeof(aDatasetTlvs.mTlvs)}, + error = OT_ERROR_INVALID_ARGS); + + tlv = reinterpret_cast(aDatasetTlvs.mTlvs + aDatasetTlvs.mLength); + /* + * Pending Timestamp TLV + * + * | Type | Value | Timestamp Seconds | Timestamp Ticks | U bit | + * | 8 | 8 | 48 | 15 | 1 | + */ + tlv->SetType(OT_MESHCOP_TLV_PENDINGTIMESTAMP); + clock_gettime(CLOCK_REALTIME, ¤tTime); + pendingTimestamp |= (static_cast(currentTime.tv_sec) << 16); // Set the 48 bits of Timestamp seconds. + pendingTimestamp |= (((static_cast(currentTime.tv_nsec) * 32768 / 1000000000) & 0x7fff) + << 1); // Set the 15 bits of Timestamp ticks, the fractional Unix Time value in 32.768 kHz + // resolution. Leave the U-bit unset. + tlv->SetValue(pendingTimestamp); + + tlv = tlv->GetNext(); + tlv->SetType(OT_MESHCOP_TLV_DELAYTIMER); + tlv->SetValue(aDelayMilli); + + aDatasetTlvs.mLength = reinterpret_cast(tlv->GetNext()) - aDatasetTlvs.mTlvs; + +exit: + return error; +} + } // namespace agent } // namespace otbr diff --git a/src/utils/thread_helper.hpp b/src/utils/thread_helper.hpp index 0bfce11513a..ed55d3a2a17 100644 --- a/src/utils/thread_helper.hpp +++ b/src/utils/thread_helper.hpp @@ -43,6 +43,7 @@ #include #include +#include #include #include #include @@ -76,13 +77,15 @@ class ThreadHelper using AttachHandler = std::function; using UpdateMeshCopTxtHandler = std::function>)>; using DatasetChangeHandler = std::function; +#if OTBR_ENABLE_DHCP6_PD + using Dhcp6PdStateCallback = std::function; +#endif /** * The constructor of a Thread helper. * * @param[in] aInstance The Thread instance. * @param[in] aHost The Thread controller. - * */ ThreadHelper(otInstance *aInstance, otbr::Ncp::RcpHost *aHost); @@ -90,10 +93,18 @@ class ThreadHelper * This method adds a callback for device role change. * * @param[in] aHandler The device role handler. - * */ void AddDeviceRoleHandler(DeviceRoleHandler aHandler); +#if OTBR_ENABLE_DHCP6_PD + /** + * This method adds a callback for DHCPv6 PD state change. + * + * @param[in] aCallback The DHCPv6 PD state change callback. + */ + void SetDhcp6PdStateCallback(Dhcp6PdStateCallback aCallback); +#endif + /** * This method adds a callback for active dataset change. * @@ -108,7 +119,6 @@ class ThreadHelper * @param[in] aSeconds The timeout to close the port, 0 for never close. * * @returns The error value of underlying OpenThread api calls. - * */ otError PermitUnsecureJoin(uint16_t aPort, uint32_t aSeconds); @@ -116,7 +126,6 @@ class ThreadHelper * This method performs a Thread network scan. * * @param[in] aHandler The scan result handler. - * */ void Scan(ScanHandler aHandler); @@ -125,7 +134,6 @@ class ThreadHelper * * @param[in] aScanDuration The duration for the scan, in milliseconds. * @param[in] aHandler The scan result handler. - * */ void EnergyScan(uint32_t aScanDuration, EnergyScanHandler aHandler); @@ -141,7 +149,6 @@ class ThreadHelper * @param[in] aPSKc The pre-shared commissioner key, empty for random. * @param[in] aChannelMask A bitmask for valid channels, will random select one. * @param[in] aHandler The attach result handler. - * */ void Attach(const std::string &aNetworkName, uint16_t aPanId, @@ -155,7 +162,6 @@ class ThreadHelper * This method detaches the device from the Thread network. * * @returns The error value of underlying OpenThread API calls. - * */ otError Detach(void); @@ -166,7 +172,6 @@ class ThreadHelper * network parameter will be set through the active dataset. * * @param[in] aHandler The attach result handler. - * */ void Attach(AttachHandler aHandler); @@ -175,7 +180,6 @@ class ThreadHelper * * @param[in] aDatasetTlvs The dataset TLVs. * @param[in] aHandler The result handler. - * */ void AttachAllNodesTo(const std::vector &aDatasetTlvs, AttachHandler aHandler); @@ -183,7 +187,6 @@ class ThreadHelper * This method resets the OpenThread stack. * * @returns The error value of underlying OpenThread api calls. - * */ otError Reset(void); @@ -199,7 +202,6 @@ class ThreadHelper * @param[in] aVendorSwVersion The vendor software version. * @param[in] aVendorData The vendor custom data. * @param[in] aHandler The join result handler. - * */ void JoinerStart(const std::string &aPskd, const std::string &aProvisioningUrl, @@ -213,7 +215,6 @@ class ThreadHelper * This method tries to restore the network after reboot * * @returns The error value of underlying OpenThread api calls. - * */ otError TryResumeNetwork(void); @@ -221,15 +222,16 @@ class ThreadHelper * This method returns the underlying OpenThread instance. * * @returns The underlying instance. - * */ - otInstance *GetInstance(void) { return mInstance; } + otInstance *GetInstance(void) + { + return mInstance; + } /** * This method handles OpenThread state changed notification. * * @param[in] aFlags A bit-field indicating specific state that has changed. See `OT_CHANGED_*` definitions. - * */ void StateChangedCallback(otChangedFlags aFlags); @@ -238,7 +240,6 @@ class ThreadHelper * This method sets a callback for calls of UpdateVendorMeshCopTxtEntries D-Bus API. * * @param[in] aHandler The handler on MeshCoP TXT changes. - * */ void SetUpdateMeshCopTxtHandler(UpdateMeshCopTxtHandler aHandler) { @@ -249,7 +250,6 @@ class ThreadHelper * This method handles MeshCoP TXT updates done by UpdateVendorMeshCopTxtEntries D-Bus API. * * @param[in] aUpdate The key-value pairs to be updated in the TXT record. - * */ void OnUpdateMeshCopTxt(std::map> aUpdate); #endif @@ -277,10 +277,27 @@ class ThreadHelper * * @param[in] aAction The action OpenThread performs. * @param[in] aError The action result. - * */ static void LogOpenThreadResult(const char *aAction, otError aError); + /** + * This method validates and updates a pending dataset do Thread network migration. + * + * This method validates that: + * 1. the given dataset doesn't contain a meshcop Pending Timestamp TLV or a meshcop Delay Timer TLV. + * 2. the given dataset has sufficient space to append a Pending Timestamp TLV and a Delay Timer TLV. + * + * If it's valid, the method will append a meshcop Pending Timestamp TLV with value being the current unix + * timestamp and a meshcop Delay Timer TLV with value being @p aDelayMilli. + * + * @param[in/out] aDatasetTlvs The dataset to validate and process in TLVs format. + * @param[in] aDelayMilli The delay time for migration in milliseconds. + * + * @retval OT_ERROR_NONE Dataset is valid to do Thread network migration. + * @retval OT_ERROR_INVALID_ARGS Dataset is invalid to do Thread network migration. + */ + static otError ProcessDatasetForMigration(otOperationalDatasetTlvs &aDatasetTlvs, uint32_t aDelayMilli); + private: static void ActiveScanHandler(otActiveScanResult *aResult, void *aThreadHelper); void ActiveScanHandler(otActiveScanResult *aResult); @@ -302,15 +319,23 @@ class ThreadHelper void ActiveDatasetChangedCallback(void); +#if OTBR_ENABLE_DHCP6_PD + static void BorderRoutingDhcp6PdCallback(otBorderRoutingDhcp6PdState aState, void *aThreadHelper); + void BorderRoutingDhcp6PdCallback(otBorderRoutingDhcp6PdState aState); +#endif #if OTBR_ENABLE_TELEMETRY_DATA_API #if OTBR_ENABLE_BORDER_ROUTING - void RetrieveExternalRouteInfo(threadnetwork::TelemetryData::ExternalRoutes *aExternalRouteInfo); + void RetrieveInfraLinkInfo(threadnetwork::TelemetryData::InfraLinkInfo &aInfraLinkInfo); + void RetrieveExternalRouteInfo(threadnetwork::TelemetryData::ExternalRoutes &aExternalRouteInfo); #endif #if OTBR_ENABLE_DHCP6_PD void RetrievePdInfo(threadnetwork::TelemetryData::WpanBorderRouter *aWpanBorderRouter); void RetrieveHashedPdPrefix(std::string *aHashedPdPrefix); void RetrievePdProcessedRaInfo(threadnetwork::TelemetryData::PdProcessedRaInfo *aPdProcessedRaInfo); #endif +#if OTBR_ENABLE_BORDER_AGENT + void RetrieveBorderAgentInfo(threadnetwork::TelemetryData::BorderAgentInfo *aBorderAgentInfo); +#endif #endif // OTBR_ENABLE_TELEMETRY_DATA_API otInstance *mInstance; @@ -339,6 +364,10 @@ class ThreadHelper std::random_device mRandomDevice; +#if OTBR_ENABLE_DHCP6_PD + Dhcp6PdStateCallback mDhcp6PdCallback; +#endif + #if OTBR_ENABLE_DBUS_SERVER UpdateMeshCopTxtHandler mUpdateMeshCopTxtHandler; #endif diff --git a/src/web/main.cpp b/src/web/main.cpp index 922038d88cd..6db9e8b8a7a 100644 --- a/src/web/main.cpp +++ b/src/web/main.cpp @@ -76,9 +76,10 @@ int main(int argc, char **argv) otbrLogLevel logLevel = OTBR_LOG_INFO; int ret = 0; int opt; - uint16_t port = OT_HTTP_PORT; + uint16_t port = OT_HTTP_PORT; + bool syslogDisable = false; - while ((opt = getopt(argc, argv, "d:I:p:va:")) != -1) + while ((opt = getopt(argc, argv, "d:I:p:va:s")) != -1) { switch (opt) { @@ -103,6 +104,10 @@ int main(int argc, char **argv) ExitNow(); break; + case 's': + syslogDisable = true; + break; + default: fprintf(stderr, "Usage: %s [-d DEBUG_LEVEL] [-I interfaceName] [-p port] [-a listenAddress] [-v]\n", argv[0]); @@ -111,7 +116,7 @@ int main(int argc, char **argv) } } - otbrLogInit(argv[0], logLevel, true, false); + otbrLogInit(argv[0], logLevel, true, syslogDisable); otbrLogInfo("Running %s", OTBR_PACKAGE_VERSION); if (interfaceName == nullptr) diff --git a/src/web/web-service/ot_client.hpp b/src/web/web-service/ot_client.hpp index c1ba5b984d9..103de9396b1 100644 --- a/src/web/web-service/ot_client.hpp +++ b/src/web/web-service/ot_client.hpp @@ -62,7 +62,6 @@ struct WpanNetworkInfo /** * This class implements functionality of OpenThread client. - * */ class OpenThreadClient { @@ -71,13 +70,11 @@ class OpenThreadClient * This constructor creates an OpenThread client. * * @param[in] aNetifName The Thread network interface name. - * */ OpenThreadClient(const char *aNetifName); /** * This destructor destories an OpenThread client. - * */ ~OpenThreadClient(void); @@ -86,7 +83,6 @@ class OpenThreadClient * * @retval TRUE Successfully connected to the daemon. * @retval FALSE Failed to connected to the daemon. - * */ bool Connect(void); @@ -97,7 +93,6 @@ class OpenThreadClient * @param[in] ... C style format arguments. * * @returns A pointer to the output if succeeded, otherwise nullptr. - * */ char *Execute(const char *aFormat, ...); @@ -108,7 +103,6 @@ class OpenThreadClient * @param[in] aTimeout Timeout for the read, in ms. * * @returns A pointer to the output if the expected response is found, otherwise nullptr. - * */ char *Read(const char *aResponse, int aTimeout); @@ -119,13 +113,11 @@ class OpenThreadClient * @param[in] aLength Number of entries in @p aNetworks. * * @returns Number of entries found. 0 if none found. - * */ int Scan(WpanNetworkInfo *aNetworks, int aLength); /** * This method performs factory reset. - * */ bool FactoryReset(void); diff --git a/src/web/web-service/web_server.hpp b/src/web/web-service/web_server.hpp index f54761e20bf..4520e41d037 100644 --- a/src/web/web-service/web_server.hpp +++ b/src/web/web-service/web_server.hpp @@ -61,20 +61,17 @@ typedef SimpleWeb::Server HttpServer; /** * This class implements the http server. - * */ class WebServer { public: /** * This method is constructor to initialize the WebServer. - * */ WebServer(void); /** * This method is destructor to free the WebServer. - * */ ~WebServer(void); @@ -84,13 +81,11 @@ class WebServer * @param[in] aIfName The pointer to the Thread interface name. * @param[in] aListenAddr The http server listen address, can be nullptr for any address. * @param[in] aPort The port of http server. - * */ void StartWebServer(const char *aIfName, const char *aListenAddr, uint16_t aPort); /** * This method stops the Web Server. - * */ void StopWebServer(void); diff --git a/src/web/web-service/wpan_service.hpp b/src/web/web-service/wpan_service.hpp index c27107be8ad..aa9b286a171 100644 --- a/src/web/web-service/wpan_service.hpp +++ b/src/web/web-service/wpan_service.hpp @@ -52,7 +52,6 @@ /** * WPAN parameter constants - * */ #define OT_EXTENDED_PANID_LENGTH 8 @@ -68,7 +67,6 @@ namespace Web { /** * This class provides web service to manage WPAN. - * */ class WpanService { @@ -77,7 +75,6 @@ class WpanService * This method handles http request to get information to generate QR code. * * @returns The string to the http response of getting QR code. - * */ std::string HandleGetQRCodeRequest(void); @@ -87,7 +84,6 @@ class WpanService * @param[in] aJoinRequest A reference to the http request of joining network. * * @returns The string to the http response of joining network. - * */ std::string HandleJoinNetworkRequest(const std::string &aJoinRequest); @@ -97,7 +93,6 @@ class WpanService * @param[in] aFormRequest A reference to the http request of forming network. * * @returns The string to the http response of forming network. - * */ std::string HandleFormNetworkRequest(const std::string &aFormRequest); @@ -107,7 +102,6 @@ class WpanService * @param[in] aAddPrefixRequest A reference to the http request of adding on-mesh prefix. * * @returns The string to the http response of adding on-mesh prefix. - * */ std::string HandleAddPrefixRequest(const std::string &aAddPrefixRequest); @@ -117,7 +111,6 @@ class WpanService * @param[in] aDeleteRequest A reference to the http request of deleting on-mesh prefix. * * @returns The string to the http response of deleting on-mesh prefix. - * */ std::string HandleDeletePrefixRequest(const std::string &aDeleteRequest); @@ -125,7 +118,6 @@ class WpanService * This method handles http request to get netowrk status. * * @returns The string to the http response of getting status. - * */ std::string HandleStatusRequest(void); @@ -133,7 +125,6 @@ class WpanService * This method handles http request to get available networks. * * @returns The string to the http response of getting available networks. - * */ std::string HandleAvailableNetworkRequest(void); @@ -141,7 +132,6 @@ class WpanService * This method handles http request to commission device * * @returns The string to the http response of commissioning - * */ std::string HandleCommission(const std::string &aCommissionRequest); @@ -149,7 +139,6 @@ class WpanService * This method sets the Thread interface name. * * @param[in] aIfName The pointer to the Thread interface name. - * */ void SetInterfaceName(const char *aIfName) { @@ -166,7 +155,6 @@ class WpanService * @retval kWpanStatus_OK Successfully started the Thread service. * @retval kWpanStatus_Offline Not started the Thread service. * @retval kWpanStatus_Down The Thread service was down. - * */ int GetWpanServiceStatus(std::string &aNetworkName, std::string &aExtPanId) const; @@ -177,7 +165,6 @@ class WpanService * @param[in] aNetworkPassword Network password * * @returns The string to the http response of getting available networks. - * */ std::string CommissionDevice(const char *aPskd, const char *aNetworkPassword); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ae8f322f767..395e4c460da 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -39,4 +39,4 @@ if(OTBR_REST) endif() add_subdirectory(tools) -add_subdirectory(unit) +add_subdirectory(gtest) diff --git a/tests/dbus/test_dbus_client.cpp b/tests/dbus/test_dbus_client.cpp index 2cb6dea64e1..eef54162058 100644 --- a/tests/dbus/test_dbus_client.cpp +++ b/tests/dbus/test_dbus_client.cpp @@ -261,6 +261,38 @@ void CheckNat64(ThreadApiDBus *aApi) #endif } +void CheckEphemeralKey(ThreadApiDBus *aApi) +{ + bool enabled; + + TEST_ASSERT(aApi->SetEphemeralKeyEnabled(false) == OTBR_ERROR_NONE); + TEST_ASSERT(aApi->GetEphemeralKeyEnabled(enabled) == OTBR_ERROR_NONE); + TEST_ASSERT(enabled == false); + TEST_ASSERT(aApi->SetEphemeralKeyEnabled(true) == OTBR_ERROR_NONE); + TEST_ASSERT(aApi->GetEphemeralKeyEnabled(enabled) == OTBR_ERROR_NONE); + TEST_ASSERT(enabled == true); +} + +void CheckBorderAgentInfo(const threadnetwork::TelemetryData_BorderAgentInfo &aBorderAgentInfo) +{ + TEST_ASSERT(aBorderAgentInfo.border_agent_counters().epskc_activations() == 0); + TEST_ASSERT(aBorderAgentInfo.border_agent_counters().epskc_deactivation_clears() == 0); + TEST_ASSERT(aBorderAgentInfo.border_agent_counters().epskc_deactivation_timeouts() == 0); + TEST_ASSERT(aBorderAgentInfo.border_agent_counters().epskc_deactivation_max_attempts() == 0); + TEST_ASSERT(aBorderAgentInfo.border_agent_counters().epskc_deactivation_disconnects() == 0); + TEST_ASSERT(aBorderAgentInfo.border_agent_counters().epskc_invalid_ba_state_errors() == 0); + TEST_ASSERT(aBorderAgentInfo.border_agent_counters().epskc_invalid_args_errors() == 0); + TEST_ASSERT(aBorderAgentInfo.border_agent_counters().epskc_start_secure_session_errors() == 0); + TEST_ASSERT(aBorderAgentInfo.border_agent_counters().epskc_secure_session_successes() == 0); + TEST_ASSERT(aBorderAgentInfo.border_agent_counters().epskc_secure_session_failures() == 0); + TEST_ASSERT(aBorderAgentInfo.border_agent_counters().epskc_commissioner_petitions() == 0); + TEST_ASSERT(aBorderAgentInfo.border_agent_counters().pskc_secure_session_successes() == 0); + TEST_ASSERT(aBorderAgentInfo.border_agent_counters().pskc_secure_session_failures() == 0); + TEST_ASSERT(aBorderAgentInfo.border_agent_counters().pskc_commissioner_petitions() == 0); + TEST_ASSERT(aBorderAgentInfo.border_agent_counters().mgmt_active_get_reqs() == 0); + TEST_ASSERT(aBorderAgentInfo.border_agent_counters().mgmt_pending_get_reqs() == 0); +} + #if OTBR_ENABLE_TELEMETRY_DATA_API void CheckTelemetryData(ThreadApiDBus *aApi) { @@ -289,6 +321,7 @@ void CheckTelemetryData(ThreadApiDBus *aApi) 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.wpan_topo_full().peer_br_count() == 0); TEST_ASSERT(telemetryData.topo_entries_size() == 1); TEST_ASSERT(telemetryData.topo_entries(0).rloc16() < 0xffff); TEST_ASSERT(telemetryData.wpan_border_router().border_routing_counters().rs_tx_failure() == 0); @@ -313,6 +346,7 @@ void CheckTelemetryData(ThreadApiDBus *aApi) TEST_ASSERT(telemetryData.wpan_border_router().infra_link_info().link_local_address_count() == 0); TEST_ASSERT(telemetryData.wpan_border_router().infra_link_info().unique_local_address_count() == 0); TEST_ASSERT(telemetryData.wpan_border_router().infra_link_info().global_unicast_address_count() == 0); + TEST_ASSERT(telemetryData.wpan_border_router().infra_link_info().peer_br_count() == 0); TEST_ASSERT(telemetryData.wpan_border_router().external_route_info().has_default_route_added() == false); TEST_ASSERT(telemetryData.wpan_border_router().external_route_info().has_ula_route_added() == false); TEST_ASSERT(telemetryData.wpan_border_router().external_route_info().has_others_route_added() == false); @@ -335,6 +369,9 @@ void CheckTelemetryData(ThreadApiDBus *aApi) #if OTBR_ENABLE_LINK_METRICS_TELEMETRY TEST_ASSERT(telemetryData.low_power_metrics().link_metrics_entries_size() >= 0); #endif +#if OTBR_ENABLE_BORDER_AGENT + CheckBorderAgentInfo(telemetryData.wpan_border_router().border_agent_info()); +#endif } #endif @@ -468,6 +505,7 @@ int main() CheckMdnsInfo(api.get()); CheckDnssdCounters(api.get()); CheckNat64(api.get()); + CheckEphemeralKey(api.get()); #if OTBR_ENABLE_TELEMETRY_DATA_API CheckTelemetryData(api.get()); #endif diff --git a/tests/gtest/CMakeLists.txt b/tests/gtest/CMakeLists.txt new file mode 100644 index 00000000000..f9674ed6946 --- /dev/null +++ b/tests/gtest/CMakeLists.txt @@ -0,0 +1,84 @@ +# +# Copyright (c) 2020, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +cmake_minimum_required(VERSION 3.14) +project(openthread-br-gtest) + +# GoogleTest requires at least C++14 +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +include(GoogleTest) + +add_executable(otbr-gtest-unit + test_async_task.cpp + test_common_types.cpp + test_dns_utils.cpp + test_logging.cpp + test_once_callback.cpp + test_pskc.cpp + test_task_runner.cpp +) +target_link_libraries(otbr-gtest-unit + mbedtls + otbr-common + otbr-ncp + otbr-utils + GTest::gmock_main +) +gtest_discover_tests(otbr-gtest-unit) + +if(OTBR_MDNS) + add_executable(otbr-gtest-mdns-subscribe + test_mdns_subscribe.cpp + ) + target_link_libraries(otbr-gtest-mdns-subscribe + otbr-common + otbr-mdns + GTest::gmock_main + ) + gtest_discover_tests(otbr-gtest-mdns-subscribe) +endif() + +add_executable(otbr-posix-gtest-unit + test_netif.cpp +) +target_link_libraries(otbr-posix-gtest-unit + otbr-posix + GTest::gmock_main +) +gtest_discover_tests(otbr-posix-gtest-unit PROPERTIES LABELS "sudo") diff --git a/tests/gtest/test_async_task.cpp b/tests/gtest/test_async_task.cpp new file mode 100644 index 00000000000..46f3649d0a4 --- /dev/null +++ b/tests/gtest/test_async_task.cpp @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2024, 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 + +#include +#include + +#include + +#include "common/code_utils.hpp" +#include "ncp/async_task.hpp" + +using otbr::Ncp::AsyncTask; +using otbr::Ncp::AsyncTaskPtr; + +TEST(AsyncTask, TestOneStep) +{ + AsyncTaskPtr task; + AsyncTaskPtr step1; + int resultHandlerCalledTimes = 0; + int stepCount = 0; + + auto errorHandler = [&resultHandlerCalledTimes](otError aError, const std::string &aErrorInfo) { + OTBR_UNUSED_VARIABLE(aError); + OTBR_UNUSED_VARIABLE(aErrorInfo); + + resultHandlerCalledTimes++; + }; + + task = std::make_shared(errorHandler); + task->First([&stepCount, &step1](AsyncTaskPtr aNext) { + step1 = std::move(aNext); + stepCount++; + }); + task->Run(); + + step1->SetResult(OT_ERROR_NONE, "Success"); + + EXPECT_EQ(resultHandlerCalledTimes, 1); + EXPECT_EQ(stepCount, 1); +} + +TEST(AsyncTask, TestNoResultReturned) +{ + AsyncTaskPtr task; + AsyncTaskPtr step1; + AsyncTaskPtr step2; + AsyncTaskPtr step3; + + int resultHandlerCalledTimes = 0; + int stepCount = 0; + otError error = OT_ERROR_NONE; + + auto errorHandler = [&resultHandlerCalledTimes, &error](otError aError, const std::string &aErrorInfo) { + OTBR_UNUSED_VARIABLE(aErrorInfo); + + resultHandlerCalledTimes++; + error = aError; + }; + + task = std::make_shared(errorHandler); + task->First([&stepCount, &step1](AsyncTaskPtr aNext) { + step1 = std::move(aNext); + stepCount++; + }) + ->Then([&stepCount, &step2](AsyncTaskPtr aNext) { + step2 = std::move(aNext); + stepCount++; + }) + ->Then([&stepCount, &step3](AsyncTaskPtr aNext) { + step3 = std::move(aNext); + stepCount++; + }); + task->Run(); + + // Asyn task ends without calling 'SetResult'. + step1 = nullptr; + task = nullptr; + + EXPECT_EQ(resultHandlerCalledTimes, 1); + EXPECT_EQ(stepCount, 1); + EXPECT_EQ(error, OT_ERROR_FAILED); +} + +TEST(AsyncTask, TestMultipleStepsSuccess) +{ + AsyncTaskPtr task; + AsyncTaskPtr step1; + AsyncTaskPtr step2; + AsyncTaskPtr step3; + + int resultHandlerCalledTimes = 0; + int stepCount = 0; + otError error = OT_ERROR_NONE; + + auto errorHandler = [&resultHandlerCalledTimes, &error](otError aError, const std::string &aErrorInfo) { + OTBR_UNUSED_VARIABLE(aErrorInfo); + + resultHandlerCalledTimes++; + error = aError; + }; + + task = std::make_shared(errorHandler); + task->First([&stepCount, &step1](AsyncTaskPtr aNext) { + step1 = std::move(aNext); + stepCount++; + }) + ->Then([&stepCount, &step2](AsyncTaskPtr aNext) { + step2 = std::move(aNext); + stepCount++; + }) + ->Then([&stepCount, &step3](AsyncTaskPtr aNext) { + step3 = std::move(aNext); + stepCount++; + }); + task->Run(); + + EXPECT_EQ(stepCount, 1); + step1->SetResult(OT_ERROR_NONE, ""); + EXPECT_EQ(resultHandlerCalledTimes, 0); + + EXPECT_EQ(stepCount, 2); + step2->SetResult(OT_ERROR_NONE, ""); + EXPECT_EQ(resultHandlerCalledTimes, 0); + + EXPECT_EQ(stepCount, 3); + error = OT_ERROR_GENERIC; + step3->SetResult(OT_ERROR_NONE, ""); + EXPECT_EQ(resultHandlerCalledTimes, 1); + EXPECT_EQ(error, OT_ERROR_NONE); +} + +TEST(AsyncTask, TestMultipleStepsFailedHalfWay) +{ + AsyncTaskPtr task; + AsyncTaskPtr step1; + AsyncTaskPtr step2; + AsyncTaskPtr step3; + + int resultHandlerCalledTimes = 0; + int stepCount = 0; + otError error = OT_ERROR_NONE; + + auto errorHandler = [&resultHandlerCalledTimes, &error](otError aError, const std::string &aErrorInfo) { + OTBR_UNUSED_VARIABLE(aErrorInfo); + + resultHandlerCalledTimes++; + error = aError; + }; + + task = std::make_shared(errorHandler); + task->First([&stepCount, &step1](AsyncTaskPtr aNext) { + step1 = std::move(aNext); + stepCount++; + }) + ->Then([&stepCount, &step2](AsyncTaskPtr aNext) { + step2 = std::move(aNext); + stepCount++; + }) + ->Then([&stepCount, &step3](AsyncTaskPtr aNext) { + step3 = std::move(aNext); + stepCount++; + }); + task->Run(); + + EXPECT_EQ(stepCount, 1); + step1->SetResult(OT_ERROR_NONE, ""); + EXPECT_EQ(resultHandlerCalledTimes, 0); + + EXPECT_EQ(stepCount, 2); + step2->SetResult(OT_ERROR_BUSY, ""); + EXPECT_EQ(resultHandlerCalledTimes, 1); + EXPECT_EQ(error, OT_ERROR_BUSY); +} diff --git a/tests/unit/test_common_types.cpp b/tests/gtest/test_common_types.cpp similarity index 53% rename from tests/unit/test_common_types.cpp rename to tests/gtest/test_common_types.cpp index 7ddac226f75..32b2c5a2177 100644 --- a/tests/unit/test_common_types.cpp +++ b/tests/gtest/test_common_types.cpp @@ -26,43 +26,36 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include +#include #include "common/types.hpp" //------------------------------------------------------------- // Test for Ip6Address // TODO: Add Ip6Address tests -TEST_GROUP(Ip6Address){}; - -TEST(Ip6Address, NULL) -{ - TEST_EXIT; -} //------------------------------------------------------------- // Test for Ip6Prefix -TEST_GROUP(Ip6Prefix){}; TEST(Ip6Prefix, ConstructorWithAddressAndLength) { using otbr::Ip6Prefix; Ip6Prefix prefix1("::", 0); - STRCMP_EQUAL("::/0", prefix1.ToString().c_str()); - CHECK_EQUAL(0, prefix1.mLength); + EXPECT_STREQ(prefix1.ToString().c_str(), "::/0"); + EXPECT_EQ(prefix1.mLength, 0); Ip6Prefix prefix2("fc00::", 7); - STRCMP_EQUAL("fc00::/7", prefix2.ToString().c_str()); - CHECK_EQUAL(7, prefix2.mLength); + EXPECT_STREQ(prefix2.ToString().c_str(), "fc00::/7"); + EXPECT_EQ(prefix2.mLength, 7); Ip6Prefix prefix3("2001:db8::", 64); - STRCMP_EQUAL("2001:db8::/64", prefix3.ToString().c_str()); - CHECK_EQUAL(64, prefix3.mLength); + EXPECT_STREQ(prefix3.ToString().c_str(), "2001:db8::/64"); + EXPECT_EQ(prefix3.mLength, 64); Ip6Prefix prefix4("2001:db8::1", 128); - STRCMP_EQUAL("2001:db8::1/128", prefix4.ToString().c_str()); - CHECK_EQUAL(128, prefix4.mLength); + EXPECT_STREQ(prefix4.ToString().c_str(), "2001:db8::1/128"); + EXPECT_EQ(prefix4.mLength, 128); } TEST(Ip6Prefix, EqualityOperator) @@ -70,37 +63,37 @@ TEST(Ip6Prefix, EqualityOperator) using otbr::Ip6Prefix; // same prefix and length - CHECK(Ip6Prefix("::", 0) == Ip6Prefix("::", 0)); - CHECK(Ip6Prefix("fc00::", 0) == Ip6Prefix("fc00::", 0)); - CHECK(Ip6Prefix("2001:db8::", 64) == Ip6Prefix("2001:db8::", 64)); + EXPECT_EQ(Ip6Prefix("::", 0), Ip6Prefix("::", 0)); + EXPECT_EQ(Ip6Prefix("fc00::", 0), Ip6Prefix("fc00::", 0)); + EXPECT_EQ(Ip6Prefix("2001:db8::", 64), Ip6Prefix("2001:db8::", 64)); // same prefix, different length - CHECK_FALSE(Ip6Prefix("::", 0) == Ip6Prefix("::", 7)); - CHECK_FALSE(Ip6Prefix("fc00::", 0) == Ip6Prefix("fc00::", 7)); - CHECK_FALSE(Ip6Prefix("fc00::", 7) == Ip6Prefix("fc00::", 8)); - CHECK_FALSE(Ip6Prefix("2001:db8::", 64) == Ip6Prefix("2001:db8::", 32)); + EXPECT_NE(Ip6Prefix("::", 0), Ip6Prefix("::", 7)); + EXPECT_NE(Ip6Prefix("fc00::", 0), Ip6Prefix("fc00::", 7)); + EXPECT_NE(Ip6Prefix("fc00::", 7), Ip6Prefix("fc00::", 8)); + EXPECT_NE(Ip6Prefix("2001:db8::", 64), Ip6Prefix("2001:db8::", 32)); // different prefix object, same length - CHECK(Ip6Prefix("::", 0) == Ip6Prefix("::1", 0)); - CHECK(Ip6Prefix("::", 0) == Ip6Prefix("2001::", 0)); - CHECK(Ip6Prefix("::", 0) == Ip6Prefix("2001:db8::1", 0)); - CHECK(Ip6Prefix("fc00::", 7) == Ip6Prefix("fd00::", 7)); - CHECK(Ip6Prefix("fc00::", 8) == Ip6Prefix("fc00:1234::", 8)); - CHECK(Ip6Prefix("2001:db8::", 32) == Ip6Prefix("2001:db8:abcd::", 32)); - CHECK(Ip6Prefix("2001:db8:0:1::", 63) == Ip6Prefix("2001:db8::", 63)); - CHECK(Ip6Prefix("2001:db8::", 64) == Ip6Prefix("2001:db8::1", 64)); - CHECK(Ip6Prefix("2001:db8::3", 127) == Ip6Prefix("2001:db8::2", 127)); - - CHECK_FALSE(Ip6Prefix("fc00::", 7) == Ip6Prefix("fe00::", 7)); - CHECK_FALSE(Ip6Prefix("fc00::", 16) == Ip6Prefix("fc01::", 16)); - CHECK_FALSE(Ip6Prefix("fc00::", 32) == Ip6Prefix("fc00:1::", 32)); - CHECK_FALSE(Ip6Prefix("2001:db8:0:1::", 64) == Ip6Prefix("2001:db8::", 64)); - CHECK_FALSE(Ip6Prefix("2001:db8::1", 128) == Ip6Prefix("2001:db8::", 128)); + EXPECT_EQ(Ip6Prefix("::", 0), Ip6Prefix("::1", 0)); + EXPECT_EQ(Ip6Prefix("::", 0), Ip6Prefix("2001::", 0)); + EXPECT_EQ(Ip6Prefix("::", 0), Ip6Prefix("2001:db8::1", 0)); + EXPECT_EQ(Ip6Prefix("fc00::", 7), Ip6Prefix("fd00::", 7)); + EXPECT_EQ(Ip6Prefix("fc00::", 8), Ip6Prefix("fc00:1234::", 8)); + EXPECT_EQ(Ip6Prefix("2001:db8::", 32), Ip6Prefix("2001:db8:abcd::", 32)); + EXPECT_EQ(Ip6Prefix("2001:db8:0:1::", 63), Ip6Prefix("2001:db8::", 63)); + EXPECT_EQ(Ip6Prefix("2001:db8::", 64), Ip6Prefix("2001:db8::1", 64)); + EXPECT_EQ(Ip6Prefix("2001:db8::3", 127), Ip6Prefix("2001:db8::2", 127)); + + EXPECT_NE(Ip6Prefix("fc00::", 7), Ip6Prefix("fe00::", 7)); + EXPECT_NE(Ip6Prefix("fc00::", 16), Ip6Prefix("fc01::", 16)); + EXPECT_NE(Ip6Prefix("fc00::", 32), Ip6Prefix("fc00:1::", 32)); + EXPECT_NE(Ip6Prefix("2001:db8:0:1::", 64), Ip6Prefix("2001:db8::", 64)); + EXPECT_NE(Ip6Prefix("2001:db8::1", 128), Ip6Prefix("2001:db8::", 128)); // different prefix object, different length - CHECK_FALSE(Ip6Prefix("::", 0) == Ip6Prefix("2001::", 7)); - CHECK_FALSE(Ip6Prefix("fc00::", 7) == Ip6Prefix("fd00::", 8)); - CHECK_FALSE(Ip6Prefix("2001:db8:0:1::", 63) == Ip6Prefix("2001:db8::", 64)); + EXPECT_NE(Ip6Prefix("::", 0), Ip6Prefix("2001::", 7)); + EXPECT_NE(Ip6Prefix("fc00::", 7), Ip6Prefix("fd00::", 8)); + EXPECT_NE(Ip6Prefix("2001:db8:0:1::", 63), Ip6Prefix("2001:db8::", 64)); } // TODO: add more test cases for otbr::Ip6Prefix @@ -108,9 +101,3 @@ TEST(Ip6Prefix, EqualityOperator) //------------------------------------------------------------- // Test for MacAddress // TODO: Add MacAddress tests -TEST_GROUP(MacAddress){}; - -TEST(MacAddress, NULL) -{ - TEST_EXIT; -} diff --git a/tests/unit/test_dbus_message.cpp b/tests/gtest/test_dbus_message.cpp similarity index 83% rename from tests/unit/test_dbus_message.cpp rename to tests/gtest/test_dbus_message.cpp index 05079e960de..f1afffe999d 100644 --- a/tests/unit/test_dbus_message.cpp +++ b/tests/gtest/test_dbus_message.cpp @@ -26,12 +26,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include "dbus/common/dbus_message_helper.hpp" -#include - using std::array; using std::string; using std::tuple; @@ -168,12 +167,12 @@ TEST(DBusMessage, TestVectorMessage) tuple, vector, vector, vector, vector, vector, vector> getVals({}, {}, {}, {}, {}, {}, {}); - CHECK(msg != nullptr); + EXPECT_NE(msg, nullptr); - CHECK(TupleToDBusMessage(*msg, setVals) == OTBR_ERROR_NONE); - CHECK(DBusMessageToTuple(*msg, getVals) == OTBR_ERROR_NONE); + EXPECT_EQ(TupleToDBusMessage(*msg, setVals), OTBR_ERROR_NONE); + EXPECT_EQ(DBusMessageToTuple(*msg, getVals), OTBR_ERROR_NONE); - CHECK(setVals == getVals); + EXPECT_EQ(setVals, getVals); dbus_message_unref(msg); } @@ -184,12 +183,12 @@ TEST(DBusMessage, TestArrayMessage) tuple> setVals({1, 2, 3, 4}); tuple> getVals({0, 0, 0, 0}); - CHECK(msg != nullptr); + EXPECT_NE(msg, nullptr); - CHECK(TupleToDBusMessage(*msg, setVals) == OTBR_ERROR_NONE); - CHECK(DBusMessageToTuple(*msg, getVals) == OTBR_ERROR_NONE); + EXPECT_EQ(TupleToDBusMessage(*msg, setVals), OTBR_ERROR_NONE); + EXPECT_EQ(DBusMessageToTuple(*msg, getVals), OTBR_ERROR_NONE); - CHECK(setVals == getVals); + EXPECT_EQ(setVals, getVals); dbus_message_unref(msg); } @@ -204,12 +203,12 @@ TEST(DBusMessage, TestNumberMessage) std::make_tuple(0, 0, 0, 0, false, 0, 0, 0); - CHECK(msg != nullptr); + EXPECT_NE(msg, nullptr); - CHECK(TupleToDBusMessage(*msg, setVals) == OTBR_ERROR_NONE); - CHECK(DBusMessageToTuple(*msg, getVals) == OTBR_ERROR_NONE); + EXPECT_EQ(TupleToDBusMessage(*msg, setVals), OTBR_ERROR_NONE); + EXPECT_EQ(DBusMessageToTuple(*msg, getVals), OTBR_ERROR_NONE); - CHECK(setVals == getVals); + EXPECT_EQ(setVals, getVals); dbus_message_unref(msg); } @@ -221,12 +220,12 @@ TEST(DBusMessage, TestStructMessage) 0x03, {0x04, 0x05}, {"hello", "world"}, {{1, 0xf0a, "test1"}, {2, 0xf0b, "test2"}}); tuple, vector, vector> getVals(0, {}, {}, {}); - CHECK(msg != nullptr); + EXPECT_NE(msg, nullptr); - CHECK(TupleToDBusMessage(*msg, setVals) == OTBR_ERROR_NONE); - CHECK(DBusMessageToTuple(*msg, getVals) == OTBR_ERROR_NONE); + EXPECT_EQ(TupleToDBusMessage(*msg, setVals), OTBR_ERROR_NONE); + EXPECT_EQ(DBusMessageToTuple(*msg, getVals), OTBR_ERROR_NONE); - CHECK(setVals == getVals); + EXPECT_EQ(setVals, getVals); dbus_message_unref(msg); } @@ -237,12 +236,12 @@ TEST(DBusMessage, TestOtbrChannelQuality) tuple> setVals({{1, 2}}); tuple> getVals; - CHECK(msg != nullptr); + EXPECT_NE(msg, nullptr); - CHECK(TupleToDBusMessage(*msg, setVals) == OTBR_ERROR_NONE); - CHECK(DBusMessageToTuple(*msg, getVals) == OTBR_ERROR_NONE); + EXPECT_EQ(TupleToDBusMessage(*msg, setVals), OTBR_ERROR_NONE); + EXPECT_EQ(DBusMessageToTuple(*msg, getVals), OTBR_ERROR_NONE); - CHECK(std::get<0>(setVals)[0] == std::get<0>(getVals)[0]); + EXPECT_EQ(std::get<0>(setVals)[0], std::get<0>(getVals)[0]); dbus_message_unref(msg); } @@ -253,12 +252,12 @@ TEST(DBusMessage, TestOtbrChildInfo) tuple> setVals({{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, true, false, true, false}}); tuple> getVals; - CHECK(msg != nullptr); + EXPECT_NE(msg, nullptr); - CHECK(TupleToDBusMessage(*msg, setVals) == OTBR_ERROR_NONE); - CHECK(DBusMessageToTuple(*msg, getVals) == OTBR_ERROR_NONE); + EXPECT_EQ(TupleToDBusMessage(*msg, setVals), OTBR_ERROR_NONE); + EXPECT_EQ(DBusMessageToTuple(*msg, getVals), OTBR_ERROR_NONE); - CHECK(std::get<0>(setVals)[0] == std::get<0>(getVals)[0]); + EXPECT_EQ(std::get<0>(setVals)[0], std::get<0>(getVals)[0]); dbus_message_unref(msg); } @@ -270,12 +269,12 @@ TEST(DBusMessage, TestOtbrNeighborInfo) {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, true, false, true, false}}); tuple> getVals; - CHECK(msg != nullptr); + EXPECT_NE(msg, nullptr); - CHECK(TupleToDBusMessage(*msg, setVals) == OTBR_ERROR_NONE); - CHECK(DBusMessageToTuple(*msg, getVals) == OTBR_ERROR_NONE); + EXPECT_EQ(TupleToDBusMessage(*msg, setVals), OTBR_ERROR_NONE); + EXPECT_EQ(DBusMessageToTuple(*msg, getVals), OTBR_ERROR_NONE); - CHECK(std::get<0>(setVals)[0] == std::get<0>(getVals)[0]); + EXPECT_EQ(std::get<0>(setVals)[0], std::get<0>(getVals)[0]); dbus_message_unref(msg); } @@ -286,12 +285,12 @@ TEST(DBusMessage, TestOtbrLeaderData) tuple> setVals({{1, 2, 3, 4, 5}}); tuple> getVals; - CHECK(msg != nullptr); + EXPECT_NE(msg, nullptr); - CHECK(TupleToDBusMessage(*msg, setVals) == OTBR_ERROR_NONE); - CHECK(DBusMessageToTuple(*msg, getVals) == OTBR_ERROR_NONE); + EXPECT_EQ(TupleToDBusMessage(*msg, setVals), OTBR_ERROR_NONE); + EXPECT_EQ(DBusMessageToTuple(*msg, getVals), OTBR_ERROR_NONE); - CHECK(std::get<0>(setVals)[0] == std::get<0>(getVals)[0]); + EXPECT_EQ(std::get<0>(setVals)[0], std::get<0>(getVals)[0]); dbus_message_unref(msg); } @@ -302,12 +301,12 @@ TEST(DBusMessage, TestOtbrActiveScanResults) tuple> setVals({{1, "a", 2, {3}, 4, 5, 6, 7, 8, 9, true, false}}); tuple> getVals; - CHECK(msg != nullptr); + EXPECT_NE(msg, nullptr); - CHECK(TupleToDBusMessage(*msg, setVals) == OTBR_ERROR_NONE); - CHECK(DBusMessageToTuple(*msg, getVals) == OTBR_ERROR_NONE); + EXPECT_EQ(TupleToDBusMessage(*msg, setVals), OTBR_ERROR_NONE); + EXPECT_EQ(DBusMessageToTuple(*msg, getVals), OTBR_ERROR_NONE); - CHECK(std::get<0>(setVals)[0] == std::get<0>(getVals)[0]); + EXPECT_EQ(std::get<0>(setVals)[0], std::get<0>(getVals)[0]); dbus_message_unref(msg); } @@ -320,12 +319,12 @@ TEST(DBusMessage, TestOtbrExternalRoute) true}}); tuple> getVals; - CHECK(msg != nullptr); + EXPECT_NE(msg, nullptr); - CHECK(TupleToDBusMessage(*msg, setVals) == OTBR_ERROR_NONE); - CHECK(DBusMessageToTuple(*msg, getVals) == OTBR_ERROR_NONE); + EXPECT_EQ(TupleToDBusMessage(*msg, setVals), OTBR_ERROR_NONE); + EXPECT_EQ(DBusMessageToTuple(*msg, getVals), OTBR_ERROR_NONE); - CHECK(std::get<0>(setVals)[0] == std::get<0>(getVals)[0]); + EXPECT_EQ(std::get<0>(setVals)[0], std::get<0>(getVals)[0]); dbus_message_unref(msg); } diff --git a/tests/unit/test_dns_utils.cpp b/tests/gtest/test_dns_utils.cpp similarity index 84% rename from tests/unit/test_dns_utils.cpp rename to tests/gtest/test_dns_utils.cpp index 55d3389c60b..411206e5633 100644 --- a/tests/unit/test_dns_utils.cpp +++ b/tests/gtest/test_dns_utils.cpp @@ -29,10 +29,7 @@ #include "common/dns_utils.hpp" #include - -#include - -TEST_GROUP(DnsUtils){}; +#include static void CheckSplitFullDnsName(const std::string &aFullName, bool aIsServiceInstance, @@ -49,23 +46,23 @@ static void CheckSplitFullDnsName(const std::string &aFullName, info = SplitFullDnsName(aFullName); - CHECK_EQUAL(aIsServiceInstance, info.IsServiceInstance()); - CHECK_EQUAL(aIsService, info.IsService()); - CHECK_EQUAL(aIsHost, info.IsHost()); - CHECK_EQUAL(aInstanceName, info.mInstanceName); - CHECK_EQUAL(aServiceName, info.mServiceName); - CHECK_EQUAL(aHostName, info.mHostName); - CHECK_EQUAL(aDomain, info.mDomain); + EXPECT_EQ(aIsServiceInstance, info.IsServiceInstance()); + EXPECT_EQ(aIsService, info.IsService()); + EXPECT_EQ(aIsHost, info.IsHost()); + EXPECT_EQ(aInstanceName, info.mInstanceName); + EXPECT_EQ(aServiceName, info.mServiceName); + EXPECT_EQ(aHostName, info.mHostName); + EXPECT_EQ(aDomain, info.mDomain); info = SplitFullDnsName(aFullName + "."); - CHECK_EQUAL(aIsServiceInstance, info.IsServiceInstance()); - CHECK_EQUAL(aIsService, info.IsService()); - CHECK_EQUAL(aIsHost, info.IsHost()); - CHECK_EQUAL(aInstanceName, info.mInstanceName); - CHECK_EQUAL(aServiceName, info.mServiceName); - CHECK_EQUAL(aHostName, info.mHostName); - CHECK_EQUAL(aDomain, info.mDomain); + EXPECT_EQ(aIsServiceInstance, info.IsServiceInstance()); + EXPECT_EQ(aIsService, info.IsService()); + EXPECT_EQ(aIsHost, info.IsHost()); + EXPECT_EQ(aInstanceName, info.mInstanceName); + EXPECT_EQ(aServiceName, info.mServiceName); + EXPECT_EQ(aHostName, info.mHostName); + EXPECT_EQ(aDomain, info.mDomain); } TEST(DnsUtils, TestSplitFullDnsName) diff --git a/tests/unit/test_logging.cpp b/tests/gtest/test_logging.cpp similarity index 94% rename from tests/unit/test_logging.cpp rename to tests/gtest/test_logging.cpp index c29970350ea..104990d8392 100644 --- a/tests/unit/test_logging.cpp +++ b/tests/gtest/test_logging.cpp @@ -28,15 +28,13 @@ #define OTBR_LOG_TAG "TEST" -#include - #include #include #include -#include "common/logging.hpp" +#include -TEST_GROUP(Logging){}; +#include "common/logging.hpp" TEST(Logging, TestLoggingHigherLevel) { @@ -50,7 +48,7 @@ TEST(Logging, TestLoggingHigherLevel) char cmd[128]; snprintf(cmd, sizeof(cmd), "grep '%s.*cool-higher' /var/log/syslog", ident); - CHECK(0 != system(cmd)); + EXPECT_NE(system(cmd), 0); } TEST(Logging, TestLoggingEqualLevel) @@ -66,7 +64,7 @@ TEST(Logging, TestLoggingEqualLevel) char cmd[128]; snprintf(cmd, sizeof(cmd), "grep '%s.*cool-equal' /var/log/syslog", ident); printf("CMD = %s\n", cmd); - CHECK(0 == system(cmd)); + EXPECT_EQ(system(cmd), 0); } TEST(Logging, TestLoggingEqualLevelNoSyslog) @@ -82,7 +80,7 @@ TEST(Logging, TestLoggingEqualLevelNoSyslog) char cmd[128]; snprintf(cmd, sizeof(cmd), "grep '%s.*cool-equal' /var/log/syslog", ident); printf("CMD = %s\n", cmd); - CHECK(0 != system(cmd)); + EXPECT_NE(system(cmd), 0); } TEST(Logging, TestLoggingLowerLevel) @@ -97,7 +95,7 @@ TEST(Logging, TestLoggingLowerLevel) sleep(0); snprintf(cmd, sizeof(cmd), "grep '%s.*cool-lower' /var/log/syslog", ident); - CHECK(0 == system(cmd)); + EXPECT_EQ(system(cmd), 0); } TEST(Logging, TestLoggingDump) @@ -121,12 +119,12 @@ TEST(Logging, TestLoggingDump) snprintf(cmd, sizeof(cmd), "grep '%s.*: foobar: 0000: 6f 6e 65 20 73 75 70 65 72 20 6c 6f 6e 67 20 73' /var/log/syslog", ident); - CHECK(0 == system(cmd)); + EXPECT_EQ(system(cmd), 0); snprintf(cmd, sizeof(cmd), "grep '%s.*: foobar: 0010: 74 72 69 6e 67 20 77 69 74 68 20 6c 6f 74 73 20' /var/log/syslog", ident); - CHECK(0 == system(cmd)); + EXPECT_EQ(system(cmd), 0); snprintf(cmd, sizeof(cmd), "grep '%s.*: foobar: 0020: 6f 66 20 74 65 78 74 00' /var/log/syslog", ident); - CHECK(0 == system(cmd)); + EXPECT_EQ(system(cmd), 0); } diff --git a/tests/gtest/test_mdns_mdnssd.cpp b/tests/gtest/test_mdns_mdnssd.cpp new file mode 100644 index 00000000000..db9bdb4549f --- /dev/null +++ b/tests/gtest/test_mdns_mdnssd.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "mdns/mdns_mdnssd.cpp" + +TEST(MdnsSd, TestDNSErrorToString) +{ + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_NoError), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_Unknown), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_NoSuchName), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_NoMemory), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_BadParam), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_BadReference), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_BadState), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_BadFlags), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_Unsupported), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_NotInitialized), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_AlreadyRegistered), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_NameConflict), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_Invalid), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_Firewall), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_Incompatible), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_BadInterfaceIndex), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_Refused), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_NoSuchRecord), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_NoAuth), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_NoSuchKey), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_NATTraversal), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_DoubleNAT), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_BadTime), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_BadSig), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_BadKey), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_Transient), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_ServiceNotRunning), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_NATPortMappingUnsupported), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_NATPortMappingDisabled), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_NoRouter), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_PollingMode), nullptr); + EXPECT_NE(otbr::Mdns::DNSErrorToString(kDNSServiceErr_Timeout), nullptr); +} diff --git a/tests/mdns/test_subscribe.cpp b/tests/gtest/test_mdns_subscribe.cpp similarity index 84% rename from tests/mdns/test_subscribe.cpp rename to tests/gtest/test_mdns_subscribe.cpp index b01be3eb434..24351e770f7 100644 --- a/tests/mdns/test_subscribe.cpp +++ b/tests/gtest/test_mdns_subscribe.cpp @@ -26,6 +26,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include +#include #include #include @@ -36,29 +38,11 @@ #include "common/mainloop_manager.hpp" #include "mdns/mdns.hpp" -#include -#include - using namespace otbr; using namespace otbr::Mdns; -TEST_GROUP(Mdns){}; - static constexpr int kTimeoutSeconds = 3; -SimpleString StringFrom(const std::set &aAddresses) -{ - std::string result = "["; - - for (const auto &address : aAddresses) - { - result += address.ToString() + ","; - } - result.back() = ']'; - - return SimpleString(result.c_str()); -} - int RunMainloopUntilTimeout(int aSeconds) { using namespace otbr; @@ -128,20 +112,23 @@ Ip6Address sAddr2; Ip6Address sAddr3; Ip6Address sAddr4; -void SetUp(void) +class MdnsTest : public ::testing::Test { - otbrLogInit("test-mdns-subscriber", OTBR_LOG_INFO, true, false); - SuccessOrDie(Ip6Address::FromString("2002::1", sAddr1), ""); - SuccessOrDie(Ip6Address::FromString("2002::2", sAddr2), ""); - SuccessOrDie(Ip6Address::FromString("2002::3", sAddr3), ""); - SuccessOrDie(Ip6Address::FromString("2002::4", sAddr4), ""); - SuccessOrDie(Publisher::EncodeTxtData(sTxtList1, sTxtData1), ""); -} +protected: + MdnsTest() + { + SuccessOrDie(Ip6Address::FromString("2002::1", sAddr1), ""); + SuccessOrDie(Ip6Address::FromString("2002::2", sAddr2), ""); + SuccessOrDie(Ip6Address::FromString("2002::3", sAddr3), ""); + SuccessOrDie(Ip6Address::FromString("2002::4", sAddr4), ""); + SuccessOrDie(Publisher::EncodeTxtData(sTxtList1, sTxtData1), ""); + } +}; std::unique_ptr CreatePublisher(void) { bool ready = false; - std::unique_ptr publisher{Publisher::Create([&publisher, &ready](Mdns::Publisher::State aState) { + std::unique_ptr publisher{Publisher::Create([&ready](Mdns::Publisher::State aState) { if (aState == Publisher::State::kReady) { ready = true; @@ -150,7 +137,7 @@ std::unique_ptr CreatePublisher(void) publisher->Start(); RunMainloopUntilTimeout(kTimeoutSeconds); - CHECK_TRUE(ready); + EXPECT_TRUE(ready); return publisher; } @@ -163,14 +150,14 @@ void CheckServiceInstance(const Publisher::DiscoveredInstanceInfo aInstanceInfo, uint16_t aPort, const Publisher::TxtData aTxtData) { - CHECK_EQUAL(aRemoved, aInstanceInfo.mRemoved); - CHECK_EQUAL(aServiceName, aInstanceInfo.mName); + EXPECT_EQ(aRemoved, aInstanceInfo.mRemoved); + EXPECT_EQ(aServiceName, aInstanceInfo.mName); if (!aRemoved) { - CHECK_EQUAL(aHostName, aInstanceInfo.mHostName); - CHECK_EQUAL(AsSet(aAddresses), AsSet(aInstanceInfo.mAddresses)); - CHECK_EQUAL(aPort, aInstanceInfo.mPort); - CHECK(AsTxtMap(aTxtData) == AsTxtMap(aInstanceInfo.mTxtData)); + EXPECT_EQ(aHostName, aInstanceInfo.mHostName); + EXPECT_EQ(AsSet(aAddresses), AsSet(aInstanceInfo.mAddresses)); + EXPECT_EQ(aPort, aInstanceInfo.mPort); + EXPECT_TRUE(AsTxtMap(aTxtData) == AsTxtMap(aInstanceInfo.mTxtData)); } } @@ -193,11 +180,11 @@ void CheckHostAdded(const Publisher::DiscoveredHostInfo &aHostInfo, const std::string &aHostName, const std::vector &aAddresses) { - CHECK_EQUAL(aHostName, aHostInfo.mHostName); - CHECK_EQUAL(AsSet(aAddresses), AsSet(aHostInfo.mAddresses)); + EXPECT_EQ(aHostName, aHostInfo.mHostName); + EXPECT_EQ(AsSet(aAddresses), AsSet(aHostInfo.mAddresses)); } -TEST(Mdns, SubscribeHost) +TEST_F(MdnsTest, SubscribeHost) { std::unique_ptr pub = CreatePublisher(); std::string lastHostName; @@ -220,23 +207,23 @@ TEST(Mdns, SubscribeHost) pub->PublishService("host1", "service1", "_test._tcp", Publisher::SubTypeList{"_sub1", "_sub2"}, 11111, sTxtData1, NoOpCallback()); RunMainloopUntilTimeout(kTimeoutSeconds); - CHECK_EQUAL("host1", lastHostName); + EXPECT_EQ("host1", lastHostName); CheckHostAdded(lastHostInfo, "host1.local.", {sAddr1, sAddr2}); clearLastHost(); pub->PublishService("host1", "service2", "_test._tcp", {}, 22222, {}, NoOpCallback()); RunMainloopUntilTimeout(kTimeoutSeconds); - CHECK_EQUAL("", lastHostName); + EXPECT_EQ("", lastHostName); clearLastHost(); pub->PublishHost("host2", Publisher::AddressList{sAddr3}, NoOpCallback()); pub->PublishService("host2", "service3", "_test._tcp", {}, 33333, {}, NoOpCallback()); RunMainloopUntilTimeout(kTimeoutSeconds); - CHECK_EQUAL("", lastHostName); + EXPECT_EQ("", lastHostName); clearLastHost(); } -TEST(Mdns, SubscribeServiceInstance) +TEST_F(MdnsTest, SubscribeServiceInstance) { std::unique_ptr pub = CreatePublisher(); std::string lastServiceType; @@ -260,23 +247,23 @@ TEST(Mdns, SubscribeServiceInstance) pub->PublishService("host1", "service1", "_test._tcp", Publisher::SubTypeList{"_sub1", "_sub2"}, 11111, sTxtData1, NoOpCallback()); RunMainloopUntilTimeout(kTimeoutSeconds); - CHECK_EQUAL("_test._tcp", lastServiceType); + EXPECT_EQ("_test._tcp", lastServiceType); CheckServiceInstanceAdded(lastInstanceInfo, "host1.local.", {sAddr1, sAddr2}, "service1", 11111, sTxtData1); clearLastInstance(); pub->PublishService("host1", "service2", "_test._tcp", {}, 22222, {}, NoOpCallback()); RunMainloopUntilTimeout(kTimeoutSeconds); - CHECK_EQUAL("", lastServiceType); + EXPECT_EQ("", lastServiceType); clearLastInstance(); pub->PublishHost("host2", Publisher::AddressList{sAddr3}, NoOpCallback()); pub->PublishService("host2", "service3", "_test._tcp", {}, 33333, {}, NoOpCallback()); RunMainloopUntilTimeout(kTimeoutSeconds); - CHECK_EQUAL("", lastServiceType); + EXPECT_EQ("", lastServiceType); clearLastInstance(); } -TEST(Mdns, SubscribeServiceType) +TEST_F(MdnsTest, SubscribeServiceType) { std::unique_ptr pub = CreatePublisher(); std::string lastServiceType; @@ -300,27 +287,27 @@ TEST(Mdns, SubscribeServiceType) pub->PublishService("host1", "service1", "_test._tcp", Publisher::SubTypeList{"_sub1", "_sub2"}, 11111, sTxtData1, NoOpCallback()); RunMainloopUntilTimeout(kTimeoutSeconds); - CHECK_EQUAL("_test._tcp", lastServiceType); + EXPECT_EQ("_test._tcp", lastServiceType); CheckServiceInstanceAdded(lastInstanceInfo, "host1.local.", {sAddr1, sAddr2}, "service1", 11111, sTxtData1); clearLastInstance(); pub->PublishService("host1", "service2", "_test._tcp", {}, 22222, {}, NoOpCallback()); RunMainloopUntilTimeout(kTimeoutSeconds); - CHECK_EQUAL("_test._tcp", lastServiceType); + EXPECT_EQ("_test._tcp", lastServiceType); CheckServiceInstanceAdded(lastInstanceInfo, "host1.local.", {sAddr1, sAddr2}, "service2", 22222, {}); clearLastInstance(); pub->PublishHost("host2", Publisher::AddressList{sAddr3}, NoOpCallback()); pub->PublishService("host2", "service3", "_test._tcp", {}, 33333, {}, NoOpCallback()); RunMainloopUntilTimeout(kTimeoutSeconds); - CHECK_EQUAL("_test._tcp", lastServiceType); + EXPECT_EQ("_test._tcp", lastServiceType); CheckServiceInstanceAdded(lastInstanceInfo, "host2.local.", {sAddr3}, "service3", 33333, {}); clearLastInstance(); pub->UnpublishHost("host2", NoOpCallback()); pub->UnpublishService("service3", "_test._tcp", NoOpCallback()); RunMainloopUntilTimeout(kTimeoutSeconds); - CHECK_EQUAL("_test._tcp", lastServiceType); + EXPECT_EQ("_test._tcp", lastServiceType); CheckServiceInstanceRemoved(lastInstanceInfo, "service3"); clearLastInstance(); @@ -328,20 +315,13 @@ TEST(Mdns, SubscribeServiceType) pub->PublishService("host2", "service3", "_test._tcp", {}, 44444, {}, NoOpCallback()); pub->PublishHost("host2", {sAddr3, sAddr4}, NoOpCallback()); RunMainloopUntilTimeout(kTimeoutSeconds); - CHECK_EQUAL("_test._tcp", lastServiceType); + EXPECT_EQ("_test._tcp", lastServiceType); CheckServiceInstanceAdded(lastInstanceInfo, "host2.local.", {sAddr3, sAddr4}, "service3", 44444, {}); clearLastInstance(); pub->PublishHost("host2", {sAddr4}, NoOpCallback()); RunMainloopUntilTimeout(kTimeoutSeconds); - CHECK_EQUAL("_test._tcp", lastServiceType); + EXPECT_EQ("_test._tcp", lastServiceType); CheckServiceInstanceAdded(lastInstanceInfo, "host2.local.", {sAddr4}, "service3", 44444, {}); clearLastInstance(); } - -int main(int argc, const char *argv[]) -{ - SetUp(); - - return RUN_ALL_TESTS(argc, argv); -} diff --git a/tests/gtest/test_netif.cpp b/tests/gtest/test_netif.cpp new file mode 100644 index 00000000000..05f51bbfec2 --- /dev/null +++ b/tests/gtest/test_netif.cpp @@ -0,0 +1,725 @@ +/* + * Copyright (c) 2024, 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#endif + +#include + +#include "common/code_utils.hpp" +#include "common/mainloop.hpp" +#include "common/types.hpp" +#include "ncp/posix/netif.hpp" +#include "utils/socket_utils.hpp" + +// Only Test on linux platform for now. +#ifdef __linux__ + +static constexpr size_t kMaxIp6Size = 1280; + +std::vector GetAllIp6Addrs(const char *aInterfaceName) +{ + struct ifaddrs *ifaddr, *ifa; + int family; + std::vector ip6Addrs; + + if (getifaddrs(&ifaddr) == -1) + { + perror("getifaddrs"); + exit(EXIT_FAILURE); + } + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr == NULL) + { + continue; + } + + family = ifa->ifa_addr->sa_family; + if (family == AF_INET6 && strcmp(ifa->ifa_name, aInterfaceName) == 0) + { + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)ifa->ifa_addr; + char addrstr[INET6_ADDRSTRLEN]; + if (inet_ntop(AF_INET6, &(in6->sin6_addr), addrstr, sizeof(addrstr)) == NULL) + { + perror("inet_ntop"); + exit(EXIT_FAILURE); + } + + ip6Addrs.emplace_back(addrstr); + } + } + + freeifaddrs(ifaddr); + + return ip6Addrs; +} + +static int ParseHex(char *aStr, unsigned char *aAddr) +{ + int len = 0; + + while (*aStr) + { + int tmp; + if (aStr[1] == 0) + { + return -1; + } + if (sscanf(aStr, "%02x", &tmp) != 1) + { + return -1; + } + aAddr[len] = tmp; + len++; + aStr += 2; + } + + return len; +} + +std::vector GetAllIp6MulAddrs(const char *aInterfaceName) +{ + const char *kPathIgmp6 = "/proc/net/igmp6"; + std::string line; + std::vector ip6MulAddrs; + + std::ifstream file(kPathIgmp6); + if (!file.is_open()) + { + perror("Cannot open IGMP6 file"); + exit(EXIT_FAILURE); + } + + while (std::getline(file, line)) + { + char interfaceName[256] = {0}; + char hexa[256] = {0}; + int index; + int users; + unsigned char addr[16]; + + sscanf(line.c_str(), "%d%s%s%d", &index, interfaceName, hexa, &users); + if (strcmp(interfaceName, aInterfaceName) == 0) + { + char addrStr[INET6_ADDRSTRLEN]; + ParseHex(hexa, addr); + if (inet_ntop(AF_INET6, addr, addrStr, sizeof(addrStr)) == NULL) + { + perror("inet_ntop"); + exit(EXIT_FAILURE); + } + ip6MulAddrs.emplace_back(addrStr); + } + } + + file.close(); + + return ip6MulAddrs; +} + +static otbr::Netif::Dependencies sDefaultNetifDependencies; + +TEST(Netif, WpanInitWithFullInterfaceName) +{ + const char *wpan = "wpan0"; + int sockfd; + struct ifreq ifr; + + otbr::Netif netif(sDefaultNetifDependencies); + EXPECT_EQ(netif.Init(wpan), OT_ERROR_NONE); + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + FAIL() << "Error creating socket: " << std::strerror(errno); + } + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, wpan, IFNAMSIZ - 1); + + EXPECT_GE(ioctl(sockfd, SIOCGIFFLAGS, &ifr), 0) << "'" << wpan << "' not found"; + + netif.Deinit(); +} + +TEST(Netif, WpanInitWithFormatInterfaceName) +{ + const char *wpan = "tun%d"; + const char *if_name = "tun0"; + int sockfd; + struct ifreq ifr; + + otbr::Netif netif(sDefaultNetifDependencies); + EXPECT_EQ(netif.Init(wpan), OT_ERROR_NONE); + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + FAIL() << "Error creating socket: " << std::strerror(errno); + } + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1); + + EXPECT_GE(ioctl(sockfd, SIOCGIFFLAGS, &ifr), 0) << "'" << if_name << "' not found"; + + netif.Deinit(); +} + +TEST(Netif, WpanInitWithEmptyInterfaceName) +{ + const char *if_name = "wpan0"; + int sockfd; + struct ifreq ifr; + + otbr::Netif netif(sDefaultNetifDependencies); + EXPECT_EQ(netif.Init(""), OT_ERROR_NONE); + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + FAIL() << "Error creating socket: " << std::strerror(errno); + } + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1); + + EXPECT_GE(ioctl(sockfd, SIOCGIFFLAGS, &ifr), 0) << "'" << if_name << "' not found"; + + netif.Deinit(); +} + +TEST(Netif, WpanInitWithInvalidInterfaceName) +{ + const char *invalid_netif_name = "invalid_netif_name"; + + otbr::Netif netif(sDefaultNetifDependencies); + EXPECT_EQ(netif.Init(invalid_netif_name), OTBR_ERROR_INVALID_ARGS); +} + +TEST(Netif, WpanMtuSize) +{ + const char *wpan = "wpan0"; + int sockfd; + struct ifreq ifr; + + otbr::Netif netif(sDefaultNetifDependencies); + EXPECT_EQ(netif.Init(wpan), OT_ERROR_NONE); + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + FAIL() << "Error creating socket: " << std::strerror(errno); + } + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, wpan, IFNAMSIZ - 1); + EXPECT_GE(ioctl(sockfd, SIOCGIFMTU, &ifr), 0) << "Error getting MTU for '" << wpan << "': " << std::strerror(errno); + EXPECT_EQ(ifr.ifr_mtu, kMaxIp6Size) << "MTU isn't set correctly"; + + netif.Deinit(); +} + +TEST(Netif, WpanDeinit) +{ + const char *wpan = "wpan0"; + int sockfd; + struct ifreq ifr; + + otbr::Netif netif(sDefaultNetifDependencies); + EXPECT_EQ(netif.Init(wpan), OT_ERROR_NONE); + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + FAIL() << "Error creating socket: " << std::strerror(errno); + } + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, wpan, IFNAMSIZ - 1); + EXPECT_GE(ioctl(sockfd, SIOCGIFFLAGS, &ifr), 0) << "'" << wpan << "' not found"; + + netif.Deinit(); + EXPECT_LT(ioctl(sockfd, SIOCGIFFLAGS, &ifr), 0) << "'" << wpan << "' isn't shutdown"; +} + +TEST(Netif, WpanAddrGenMode) +{ + otbr::Netif netif(sDefaultNetifDependencies); + EXPECT_EQ(netif.Init("wpan0"), OT_ERROR_NONE); + + std::fstream file("/proc/sys/net/ipv6/conf/wpan0/addr_gen_mode", std::ios::in); + if (!file.is_open()) + { + FAIL() << "wpan0 interface doesn't exist!"; + } + std::string fileContents((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + + EXPECT_EQ(std::stoi(fileContents), IN6_ADDR_GEN_MODE_NONE); + + netif.Deinit(); +} + +TEST(Netif, WpanIfHasCorrectUnicastAddresses_AfterUpdatingUnicastAddresses) +{ + const char *wpan = "wpan0"; + + const otIp6Address kLl = { + {0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x14, 0x03, 0x32, 0x4c, 0xc2, 0xf8, 0xd0}}; + const otIp6Address kMlEid = { + {0xfd, 0x0d, 0x07, 0xfc, 0xa1, 0xb9, 0xf0, 0x50, 0x03, 0xf1, 0x47, 0xce, 0x85, 0xd3, 0x07, 0x7f}}; + const otIp6Address kMlRloc = { + {0xfd, 0x0d, 0x07, 0xfc, 0xa1, 0xb9, 0xf0, 0x50, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0xb8, 0x00}}; + const otIp6Address kMlAloc = { + {0xfd, 0x0d, 0x07, 0xfc, 0xa1, 0xb9, 0xf0, 0x50, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0xfc, 0x00}}; + + const char *kLlStr = "fe80::8014:332:4cc2:f8d0"; + const char *kMlEidStr = "fd0d:7fc:a1b9:f050:3f1:47ce:85d3:77f"; + const char *kMlRlocStr = "fd0d:7fc:a1b9:f050:0:ff:fe00:b800"; + const char *kMlAlocStr = "fd0d:7fc:a1b9:f050:0:ff:fe00:fc00"; + + otbr::Netif netif(sDefaultNetifDependencies); + EXPECT_EQ(netif.Init(wpan), OT_ERROR_NONE); + + otbr::Ip6AddressInfo testArray1[] = { + {kLl, 64, 0, 1, 0}, + {kMlEid, 64, 0, 1, 1}, + {kMlRloc, 64, 0, 1, 1}, + }; + std::vector testVec1(testArray1, + testArray1 + sizeof(testArray1) / sizeof(otbr::Ip6AddressInfo)); + netif.UpdateIp6UnicastAddresses(testVec1); + std::vector wpan_addrs = GetAllIp6Addrs(wpan); + EXPECT_EQ(wpan_addrs.size(), 3); + EXPECT_THAT(wpan_addrs, ::testing::Contains(kLlStr)); + EXPECT_THAT(wpan_addrs, ::testing::Contains(kMlEidStr)); + EXPECT_THAT(wpan_addrs, ::testing::Contains(kMlRlocStr)); + + otbr::Ip6AddressInfo testArray2[] = { + {kLl, 64, 0, 1, 0}, + {kMlEid, 64, 0, 1, 1}, + {kMlRloc, 64, 0, 1, 1}, + {kMlAloc, 64, 0, 1, 1}, + }; + std::vector testVec2(testArray2, + testArray2 + sizeof(testArray2) / sizeof(otbr::Ip6AddressInfo)); + netif.UpdateIp6UnicastAddresses(testVec2); + wpan_addrs = GetAllIp6Addrs(wpan); + EXPECT_EQ(wpan_addrs.size(), 4); + EXPECT_THAT(wpan_addrs, ::testing::Contains(kLlStr)); + EXPECT_THAT(wpan_addrs, ::testing::Contains(kMlEidStr)); + EXPECT_THAT(wpan_addrs, ::testing::Contains(kMlRlocStr)); + EXPECT_THAT(wpan_addrs, ::testing::Contains(kMlAlocStr)); + + std::vector testVec3; + netif.UpdateIp6UnicastAddresses(testVec3); + wpan_addrs = GetAllIp6Addrs(wpan); + EXPECT_EQ(wpan_addrs.size(), 0); + + netif.Deinit(); +} + +TEST(Netif, WpanIfHasCorrectMulticastAddresses_AfterUpdatingMulticastAddresses) +{ + const char *wpan = "wpan0"; + otbr::Netif netif(sDefaultNetifDependencies); + EXPECT_EQ(netif.Init(wpan), OT_ERROR_NONE); + + otbr::Ip6Address kDefaultMulAddr1 = { + {0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}; + const char *kDefaultMulAddr1Str = "ff01::1"; + const char *kDefaultMulAddr2Str = "ff02::1"; + const char *kDefaultMulAddr3Str = "ff02::2"; + const char *kDefaultMulAddr4Str = "ff02::16"; + + otbr::Ip6Address kMulAddr1 = { + {0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc}}; + otbr::Ip6Address kMulAddr2 = { + {0xff, 0x32, 0x00, 0x40, 0xfd, 0x0d, 0x07, 0xfc, 0xa1, 0xb9, 0xf0, 0x50, 0x00, 0x00, 0x00, 0x01}}; + const char *kMulAddr1Str = "ff03::fc"; + const char *kMulAddr2Str = "ff32:40:fd0d:7fc:a1b9:f050:0:1"; + + otbr::Ip6Address testArray1[] = { + kMulAddr1, + }; + std::vector testVec1(testArray1, testArray1 + sizeof(testArray1) / sizeof(otbr::Ip6Address)); + netif.UpdateIp6MulticastAddresses(testVec1); + std::vector wpanMulAddrs = GetAllIp6MulAddrs(wpan); + EXPECT_EQ(wpanMulAddrs.size(), 5); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kMulAddr1Str)); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr1Str)); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr2Str)); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr3Str)); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr4Str)); + + otbr::Ip6Address testArray2[] = {kMulAddr1, kMulAddr2}; + std::vector testVec2(testArray2, testArray2 + sizeof(testArray2) / sizeof(otbr::Ip6Address)); + netif.UpdateIp6MulticastAddresses(testVec2); + wpanMulAddrs = GetAllIp6MulAddrs(wpan); + EXPECT_EQ(wpanMulAddrs.size(), 6); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kMulAddr1Str)); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kMulAddr2Str)); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr1Str)); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr2Str)); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr3Str)); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr4Str)); + + otbr::Ip6Address testArray3[] = {kDefaultMulAddr1}; + std::vector testVec3(testArray3, testArray3 + sizeof(testArray3) / sizeof(otbr::Ip6Address)); + netif.UpdateIp6MulticastAddresses(testVec3); + wpanMulAddrs = GetAllIp6MulAddrs(wpan); + EXPECT_EQ(wpanMulAddrs.size(), 4); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr1Str)); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr2Str)); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr3Str)); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr4Str)); + + std::vector empty; + netif.UpdateIp6MulticastAddresses(empty); + wpanMulAddrs = GetAllIp6MulAddrs(wpan); + EXPECT_EQ(wpanMulAddrs.size(), 4); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr1Str)); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr2Str)); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr3Str)); + EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr4Str)); + + netif.Deinit(); +} + +TEST(Netif, WpanIfStateChangesCorrectly_AfterSettingNetifState) +{ + otbr::Netif netif(sDefaultNetifDependencies); + const char *wpan = "wpan0"; + EXPECT_EQ(netif.Init(wpan), OTBR_ERROR_NONE); + + int fd = SocketWithCloseExec(AF_INET6, SOCK_DGRAM, IPPROTO_IP, kSocketNonBlock); + if (fd < 0) + { + perror("Failed to create test socket"); + exit(EXIT_FAILURE); + } + + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, wpan, IFNAMSIZ - 1); + + netif.SetNetifState(true); + ioctl(fd, SIOCGIFFLAGS, &ifr); + EXPECT_EQ(ifr.ifr_flags & IFF_UP, IFF_UP); + + netif.SetNetifState(false); + ioctl(fd, SIOCGIFFLAGS, &ifr); + EXPECT_EQ(ifr.ifr_flags & IFF_UP, 0); + + netif.Deinit(); +} + +TEST(Netif, WpanIfRecvIp6PacketCorrectly_AfterReceivingFromNetif) +{ + otbr::Netif netif(sDefaultNetifDependencies); + EXPECT_EQ(netif.Init("wpan0"), OTBR_ERROR_NONE); + + const otIp6Address kOmr = { + {0xfd, 0x2a, 0xc3, 0x0c, 0x87, 0xd3, 0x00, 0x01, 0xed, 0x1c, 0x0c, 0x91, 0xcc, 0xb6, 0x57, 0x8b}}; + std::vector addrs = { + {kOmr, 64, 0, 1, 0}, + }; + netif.UpdateIp6UnicastAddresses(addrs); + netif.SetNetifState(true); + + // Receive UDP packets on wpan address with specified port. + int sockFd; + const uint16_t port = 12345; + struct sockaddr_in6 listenAddr; + const char *listenIp = "fd2a:c30c:87d3:1:ed1c:c91:ccb6:578b"; + uint8_t recvBuf[kMaxIp6Size]; + + if ((sockFd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + { + perror("socket creation failed"); + exit(EXIT_FAILURE); + } + + memset(&listenAddr, 0, sizeof(listenAddr)); + listenAddr.sin6_family = AF_INET6; + listenAddr.sin6_port = htons(port); + inet_pton(AF_INET6, listenIp, &(listenAddr.sin6_addr)); + + if (bind(sockFd, (const struct sockaddr *)&listenAddr, sizeof(listenAddr)) < 0) + { + perror("bind failed"); + exit(EXIT_FAILURE); + } + + // Udp Packet + // Ip6 source: fd2a:c30c:87d3:1:ed1c:c91:ccb6:578a + // Ip6 destination: fd2a:c30c:87d3:1:ed1c:c91:ccb6:578b + // Udp destination port: 12345 + // Udp payload: "Hello Otbr Netif!" + const uint8_t udpPacket[] = {0x60, 0x0e, 0xea, 0x69, 0x00, 0x19, 0x11, 0x40, 0xfd, 0x2a, 0xc3, 0x0c, 0x87, + 0xd3, 0x00, 0x01, 0xed, 0x1c, 0x0c, 0x91, 0xcc, 0xb6, 0x57, 0x8a, 0xfd, 0x2a, + 0xc3, 0x0c, 0x87, 0xd3, 0x00, 0x01, 0xed, 0x1c, 0x0c, 0x91, 0xcc, 0xb6, 0x57, + 0x8b, 0xe7, 0x08, 0x30, 0x39, 0x00, 0x19, 0x36, 0x81, 0x48, 0x65, 0x6c, 0x6c, + 0x6f, 0x20, 0x4f, 0x74, 0x62, 0x72, 0x20, 0x4e, 0x65, 0x74, 0x69, 0x66, 0x21}; + netif.Ip6Receive(udpPacket, sizeof(udpPacket)); + + socklen_t len = sizeof(listenAddr); + int n = recvfrom(sockFd, (char *)recvBuf, kMaxIp6Size, MSG_WAITALL, (struct sockaddr *)&listenAddr, &len); + std::string udpPayload(reinterpret_cast(recvBuf), n); + EXPECT_EQ(udpPayload, "Hello Otbr Netif!"); + + close(sockFd); + netif.Deinit(); +} + +class NetifDependencyTestIp6Send : public otbr::Netif::Dependencies +{ +public: + NetifDependencyTestIp6Send(bool &aReceived, std::string &aReceivedPayload) + : mReceived(aReceived) + , mReceivedPayload(aReceivedPayload) + { + } + + otbrError Ip6Send(const uint8_t *aData, uint16_t aLength) override + { + const ip6_hdr *ipv6_header = reinterpret_cast(aData); + if (ipv6_header->ip6_nxt == IPPROTO_UDP) + { + const uint8_t *udpPayload = aData + aLength - ntohs(ipv6_header->ip6_plen) + sizeof(udphdr); + uint16_t udpPayloadLen = ntohs(ipv6_header->ip6_plen) - sizeof(udphdr); + mReceivedPayload = std::string(reinterpret_cast(udpPayload), udpPayloadLen); + + mReceived = true; + } + + return OTBR_ERROR_NONE; + } + + bool &mReceived; + std::string &mReceivedPayload; +}; + +TEST(Netif, WpanIfSendIp6PacketCorrectly_AfterReceivingOnIf) +{ + bool received = false; + std::string receivedPayload; + NetifDependencyTestIp6Send netifDependency(received, receivedPayload); + const char *hello = "Hello Otbr Netif!"; + + otbr::Netif netif(netifDependency); + EXPECT_EQ(netif.Init("wpan0"), OT_ERROR_NONE); + + // OMR Prefix: fd76:a5d1:fcb0:1707::/64 + const otIp6Address kOmr = { + {0xfd, 0x76, 0xa5, 0xd1, 0xfc, 0xb0, 0x17, 0x07, 0xf3, 0xc7, 0xd8, 0x8c, 0xef, 0xd1, 0x24, 0xa9}}; + std::vector addrs = { + {kOmr, 64, 0, 1, 0}, + }; + netif.UpdateIp6UnicastAddresses(addrs); + netif.SetNetifState(true); + + // Send a UDP packet destined to an address with OMR prefix. + { + int sockFd; + const uint16_t destPort = 12345; + struct sockaddr_in6 destAddr; + const char *destIp = "fd76:a5d1:fcb0:1707:3f1:47ce:85d3:77f"; + + if ((sockFd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + { + perror("socket creation failed"); + exit(EXIT_FAILURE); + } + + memset(&destAddr, 0, sizeof(destAddr)); + destAddr.sin6_family = AF_INET6; + destAddr.sin6_port = htons(destPort); + inet_pton(AF_INET6, destIp, &(destAddr.sin6_addr)); + + if (sendto(sockFd, hello, strlen(hello), MSG_CONFIRM, (const struct sockaddr *)&destAddr, sizeof(destAddr)) < 0) + { + FAIL() << "Failed to send UDP packet through WPAN interface"; + } + close(sockFd); + } + + otbr::MainloopContext context; + while (!received) + { + context.mMaxFd = -1; + context.mTimeout = {100, 0}; + FD_ZERO(&context.mReadFdSet); + FD_ZERO(&context.mWriteFdSet); + FD_ZERO(&context.mErrorFdSet); + + netif.UpdateFdSet(&context); + int rval = select(context.mMaxFd + 1, &context.mReadFdSet, &context.mWriteFdSet, &context.mErrorFdSet, + &context.mTimeout); + if (rval < 0) + { + perror("select failed"); + exit(EXIT_FAILURE); + } + netif.Process(&context); + } + + EXPECT_STREQ(receivedPayload.c_str(), hello); + + netif.Deinit(); +} + +class NetifDependencyTestMulSub : public otbr::Netif::Dependencies +{ +public: + NetifDependencyTestMulSub(bool &aReceived, otIp6Address &aMulAddr, bool &aIsAdded) + : mReceived(aReceived) + , mMulAddr(aMulAddr) + , mIsAdded(aIsAdded) + { + } + + otbrError Ip6MulAddrUpdateSubscription(const otIp6Address &aAddress, bool aIsAdded) override + { + mMulAddr = aAddress; + mIsAdded = aIsAdded; + mReceived = true; + return OTBR_ERROR_NONE; + } + + bool &mReceived; + otIp6Address &mMulAddr; + bool &mIsAdded; +}; + +TEST(Netif, WpanIfUpdateMulAddrSubscription_AfterAppJoiningMulGrp) +{ + bool received = false; + otIp6Address subscribedMulAddr; + bool isAdded = false; + NetifDependencyTestMulSub dependency(received, subscribedMulAddr, isAdded); + const char *multicastGroup = "ff99::1"; + const char *wpan = "wpan0"; + int sockFd; + otbr::Netif netif(dependency); + const otIp6Address expectedMulAddr = {0xff, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; + + EXPECT_EQ(netif.Init("wpan0"), OT_ERROR_NONE); + + const otIp6Address kLl = { + {0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x14, 0x03, 0x32, 0x4c, 0xc2, 0xf8, 0xd0}}; + std::vector addrs = { + {kLl, 64, 0, 1, 0}, + }; + netif.UpdateIp6UnicastAddresses(addrs); + netif.SetNetifState(true); + + { + struct ipv6_mreq mreq; + struct sockaddr_in6 addr; + + if ((sockFd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + { + perror("socket creation failed"); + exit(EXIT_FAILURE); + } + + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr = in6addr_any; + addr.sin6_port = htons(9999); + + if (bind(sockFd, (const struct sockaddr *)&addr, sizeof(addr)) < 0) + { + perror("bind failed"); + exit(EXIT_FAILURE); + } + + inet_pton(AF_INET6, multicastGroup, &(mreq.ipv6mr_multiaddr)); + mreq.ipv6mr_interface = if_nametoindex(wpan); + + if (setsockopt(sockFd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) + { + perror("Error joining multicast group"); + exit(EXIT_FAILURE); + } + } + + otbr::MainloopContext context; + while (!received) + { + context.mMaxFd = -1; + context.mTimeout = {100, 0}; + FD_ZERO(&context.mReadFdSet); + FD_ZERO(&context.mWriteFdSet); + FD_ZERO(&context.mErrorFdSet); + + netif.UpdateFdSet(&context); + int rval = select(context.mMaxFd + 1, &context.mReadFdSet, &context.mWriteFdSet, &context.mErrorFdSet, + &context.mTimeout); + if (rval < 0) + { + perror("select failed"); + exit(EXIT_FAILURE); + } + netif.Process(&context); + } + + EXPECT_EQ(otbr::Ip6Address(subscribedMulAddr), otbr::Ip6Address(expectedMulAddr)); + EXPECT_EQ(isAdded, true); + close(sockFd); + netif.Deinit(); +} + +#endif // __linux__ diff --git a/tests/unit/test_once_callback.cpp b/tests/gtest/test_once_callback.cpp similarity index 91% rename from tests/unit/test_once_callback.cpp rename to tests/gtest/test_once_callback.cpp index b43682c6504..a3276f15a7f 100644 --- a/tests/unit/test_once_callback.cpp +++ b/tests/gtest/test_once_callback.cpp @@ -26,24 +26,22 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "common/callback.hpp" - -#include +#include -TEST_GROUP(IsNull){}; +#include "common/callback.hpp" TEST(IsNull, NullptrIsNull) { otbr::OnceCallback noop = nullptr; - CHECK_TRUE(noop.IsNull()); + EXPECT_TRUE(noop.IsNull()); } TEST(IsNull, NonNullptrIsNotNull) { otbr::OnceCallback noop = [](void) {}; - CHECK_FALSE(noop.IsNull()); + EXPECT_FALSE(noop.IsNull()); } TEST(IsNull, IsNullAfterInvoking) @@ -52,16 +50,14 @@ TEST(IsNull, IsNullAfterInvoking) std::move(square)(5); - CHECK_TRUE(square.IsNull()); + EXPECT_TRUE(square.IsNull()); } -TEST_GROUP(VerifyInvocation){}; - TEST(VerifyInvocation, CallbackResultIsExpected) { otbr::OnceCallback square = [](int x) { return x * x; }; int ret = std::move(square)(5); - CHECK_EQUAL(ret, 25); + EXPECT_EQ(ret, 25); } diff --git a/tests/unit/test_pskc.cpp b/tests/gtest/test_pskc.cpp similarity index 72% rename from tests/unit/test_pskc.cpp rename to tests/gtest/test_pskc.cpp index 12fb6eaaed0..6120a1673de 100644 --- a/tests/unit/test_pskc.cpp +++ b/tests/gtest/test_pskc.cpp @@ -26,39 +26,40 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include +#include -#include "utils/pskc.hpp" +#include +#include -TEST_GROUP(Pskc) -{ - otbr::Psk::Pskc mPSKc; -}; +using ::testing::ElementsAreArray; + +#include "utils/pskc.hpp" TEST(Pskc, Test123456_0001020304050607_OpenThread) { + otbr::Psk::Pskc pskc; + uint8_t extpanid[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; uint8_t expected[] = { 0xb7, 0x83, 0x81, 0x27, 0x89, 0x91, 0x1e, 0xb4, 0xea, 0x76, 0x59, 0x6c, 0x9c, 0xed, 0x2a, 0x69, }; - const uint8_t *pskc = nullptr; - pskc = mPSKc.ComputePskc(extpanid, "OpenThread", "123456"); - MEMCMP_EQUAL(expected, pskc, sizeof(expected)); + const uint8_t *actual = pskc.ComputePskc(extpanid, "OpenThread", "123456"); + EXPECT_THAT(std::vector(actual, actual + OT_PSKC_LENGTH), ElementsAreArray(expected)); } TEST(Pskc, Test_TruncatedNetworkNamePskc_OpenThread) { - uint8_t extpanid[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; - const uint8_t *pskc = nullptr; - uint8_t expected[OT_PSKC_LENGTH]; + otbr::Psk::Pskc pskc; + uint8_t extpanid[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; + uint8_t expected[OT_PSKC_LENGTH]; // First run with shorter network name (max) - pskc = mPSKc.ComputePskc(extpanid, "OpenThread123456", "123456"); - memcpy(expected, pskc, OT_PSKC_LENGTH); + const uint8_t *actual = pskc.ComputePskc(extpanid, "OpenThread123456", "123456"); + memcpy(expected, actual, OT_PSKC_LENGTH); // Second run with longer network name that gets truncated - pskc = mPSKc.ComputePskc(extpanid, "OpenThread123456NetworkNameThatExceedsBuffer", "123456"); + actual = pskc.ComputePskc(extpanid, "OpenThread123456NetworkNameThatExceedsBuffer", "123456"); - MEMCMP_EQUAL(expected, pskc, OT_PSKC_LENGTH); + EXPECT_THAT(std::vector(actual, actual + OT_PSKC_LENGTH), ElementsAreArray(expected)); } diff --git a/tests/unit/test_task_runner.cpp b/tests/gtest/test_task_runner.cpp similarity index 92% rename from tests/unit/test_task_runner.cpp rename to tests/gtest/test_task_runner.cpp index 45aa6187d35..fedc776dbc6 100644 --- a/tests/unit/test_task_runner.cpp +++ b/tests/gtest/test_task_runner.cpp @@ -26,16 +26,14 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "common/task_runner.hpp" - #include #include #include -#include -#include +#include +#include -TEST_GROUP(TaskRunner){}; +#include "common/task_runner.hpp" TEST(TaskRunner, TestSingleThread) { @@ -63,10 +61,10 @@ TEST(TaskRunner, TestSingleThread) taskRunner.Update(mainloop); rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet, &mainloop.mTimeout); - CHECK_EQUAL(1, rval); + EXPECT_EQ(1, rval); taskRunner.Process(mainloop); - CHECK_EQUAL(3, counter); + EXPECT_EQ(3, counter); } TEST(TaskRunner, TestTasksOrder) @@ -90,12 +88,12 @@ TEST(TaskRunner, TestTasksOrder) taskRunner.Update(mainloop); rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet, &mainloop.mTimeout); - CHECK_TRUE(rval == 1); + EXPECT_EQ(rval, 1); taskRunner.Process(mainloop); // Make sure the tasks are executed in the order of posting. - STRCMP_EQUAL("abc", str.c_str()); + EXPECT_STREQ("abc", str.c_str()); } TEST(TaskRunner, TestMultipleThreads) @@ -125,7 +123,7 @@ TEST(TaskRunner, TestMultipleThreads) taskRunner.Update(mainloop); rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet, &mainloop.mTimeout); - CHECK_EQUAL(1, rval); + EXPECT_EQ(1, rval); taskRunner.Process(mainloop); } @@ -135,7 +133,7 @@ TEST(TaskRunner, TestMultipleThreads) th.join(); } - CHECK_EQUAL(10, counter.load()); + EXPECT_EQ(10, counter.load()); } TEST(TaskRunner, TestPostAndWait) @@ -166,7 +164,7 @@ TEST(TaskRunner, TestPostAndWait) taskRunner.Update(mainloop); rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet, &mainloop.mTimeout); - CHECK_EQUAL(1, rval); + EXPECT_EQ(1, rval); taskRunner.Process(mainloop); } @@ -176,8 +174,8 @@ TEST(TaskRunner, TestPostAndWait) th.join(); } - CHECK_EQUAL(55, total); - CHECK_EQUAL(10, counter.load()); + EXPECT_EQ(55, total); + EXPECT_EQ(10, counter.load()); } TEST(TaskRunner, TestDelayedTasks) @@ -207,7 +205,7 @@ TEST(TaskRunner, TestDelayedTasks) taskRunner.Update(mainloop); rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet, &mainloop.mTimeout); - CHECK_TRUE(rval >= 0 || errno == EINTR); + EXPECT_TRUE(rval >= 0 || errno == EINTR); taskRunner.Process(mainloop); } @@ -217,7 +215,7 @@ TEST(TaskRunner, TestDelayedTasks) th.join(); } - CHECK_EQUAL(10, counter.load()); + EXPECT_EQ(10, counter.load()); } TEST(TaskRunner, TestDelayedTasksOrder) @@ -244,13 +242,13 @@ TEST(TaskRunner, TestDelayedTasksOrder) taskRunner.Update(mainloop); rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet, &mainloop.mTimeout); - CHECK_TRUE(rval >= 0 || errno == EINTR); + EXPECT_TRUE(rval >= 0 || errno == EINTR); taskRunner.Process(mainloop); } // Make sure that tasks with smaller delay are executed earlier. - STRCMP_EQUAL("bac", str.c_str()); + EXPECT_STREQ("bac", str.c_str()); } TEST(TaskRunner, TestCancelDelayedTasks) @@ -265,11 +263,11 @@ TEST(TaskRunner, TestCancelDelayedTasks) tid4 = taskRunner.Post(std::chrono::milliseconds(40), [&]() { str.push_back('d'); }); tid5 = taskRunner.Post(std::chrono::milliseconds(50), [&]() { str.push_back('e'); }); - CHECK(0 < tid1); - CHECK(tid1 < tid2); - CHECK(tid2 < tid3); - CHECK(tid3 < tid4); - CHECK(tid4 < tid5); + EXPECT_TRUE(0 < tid1); + EXPECT_TRUE(tid1 < tid2); + EXPECT_TRUE(tid2 < tid3); + EXPECT_TRUE(tid3 < tid4); + EXPECT_TRUE(tid4 < tid5); taskRunner.Cancel(tid2); @@ -294,13 +292,13 @@ TEST(TaskRunner, TestCancelDelayedTasks) taskRunner.Update(mainloop); rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet, &mainloop.mTimeout); - CHECK_TRUE(rval >= 0 || errno == EINTR); + EXPECT_TRUE(rval >= 0 || errno == EINTR); taskRunner.Process(mainloop); } // Make sure the delayed task was not executed. - STRCMP_EQUAL("ae", str.c_str()); + EXPECT_STREQ("ae", str.c_str()); // Make sure it's fine to cancel expired task IDs. taskRunner.Cancel(tid1); @@ -337,7 +335,7 @@ TEST(TaskRunner, TestAllAPIs) taskRunner.Update(mainloop); rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet, &mainloop.mTimeout); - CHECK_TRUE(rval >= 0 || errno == EINTR); + EXPECT_TRUE(rval >= 0 || errno == EINTR); taskRunner.Process(mainloop); } @@ -347,5 +345,5 @@ TEST(TaskRunner, TestAllAPIs) th.join(); } - CHECK_EQUAL(30, counter.load()); + EXPECT_EQ(30, counter.load()); } diff --git a/tests/mdns/CMakeLists.txt b/tests/mdns/CMakeLists.txt index 861a79f17d0..f4778feece3 100644 --- a/tests/mdns/CMakeLists.txt +++ b/tests/mdns/CMakeLists.txt @@ -87,20 +87,3 @@ set_tests_properties( PROPERTIES ENVIRONMENT "OTBR_MDNS=${OTBR_MDNS};OTBR_TEST_MDNS=$" ) - -add_executable(otbr-test-mdns-subscribe - test_subscribe.cpp -) - -target_link_libraries(otbr-test-mdns-subscribe PRIVATE - otbr-config - otbr-mdns - $<$:-L$> - ${CPPUTEST_LIBRARIES} -) - - -add_test( - NAME mdns-subscribe - COMMAND otbr-test-mdns-subscribe -) diff --git a/tests/scripts/bootstrap.sh b/tests/scripts/bootstrap.sh index f3bdf513a6c..9c175970a1b 100755 --- a/tests/scripts/bootstrap.sh +++ b/tests/scripts/bootstrap.sh @@ -113,7 +113,7 @@ case "$(uname)" in if [ "$BUILD_TARGET" == check ] || [ "$BUILD_TARGET" == meshcop ]; then install_openthread_binraries - sudo apt-get install --no-install-recommends -y avahi-daemon avahi-utils cpputest + sudo apt-get install --no-install-recommends -y avahi-daemon avahi-utils configure_network fi diff --git a/tests/scripts/check-docker b/tests/scripts/check-docker index 3387a52a9b7..9d308cfe0a4 100755 --- a/tests/scripts/check-docker +++ b/tests/scripts/check-docker @@ -77,9 +77,11 @@ main() # shellcheck disable=SC2094 ot-rcp 1 >"$DEVICE_PTY" <"$DEVICE_PTY" & - OTBR_DOCKER_PID=$(docker run -d \ - --sysctl "net.ipv6.conf.all.disable_ipv6=0 net.ipv4.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1" \ - --privileged -p 8080:80 --dns=127.0.0.1 --volume "$DOCKER_PTY":/dev/ttyUSB0 otbr --backbone-interface eth0) + OTBR_DOCKER_PID=$( + docker run -d -e HTTP_PORT=10080 \ + --sysctl "net.ipv6.conf.all.disable_ipv6=0 net.ipv4.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1" \ + --privileged -p 8080:10080 --dns=127.0.0.1 --volume "$DOCKER_PTY":/dev/ttyUSB0 otbr --backbone-interface eth0 + ) readonly OTBR_DOCKER_PID sleep 10 sudo lsof -i :8080 diff --git a/tests/scripts/expect/_common.exp b/tests/scripts/expect/_common.exp new file mode 100644 index 00000000000..277e9709e95 --- /dev/null +++ b/tests/scripts/expect/_common.exp @@ -0,0 +1,112 @@ +#!/usr/bin/expect -f +# +# Copyright (c) 2024, 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. +# + +proc wait_for {command success {failure {[\r\n]FAILURE_NOT_EXPECTED[\r\n]}}} { + set timeout 1 + for {set i 0} {$i < 40} {incr i} { + if {$command != ""} { + send "$command\n" + } + + expect { + -re $success { + return 0 + } + -re $failure { + fail "Failed due to '$failure' found" + } + timeout { + # Do nothing + } + } + } + fail "Failed due to '$success' not found" +} + +proc expect_line {line} { + set timeout 10 + expect -re "\[\r\n \]($line)(?=\[\r\n>\])" + return $expect_out(1,string) +} + +# type: The type of the node. +# Possible values: +# 1. cli: The cli app. ot-cli-ftd or ot-cli-mtd +# 2. otbr: The otbr-agent. +# +# sim_app: The path of the simulation app to start the node. +# If type is 'cli', sim_app is the path of the cli app. +# If type is 'otbr', sim_app is the path of the coprocessor. It could be 'ot-rcp', 'ot-ncp-ftd' +# or 'ot-ncp-mtd'. +proc spawn_node {id type sim_app} { + global spawn_id + global spawn_ids + global argv0 + + send_user "\n# ${id} ${type} ${sim_app}\n" + + switch -regexp ${type} { + cli { + spawn $sim_app $id + send "factoryreset\n" + wait_for "state" "disabled" + expect_line "Done" + send "routerselectionjitter 1\n" + expect_line "Done" + + expect_after { + timeout { fail "Timed out" } + } + } + otbr { + spawn $::env(EXP_OTBR_AGENT_PATH) -I $::env(EXP_TUN_NAME) -d7 "spinel+hdlc+forkpty://${sim_app}?forkpty-arg=${id}" + } + } + + set spawn_ids($id) $spawn_id + + return $spawn_id +} + +proc switch_node {id} { + global spawn_ids + global spawn_id + + send_user "\n# ${id}\n" + set spawn_id $spawn_ids($id) +} + +proc get_ipaddr {type} { + send "ipaddr $type\n" + expect "ipaddr $type" + set rval [expect_line {([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}}] + expect_line "Done" + + return $rval +} diff --git a/tests/scripts/expect/ncp_get_device_role.exp b/tests/scripts/expect/ncp_get_device_role.exp new file mode 100755 index 00000000000..72b361b78f6 --- /dev/null +++ b/tests/scripts/expect/ncp_get_device_role.exp @@ -0,0 +1,46 @@ +#!/usr/bin/expect -f +# +# Copyright (c) 2024, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +source "tests/scripts/expect/_common.exp" + +spawn_node 1 otbr $::env(EXP_OT_NCP_PATH) + +sleep 1 + +spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --print-reply --reply-timeout=1000 /io/openthread/BorderRouter/wpan0 org.freedesktop.DBus.Properties.Get string:io.openthread.BorderRouter string:DeviceRole +expect -re {disabled} { +} timeout { + puts "timeout!" + exit 1 +} +expect eof + +# Shut down otbr-agent +switch_node 1 +send "\x04" +expect eof diff --git a/tests/scripts/expect/ncp_join_leave.exp b/tests/scripts/expect/ncp_join_leave.exp new file mode 100755 index 00000000000..a6c25ab2021 --- /dev/null +++ b/tests/scripts/expect/ncp_join_leave.exp @@ -0,0 +1,76 @@ +#!/usr/bin/expect -f +# +# Copyright (c) 2024, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +source "tests/scripts/expect/_common.exp" + +set dataset "0e080000000000010000000300001435060004001fffe002087d61eb42cdc48d6a0708fd0d07fca1b9f0500510ba088fc2bd6c3b3897f7a10f58263ff3030f4f70656e5468726561642d353234660102524f04109dc023ccd447b12b50997ef68020f19e0c0402a0f7f8" +set dataset_dbus "0x0e,0x08,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x14,0x35,0x06,0x00,0x04,0x00,0x1f,0xff,0xe0,0x02,0x08,0x7d,0x61,0xeb,0x42,0xcd,0xc4,0x8d,0x6a,0x07,0x08,0xfd,0x0d,0x07,0xfc,0xa1,0xb9,0xf0,0x50,0x05,0x10,0xba,0x08,0x8f,0xc2,0xbd,0x6c,0x3b,0x38,0x97,0xf7,0xa1,0x0f,0x58,0x26,0x3f,0xf3,0x03,0x0f,0x4f,0x70,0x65,0x6e,0x54,0x68,0x72,0x65,0x61,0x64,0x2d,0x35,0x32,0x34,0x66,0x01,0x02,0x52,0x4f,0x04,0x10,0x9d,0xc0,0x23,0xcc,0xd4,0x47,0xb1,0x2b,0x50,0x99,0x7e,0xf6,0x80,0x20,0xf1,0x9e,0x0c,0x04,0x02,0xa0,0xf7,0xf8" + +# Step 1. Start a Thread node and create a Thread network +spawn_node 1 cli $::env(EXP_OT_CLI_PATH) + +send "dataset set active ${dataset}\n" +expect_line "Done" +send "ifconfig up\n" +expect_line "Done" +send "thread start\n" +expect_line "Done" +wait_for "state" "leader" +expect_line "Done" + + +# Step 2. Start otbr-agent with a NCP and join the network by dbus join method +spawn_node 2 otbr $::env(EXP_OT_NCP_PATH) +sleep 1 + +spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 io.openthread.BorderRouter.Join "array:byte:${dataset_dbus}" +expect eof + +# Step 3. Wait 10 seconds, check if the otbr-agent has attached successfully +sleep 10 +spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --print-reply --reply-timeout=1000 /io/openthread/BorderRouter/wpan0 org.freedesktop.DBus.Properties.Get string:io.openthread.BorderRouter string:DeviceRole +expect -re {router|child} { +} timeout { + puts "timeout!" + exit 1 +} +expect eof + +# Step 4. Use dbus leave method to let otbr-agent leave the network +spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 io.openthread.BorderRouter.LeaveNetwork +expect eof + +# Step 5. Verify the state of otbr-agent is 'disabled' +spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --print-reply --reply-timeout=1000 /io/openthread/BorderRouter/wpan0 org.freedesktop.DBus.Properties.Get string:io.openthread.BorderRouter string:DeviceRole +expect -re {disabled} { +} timeout { + puts "timeout!" + exit 1 +} +expect eof diff --git a/tests/scripts/expect/ncp_netif_address_update.exp b/tests/scripts/expect/ncp_netif_address_update.exp new file mode 100755 index 00000000000..974b563301c --- /dev/null +++ b/tests/scripts/expect/ncp_netif_address_update.exp @@ -0,0 +1,94 @@ +#!/usr/bin/expect -f +# +# Copyright (c) 2024, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +source "tests/scripts/expect/_common.exp" + +# Dataset +# Mesh Local Prefix: fd0d:7fc:a1b9:f050::/64 +set dataset_dbus "0x0e,0x08,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x14,0x35,0x06,0x00,0x04,0x00,0x1f,0xff,0xe0,0x02,0x08,0x7d,0x61,0xeb,0x42,0xcd,0xc4,0x8d,0x6a,0x07,0x08,0xfd,0x0d,0x07,0xfc,0xa1,0xb9,0xf0,0x50,0x05,0x10,0xba,0x08,0x8f,0xc2,0xbd,0x6c,0x3b,0x38,0x97,0xf7,0xa1,0x0f,0x58,0x26,0x3f,0xf3,0x03,0x0f,0x4f,0x70,0x65,0x6e,0x54,0x68,0x72,0x65,0x61,0x64,0x2d,0x35,0x32,0x34,0x66,0x01,0x02,0x52,0x4f,0x04,0x10,0x9d,0xc0,0x23,0xcc,0xd4,0x47,0xb1,0x2b,0x50,0x99,0x7e,0xf6,0x80,0x20,0xf1,0x9e,0x0c,0x04,0x02,0xa0,0xf7,0xf8" + +# Step 1. Start otbr-agent with a NCP and join the network by dbus join method. +spawn_node 2 otbr $::env(EXP_OT_NCP_PATH) +sleep 1 + +spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 io.openthread.BorderRouter.Join "array:byte:${dataset_dbus}" +expect eof + +# Step 2. Wait 10 seconds for it becomes a leader. +sleep 10 +spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --print-reply --reply-timeout=1000 /io/openthread/BorderRouter/wpan0 org.freedesktop.DBus.Properties.Get string:io.openthread.BorderRouter string:DeviceRole +expect -re {leader} { +} timeout { + puts "timeout!" + exit 1 +} +expect eof + +# Step 3. Verify the addresses on wpan. +# There should be: +# 1. ml eid +# 2. ml anycast +# 3. ml rloc +# 4. link local +spawn ip addr show wpan0 +expect -re {fd0d:7fc:a1b9:f050(:[0-9a-f]{1,4}){4,4}} +expect -re {fd0d:7fc:a1b9:f050(:[0-9a-f]{1,4}){4,4}} +expect -re {fd0d:7fc:a1b9:f050(:[0-9a-f]{1,4}){4,4}} +expect -re {fe80:(:[0-9a-f]{1,4}){4,4}} +expect eof + +# Multicast addresses should contain: +# 1. ff01::1 +# 2. ff02::1 +# 3. ff02::2 +# 4. ff03::1 +# 5. ff03::2 +spawn ip maddr show dev wpan0 +expect eof +set maddr_output $expect_out(buffer) +if {![string match "*ff01::1*" $maddr_output]} { fail "No multicast address ff01::1" } +if {![string match "*ff02::1*" $maddr_output]} { fail "No multicast address ff02::1" } +if {![string match "*ff02::2*" $maddr_output]} { fail "No multicast address ff02::2" } +if {![string match "*ff03::1*" $maddr_output]} { fail "No multicast address ff03::1" } +if {![string match "*ff03::2*" $maddr_output]} { fail "No multicast address ff03::2" } + +# Step 4. Verify the wpan isUp state +spawn ip link show wpan0 +expect -re {UP} +expect eof + +# Step 5. Use dbus leave method to let the node leave the network +spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 io.openthread.BorderRouter.LeaveNetwork +expect eof + +# Step 6. Verify the addresses on wpan. +# There should be: +# 1. link local +spawn ip addr show wpan0 +expect -re {fe80:(:[0-9a-f]{1,4}){4,4}} +expect eof diff --git a/tests/scripts/expect/ncp_netif_tx_rx.exp b/tests/scripts/expect/ncp_netif_tx_rx.exp new file mode 100755 index 00000000000..8e7d1f3c5e4 --- /dev/null +++ b/tests/scripts/expect/ncp_netif_tx_rx.exp @@ -0,0 +1,67 @@ +#!/usr/bin/expect -f +# +# Copyright (c) 2024, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +source "tests/scripts/expect/_common.exp" + +set dataset "0e080000000000010000000300001435060004001fffe002087d61eb42cdc48d6a0708fd0d07fca1b9f0500510ba088fc2bd6c3b3897f7a10f58263ff3030f4f70656e5468726561642d353234660102524f04109dc023ccd447b12b50997ef68020f19e0c0402a0f7f8" +set dataset_dbus "0x0e,0x08,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x14,0x35,0x06,0x00,0x04,0x00,0x1f,0xff,0xe0,0x02,0x08,0x7d,0x61,0xeb,0x42,0xcd,0xc4,0x8d,0x6a,0x07,0x08,0xfd,0x0d,0x07,0xfc,0xa1,0xb9,0xf0,0x50,0x05,0x10,0xba,0x08,0x8f,0xc2,0xbd,0x6c,0x3b,0x38,0x97,0xf7,0xa1,0x0f,0x58,0x26,0x3f,0xf3,0x03,0x0f,0x4f,0x70,0x65,0x6e,0x54,0x68,0x72,0x65,0x61,0x64,0x2d,0x35,0x32,0x34,0x66,0x01,0x02,0x52,0x4f,0x04,0x10,0x9d,0xc0,0x23,0xcc,0xd4,0x47,0xb1,0x2b,0x50,0x99,0x7e,0xf6,0x80,0x20,0xf1,0x9e,0x0c,0x04,0x02,0xa0,0xf7,0xf8" + +# Step 1. Start a Thread node and create a Thread network +spawn_node 1 cli $::env(EXP_OT_CLI_PATH) + +send "dataset set active ${dataset}\n" +expect_line "Done" +send "ifconfig up\n" +expect_line "Done" +send "thread start\n" +expect_line "Done" +wait_for "state" "leader" +expect_line "Done" +set dest_addr [get_ipaddr mleid] + +# Step 2. Start otbr-agent with a NCP and join the network by dbus join method +spawn_node 2 otbr $::env(EXP_OT_NCP_PATH) +sleep 1 + +spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 io.openthread.BorderRouter.Join "array:byte:${dataset_dbus}" +expect eof + +# Step 3. Wait 10 seconds, check if the otbr-agent has attached successfully +sleep 10 +spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --print-reply --reply-timeout=1000 /io/openthread/BorderRouter/wpan0 org.freedesktop.DBus.Properties.Get string:io.openthread.BorderRouter string:DeviceRole +expect -re {router|child} { +} timeout { + puts "timeout!" + exit 1 +} +expect eof + +# Step 4. Verify pinging from otbr-agent NCP to the cli node +spawn ping6 -c 10 ${dest_addr} +expect "10 packets transmitted, 10 received, 0% packet loss" +expect eof diff --git a/tests/scripts/expect/ncp_schedule_migration.exp b/tests/scripts/expect/ncp_schedule_migration.exp new file mode 100644 index 00000000000..c32656f52f5 --- /dev/null +++ b/tests/scripts/expect/ncp_schedule_migration.exp @@ -0,0 +1,80 @@ +#!/usr/bin/expect -f +# +# Copyright (c) 2024, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +source "tests/scripts/expect/_common.exp" + +# Dataset of the initial Thread network +set dataset "0e080000000000010000000300001435060004001fffe002087d61eb42cdc48d6a0708fd0d07fca1b9f0500510ba088fc2bd6c3b3897f7a10f58263ff3030f4f70656e5468726561642d353234660102524f04109dc023ccd447b12b50997ef68020f19e0c0402a0f7f8" +set dataset_dbus "0x0e,0x08,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x14,0x35,0x06,0x00,0x04,0x00,0x1f,0xff,0xe0,0x02,0x08,0x7d,0x61,0xeb,0x42,0xcd,0xc4,0x8d,0x6a,0x07,0x08,0xfd,0x0d,0x07,0xfc,0xa1,0xb9,0xf0,0x50,0x05,0x10,0xba,0x08,0x8f,0xc2,0xbd,0x6c,0x3b,0x38,0x97,0xf7,0xa1,0x0f,0x58,0x26,0x3f,0xf3,0x03,0x0f,0x4f,0x70,0x65,0x6e,0x54,0x68,0x72,0x65,0x61,0x64,0x2d,0x35,0x32,0x34,0x66,0x01,0x02,0x52,0x4f,0x04,0x10,0x9d,0xc0,0x23,0xcc,0xd4,0x47,0xb1,0x2b,0x50,0x99,0x7e,0xf6,0x80,0x20,0xf1,0x9e,0x0c,0x04,0x02,0xa0,0xf7,0xf8" + +# Dataset of the Thread network to migrate to +# (Only updates active timestamp and panid, panid is set to 0x9999) +set dataset1 "0e080000000000020000000300001435060004001fffe002087d61eb42cdc48d6a0708fd0d07fca1b9f0500510ba088fc2bd6c3b3897f7a10f58263ff3030f4f70656e5468726561642d353234660102999904109dc023ccd447b12b50997ef68020f19e0c0402a0f7f8" +set dataset1_dbus "0x0e,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x14,0x35,0x06,0x00,0x04,0x00,0x1f,0xff,0xe0,0x02,0x08,0x7d,0x61,0xeb,0x42,0xcd,0xc4,0x8d,0x6a,0x07,0x08,0xfd,0x0d,0x07,0xfc,0xa1,0xb9,0xf0,0x50,0x05,0x10,0xba,0x08,0x8f,0xc2,0xbd,0x6c,0x3b,0x38,0x97,0xf7,0xa1,0x0f,0x58,0x26,0x3f,0xf3,0x03,0x0f,0x4f,0x70,0x65,0x6e,0x54,0x68,0x72,0x65,0x61,0x64,0x2d,0x35,0x32,0x34,0x66,0x01,0x02,0x99,0x99,0x04,0x10,0x9d,0xc0,0x23,0xcc,0xd4,0x47,0xb1,0x2b,0x50,0x99,0x7e,0xf6,0x80,0x20,0xf1,0x9e,0x0c,0x04,0x02,0xa0,0xf7,0xf8" + +# Step 1. Start otbr-agent with a NCP and join the network by dbus join method +spawn_node 1 otbr $::env(EXP_OT_NCP_PATH) +sleep 1 +spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 io.openthread.BorderRouter.Join "array:byte:${dataset_dbus}" +expect eof + +# Step 2. Wait 10 seconds, check if the otbr-agent has attached successfully +sleep 10 +spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --print-reply --reply-timeout=1000 /io/openthread/BorderRouter/wpan0 org.freedesktop.DBus.Properties.Get string:io.openthread.BorderRouter string:DeviceRole +expect -re {leader} { +} timeout { + puts "timeout!" + exit 1 +} +expect eof + +# Step 3. Start a Thread node and create a Thread network +spawn_node 2 cli $::env(EXP_OT_CLI_PATH) + +send "dataset set active ${dataset}\n" +expect_line "Done" +send "mode rn\n" +expect_line "Done" +send "ifconfig up\n" +expect_line "Done" +send "thread start\n" +expect_line "Done" +wait_for "state" "child" +expect_line "Done" + +# Step 4. Call ScheduleMigration method to migrate to another Thread network after 30s +spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 io.openthread.BorderRouter.ScheduleMigration "array:byte:${dataset1_dbus}" "uint32:0x7530" +expect eof + +# Step 5. Wait 31 seconds, check if the otbr-agent has migrated successfully by checking child's panid +sleep 31 +switch_node 2 +send "panid\n" +expect_line "0x9999" +expect_line "Done" diff --git a/tests/scripts/expect/ncp_test_schedule_migration_dbus_api.exp b/tests/scripts/expect/ncp_test_schedule_migration_dbus_api.exp new file mode 100755 index 00000000000..94909534d8e --- /dev/null +++ b/tests/scripts/expect/ncp_test_schedule_migration_dbus_api.exp @@ -0,0 +1,51 @@ +#!/usr/bin/expect -f +# +# Copyright (c) 2024, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +source "tests/scripts/expect/_common.exp" + +set dataset_valid "0x0e,0x08,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x0d,0x35,0x06,0x00,0x04,0x00,0x1f,0xff,0xe0,0x02,0x08,0x1f,0xeb,0xac,0x0f,0xca,0x10,0x8c,0xcd,0x07,0x08,0xfd,0x26,0x9e,0x9f,0x6b,0x8a,0x2a,0xa1,0x05,0x10,0xd3,0x7e,0x6d,0x55,0x73,0xcc,0x88,0x43,0xdb,0x22,0x3b,0x00,0xcd,0x8f,0xf2,0xb0,0x03,0x0f,0x4f,0x70,0x65,0x6e,0x54,0x68,0x72,0x65,0x61,0x64,0x2d,0x65,0x36,0x62,0x37,0x04,0x10,0x16,0xcc,0x1e,0x42,0x3a,0x9c,0xe9,0x47,0xf6,0x05,0x9a,0xe5,0xb8,0x38,0x17,0xb7,0x0c,0x04,0x02,0xa0,0xf7,0xf8,0x01,0x02,0x99,0x99" + +set dataset_has_pending_timestamp "$dataset_valid,0x33,0x08,0x00,0x00,0x07,0x5b,0xcd,0x15,0x00,0x00" + +set dataset_has_delay "$dataset_valid,0x34,0x04,0x00,0x00,0x75,0x30" + +spawn_node 1 otbr $::env(EXP_OT_NCP_PATH) +sleep 1 + +spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 io.openthread.BorderRouter.ScheduleMigration "array:byte:${dataset_valid}" "uint32:0x7530" +expect Error.InvalidState +expect eof + +spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 io.openthread.BorderRouter.ScheduleMigration "array:byte:${dataset_has_pending_timestamp}" "uint32:0x7530" +expect Error.InvalidArgs +expect eof + +spawn dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 io.openthread.BorderRouter.ScheduleMigration "array:byte:${dataset_has_delay}" "uint32:0x7530" +expect Error.InvalidArgs +expect eof diff --git a/tests/scripts/expect/ncp_version.exp b/tests/scripts/expect/ncp_version.exp new file mode 100755 index 00000000000..7cd3b614af1 --- /dev/null +++ b/tests/scripts/expect/ncp_version.exp @@ -0,0 +1,42 @@ +#!/usr/bin/expect -f +# +# Copyright (c) 2024, 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. +# +set timeout 1 + +# Spawn the otbr-agent with NCP in Dry Run mode +spawn $::env(EXP_OTBR_AGENT_PATH) -I $::env(EXP_TUN_NAME) -v -d7 --radio-version "spinel+hdlc+forkpty://$::env(EXP_OT_NCP_PATH)?forkpty-arg=$::env(EXP_LEADER_NODE_ID)" + +# Expect the NCP version +expect -re {OPENTHREAD/[0-9a-z]{6,9}; SIMULATION} { +} timeout { + puts "timeout!" + exit 1 +} + +# Wait for the spawned process to terminate +expect eof diff --git a/tests/scripts/meshcop b/tests/scripts/meshcop index f44882dd8fe..104c21e7ed1 100755 --- a/tests/scripts/meshcop +++ b/tests/scripts/meshcop @@ -517,7 +517,7 @@ test_meshcop_service() service="$(scan_meshcop_service)" grep "${OT_SERVICE_INSTANCE}._meshcop\._udp" <<<"${service}" grep "rv=1" <<<"${service}" - grep "tv=1\.3\.0" <<<"${service}" + grep "tv=1\.4\.0" <<<"${service}" grep "nn=${network_name}" <<<"${service}" grep "xp=${xpanid_txt}" <<<"${service}" grep "xa=${extaddr_txt}" <<<"${service}" diff --git a/tests/scripts/ncp_mode b/tests/scripts/ncp_mode new file mode 100755 index 00000000000..a6d00067273 --- /dev/null +++ b/tests/scripts/ncp_mode @@ -0,0 +1,261 @@ +#!/bin/bash +# +# Copyright (c) 2024, 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. +# +# Test basic functionality of otbr-agent under NCP mode. +# +# Usage: +# ./ncp_mode +set -euxo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +readonly SCRIPT_DIR +EXPECT_SCRIPT_DIR="${SCRIPT_DIR}/expect" +readonly EXPECT_SCRIPT_DIR + +#--------------------------------------- +# Configurations +#--------------------------------------- +OT_CLI="${OT_CLI:-ot-cli-ftd}" +readonly OT_CLI + +OT_NCP="${OT_NCP:-ot-ncp-ftd}" +readonly OT_NCP + +ABS_TOP_BUILDDIR="$(cd "${top_builddir:-"${SCRIPT_DIR}"/../../}" && pwd)" +readonly ABS_TOP_BUILDDIR + +ABS_TOP_SRCDIR="$(cd "${top_srcdir:-"${SCRIPT_DIR}"/../../}" && pwd)" +readonly ABS_TOP_SRCDIR + +ABS_TOP_OT_SRCDIR="${ABS_TOP_SRCDIR}/third_party/openthread/repo" +readonly ABS_TOP_OT_SRCDIR + +ABS_TOP_OT_BUILDDIR="${ABS_TOP_BUILDDIR}/../simulation" +readonly ABS_TOP_BUILDDIR + +OTBR_COLOR_PASS='\033[0;32m' +readonly OTBR_COLOR_PASS + +OTBR_COLOR_FAIL='\033[0;31m' +readonly OTBR_COLOR_FAIL + +OTBR_COLOR_NONE='\033[0m' +readonly OTBR_COLOR_NONE + +readonly OTBR_VERBOSE="${OTBR_VERBOSE:-0}" + +#---------------------------------------- +# Helper functions +#---------------------------------------- +die() +{ + exit_message="$*" + echo " *** ERROR: $*" + exit 1 +} + +exists_or_die() +{ + [[ -f $1 ]] || die "Missing file: $1" +} + +executable_or_die() +{ + [[ -x $1 ]] || die "Missing executable: $1" +} + +write_syslog() +{ + logger -s -p syslog.alert "OTBR_TEST: $*" +} + +#---------------------------------------- +# Test constants +#---------------------------------------- +TEST_BASE=/tmp/test-otbr +readonly TEST_BASE + +OTBR_AGENT=otbr-agent +readonly OTBR_AGENT + +STAGE_DIR="${TEST_BASE}/stage" +readonly STAGE_DIR + +BUILD_DIR="${TEST_BASE}/build" +readonly BUILD_DIR + +OTBR_DBUS_CONF="${ABS_TOP_BUILDDIR}/src/agent/otbr-agent.conf" +readonly OTBR_DBUS_CONF + +OTBR_AGENT_PATH="${ABS_TOP_BUILDDIR}/src/agent/${OTBR_AGENT}" +readonly OTBR_AGENT_PATH + +# The node ids +LEADER_NODE_ID=1 +readonly LEADER_NODE_ID + +# The TUN device for OpenThread border router. +TUN_NAME=wpan0 +readonly TUN_NAME + +#---------------------------------------- +# Test steps +#---------------------------------------- +build_ot_simulation() +{ + sudo rm -rf "${ABS_TOP_OT_BUILDDIR}/ncp" + sudo rm -rf "${ABS_TOP_OT_BUILDDIR}/cli" + OT_CMAKE_BUILD_DIR=${ABS_TOP_OT_BUILDDIR}/ncp "${ABS_TOP_OT_SRCDIR}"/script/cmake-build simulation -DOT_MTD=OFF -DOT_APP_CLI=OFF -DOT_APP_RCP=OFF + OT_CMAKE_BUILD_DIR=${ABS_TOP_OT_BUILDDIR}/cli "${ABS_TOP_OT_SRCDIR}"/script/cmake-build simulation -DOT_MTD=OFF -DOT_APP_NCP=OFF -DOT_APP_RCP=OFF -DOT_RCP=OFF +} + +test_setup() +{ + executable_or_die "${OTBR_AGENT_PATH}" + + # Remove flashes + sudo rm -vrf "${TEST_BASE}/tmp" + # OPENTHREAD_POSIX_DAEMON_SOCKET_LOCK + sudo rm -vf "/tmp/openthread.lock" + + [[ ${BUILD_OT_SIM} == 1 ]] && build_ot_simulation + ot_cli=$(find "${ABS_TOP_OT_BUILDDIR}" -name "${OT_CLI}") + ot_ncp=$(find "${ABS_TOP_OT_BUILDDIR}" -name "${OT_NCP}") + + # We will be creating a lot of log information + # Rotate logs so we have a clean and empty set of logs uncluttered with other stuff + if [[ -f /etc/logrotate.conf ]]; then + sudo logrotate -f /etc/logrotate.conf || true + fi + + # Preparation for otbr-agent + exists_or_die "${OTBR_DBUS_CONF}" + sudo cp "${OTBR_DBUS_CONF}" /etc/dbus-1/system.d + + write_syslog "AGENT: kill old" + sudo killall "${OTBR_AGENT}" || true + + # From now on - all exits are TRAPPED + # When they occur, we call the function: output_logs'. + trap test_teardown EXIT +} + +test_teardown() +{ + # Capture the exit code so we can return it below + EXIT_CODE=$? + readonly EXIT_CODE + write_syslog "EXIT ${EXIT_CODE} - output logs" + + sudo pkill -f "${OTBR_AGENT}" || true + sudo pkill -f "${OT_CLI}" || true + sudo pkill -f "${OT_NCP}" || true + wait + + echo 'clearing all' + sudo rm /etc/dbus-1/system.d/otbr-agent.conf || true + sudo rm -rf "${STAGE_DIR}" || true + sudo rm -rf "${BUILD_DIR}" || true + + exit_message="Test teardown" + echo "EXIT ${EXIT_CODE}: MESSAGE: ${exit_message}" + exit ${EXIT_CODE} +} + +otbr_exec_expect_script() +{ + local log_file="tmp/log_expect" + + for script in "$@"; do + echo -e "\n${OTBR_COLOR_PASS}EXEC${OTBR_COLOR_NONE} ${script}" + sudo killall ot-rcp || true + sudo killall ot-cli || true + sudo killall ot-cli-ftd || true + sudo killall ot-cli-mtd || true + sudo killall ot-ncp-ftd || true + sudo killall ot-ncp-mtd || true + sudo rm -rf tmp + mkdir tmp + { + sudo -E expect -df "${script}" 2>"${log_file}" + } || { + local EXIT_CODE=$? + + echo -e "\n${OTBR_COLOR_FAIL}FAIL${OTBR_COLOR_NONE} ${script}" + cat "${log_file}" >&2 + return "${EXIT_CODE}" + } + echo -e "\n${OTBR_COLOR_PASS}PASS${OTBR_COLOR_NONE} ${script}" + if [[ ${OTBR_VERBOSE} == 1 ]]; then + cat "${log_file}" >&2 + fi + done +} + +parse_args() +{ + BUILD_OT_SIM=1 + RUN_ALL_TESTS=1 + + while [[ $# -gt 0 ]]; do + case $1 in + --build-ot-sim) + BUILD_OT_SIM="$2" + shift + ;; + --one-test) + RUN_ALL_TESTS=0 + TEST_NAME="$2" + shift + ;; + esac + shift + done +} + +main() +{ + parse_args "$@" + + test_setup + + export EXP_OTBR_AGENT_PATH="${OTBR_AGENT_PATH}" + export EXP_TUN_NAME="${TUN_NAME}" + export EXP_LEADER_NODE_ID="${LEADER_NODE_ID}" + export EXP_OT_CLI_PATH="${ot_cli}" + export EXP_OT_NCP_PATH="${ot_ncp}" + + if [[ ${RUN_ALL_TESTS} == 0 ]]; then + otbr_exec_expect_script "${EXPECT_SCRIPT_DIR}/${TEST_NAME}" || die "ncp expect script failed!" + else + mapfile -t test_files < <(find "${EXPECT_SCRIPT_DIR}" -type f -name "ncp_*.exp") + otbr_exec_expect_script "${test_files[@]}" || die "ncp expect script failed!" + fi +} + +main "$@" diff --git a/tests/unit/main.cpp b/tests/unit/main.cpp deleted file mode 100644 index affea1aaefd..00000000000 --- a/tests/unit/main.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2017, 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 - -int main(int argc, const char *argv[]) -{ - return RUN_ALL_TESTS(argc, argv); -} diff --git a/tests/unit/test_mdns_mdnssd.cpp b/tests/unit/test_mdns_mdnssd.cpp deleted file mode 100644 index 6104841abd0..00000000000 --- a/tests/unit/test_mdns_mdnssd.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2018, The OpenThread Authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include "mdns/mdns_mdnssd.cpp" - -TEST_GROUP(MdnsSd){}; - -TEST(MdnsSd, TestDNSErrorToString) -{ - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_NoError)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_Unknown)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_NoSuchName)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_NoMemory)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_BadParam)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_BadReference)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_BadState)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_BadFlags)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_Unsupported)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_NotInitialized)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_AlreadyRegistered)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_NameConflict)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_Invalid)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_Firewall)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_Incompatible)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_BadInterfaceIndex)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_Refused)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_NoSuchRecord)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_NoAuth)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_NoSuchKey)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_NATTraversal)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_DoubleNAT)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_BadTime)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_BadSig)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_BadKey)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_Transient)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_ServiceNotRunning)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_NATPortMappingUnsupported)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_NATPortMappingDisabled)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_NoRouter)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_PollingMode)); - CHECK(nullptr != otbr::Mdns::DNSErrorToString(kDNSServiceErr_Timeout)); -} diff --git a/third_party/openthread/CMakeLists.txt b/third_party/openthread/CMakeLists.txt index 8ea4516e4e7..eab6e7c6007 100644 --- a/third_party/openthread/CMakeLists.txt +++ b/third_party/openthread/CMakeLists.txt @@ -46,6 +46,7 @@ set(OT_COMMISSIONER ON CACHE STRING "enable commissioner") set(OT_DAEMON ON CACHE STRING "enable daemon mode" FORCE) set(OT_DATASET_UPDATER ON CACHE STRING "enable dataset updater" FORCE) set(OT_DNS_CLIENT ON CACHE STRING "enable DNS client" FORCE) +set(OT_DNS_CLIENT_OVER_TCP OFF CACHE STRING "disable DNS query over TCP") set(OT_DNS_UPSTREAM_QUERY ${OTBR_DNS_UPSTREAM_QUERY} CACHE STRING "enable sending DNS queries to upstream" FORCE) set(OT_DNSSD_SERVER ${OTBR_DNSSD_DISCOVERY_PROXY} CACHE STRING "enable DNS-SD server support" FORCE) set(OT_ECDSA ON CACHE STRING "enable ECDSA" FORCE) @@ -67,7 +68,7 @@ set(OT_SERVICE ON CACHE STRING "enable service" FORCE) set(OT_SLAAC ON CACHE STRING "enable SLAAC" FORCE) set(OT_SRP_CLIENT ON CACHE STRING "enable SRP client" FORCE) set(OT_TARGET_OPENWRT ${OTBR_OPENWRT} CACHE STRING "target on OpenWRT" FORCE) -set(OT_TCP OFF CACHE STRING "disable TCP" FORCE) +set(OT_TCP OFF CACHE STRING "disable TCP") set(OT_TREL ${OTBR_TREL} CACHE STRING "enable TREL" FORCE) set(OT_UDP_FORWARD OFF CACHE STRING "disable udp forward" FORCE) set(OT_UPTIME ON CACHE STRING "enable uptime" FORCE) @@ -105,7 +106,6 @@ target_compile_definitions(ot-config INTERFACE "-DOPENTHREAD_CONFIG_LOG_CLI=1" "-DOPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS=3" "-DOPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE=1" - "-DOPENTHREAD_CONFIG_TCP_ENABLE=0" "-DOPENTHREAD_POSIX_CONFIG_FILE=\"${PROJECT_BINARY_DIR}/src/agent/openthread-otbr-posix-config.h\"" ) diff --git a/third_party/openthread/repo b/third_party/openthread/repo index 32f462ff34d..b42be4cff14 160000 --- a/third_party/openthread/repo +++ b/third_party/openthread/repo @@ -1 +1 @@ -Subproject commit 32f462ff34d73d8011d349387f1433d1b9305117 +Subproject commit b42be4cff14595a66f603fc83460505c176754f7