From 6f0c803670096107c96a335d574e500de302600b Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Tue, 20 Oct 2020 01:19:31 +0800 Subject: [PATCH 001/175] [dbus] fix using `dbusError` after free (#592) dbusError is freed before used in logging. This caused wrong logging message. --- src/dbus/server/dbus_agent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dbus/server/dbus_agent.cpp b/src/dbus/server/dbus_agent.cpp index 17b57fb13e7..f1535aa59cd 100644 --- a/src/dbus/server/dbus_agent.cpp +++ b/src/dbus/server/dbus_agent.cpp @@ -64,11 +64,11 @@ otbrError DBusAgent::Init(void) mThreadObject = std::unique_ptr(new DBusThreadObject(mConnection.get(), mInterfaceName, mNcp)); error = mThreadObject->Init(); exit: - dbus_error_free(&dbusError); if (error != OTBR_ERROR_NONE) { otbrLog(OTBR_LOG_ERR, "dbus error %s: %s", dbusError.name, dbusError.message); } + dbus_error_free(&dbusError); return error; } From f10bdbd466becacdaf47f0437764b8dcecdd8349 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Sat, 24 Oct 2020 11:29:00 +0800 Subject: [PATCH 002/175] [openthread] update openthread to master (#594) --- third_party/openthread/repo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/openthread/repo b/third_party/openthread/repo index dc9b032dad4..f192c6dd00f 160000 --- a/third_party/openthread/repo +++ b/third_party/openthread/repo @@ -1 +1 @@ -Subproject commit dc9b032dad4d348da389c1053457147dd2817bd8 +Subproject commit f192c6dd00f14d688ee4834e612f3270270bd92b From a85fd12b16faa28ac69ebc91381d24b8925f6b59 Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Mon, 26 Oct 2020 11:11:55 +0800 Subject: [PATCH 003/175] [docker] move to ubuntu 20.04 (#595) --- etc/docker/Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/etc/docker/Dockerfile b/etc/docker/Dockerfile index 96411c35222..217a4d57c09 100644 --- a/etc/docker/Dockerfile +++ b/etc/docker/Dockerfile @@ -25,7 +25,7 @@ # POSSIBILITY OF SUCH DAMAGE. # -FROM ubuntu:bionic +FROM ubuntu:focal ARG OT_BACKBONE_CI ARG OTBR_OPTIONS @@ -61,7 +61,7 @@ ENV OTBR_BUILD_DEPS apt-utils build-essential psmisc ninja-build cmake wget ca-c libavahi-client-dev libboost-dev libboost-filesystem-dev libboost-system-dev libjsoncpp-dev # Required for OpenThread Backbone CI -ENV OTBR_OT_BACKBONE_CI_DEPS curl ca-certificates +ENV OTBR_OT_BACKBONE_CI_DEPS curl # Required and installed during build (script/bootstrap) when RELEASE=1, could be removed ENV OTBR_NORELEASE_DEPS \ @@ -71,6 +71,7 @@ ENV OTBR_NORELEASE_DEPS \ 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) \ && ln -fs /usr/share/zoneinfo/UTC /etc/localtime \ && ./script/bootstrap \ && ./script/setup \ @@ -86,8 +87,7 @@ RUN apt-get update \ && 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/* \ - ) \ - && [ "${OT_BACKBONE_CI}" != "1" ] || apt-get install --no-install-recommends -y $OTBR_OT_BACKBONE_CI_DEPS + ) ENTRYPOINT ["/app/etc/docker/docker_entrypoint.sh"] From 474a2abe7d9a5bd6e18749e92780fe71a626117d Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Mon, 26 Oct 2020 08:14:22 -0700 Subject: [PATCH 004/175] [openthread] update to 7a24666 (#596) --- third_party/openthread/repo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/openthread/repo b/third_party/openthread/repo index f192c6dd00f..7a24666bf45 160000 --- a/third_party/openthread/repo +++ b/third_party/openthread/repo @@ -1 +1 @@ -Subproject commit f192c6dd00f14d688ee4834e612f3270270bd92b +Subproject commit 7a24666bf45b92f2a2bedd0559411c7ce019832c From 3dae3a3f37a3a3ca1fe9e0d6bd2fed2625872c40 Mon Sep 17 00:00:00 2001 From: kangping Date: Tue, 27 Oct 2020 22:56:10 +0800 Subject: [PATCH 005/175] [cmake] fix conditional inclusion of REST dependencies (#597) --- src/rest/CMakeLists.txt | 4 ++-- third_party/CMakeLists.txt | 2 +- third_party/http-parser/CMakeLists.txt | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/rest/CMakeLists.txt b/src/rest/CMakeLists.txt index 0f889be4424..63715c409e5 100644 --- a/src/rest/CMakeLists.txt +++ b/src/rest/CMakeLists.txt @@ -26,7 +26,7 @@ # POSSIBILITY OF SUCH DAMAGE. # -add_library( otbr-rest +add_library(otbr-rest rest_web_server.cpp connection.cpp resource.cpp @@ -36,7 +36,7 @@ add_library( otbr-rest response.cpp ) -target_link_libraries(otbr-rest +target_link_libraries(otbr-rest PUBLIC http_parser PRIVATE diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index 829b11e4eb3..8e8aaf77a23 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -27,7 +27,7 @@ # add_subdirectory(openthread) -if(OTBR_WEB) +if(OTBR_REST) add_subdirectory(cJSON) add_subdirectory(http-parser) endif() diff --git a/third_party/http-parser/CMakeLists.txt b/third_party/http-parser/CMakeLists.txt index ccf67563fe0..720b0077836 100644 --- a/third_party/http-parser/CMakeLists.txt +++ b/third_party/http-parser/CMakeLists.txt @@ -28,9 +28,9 @@ project(http_parser C) -add_library(http_parser - STATIC - repo/http_parser.c +add_library(http_parser + STATIC + repo/http_parser.c repo/http_parser.h ) From 8609c03615f705add42ce32a7a2305c1bf59b09d Mon Sep 17 00:00:00 2001 From: Moandor Date: Tue, 27 Oct 2020 23:00:39 +0800 Subject: [PATCH 006/175] [docker] add backbone CI dependency (#599) --- etc/docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/docker/Dockerfile b/etc/docker/Dockerfile index 217a4d57c09..e2955bd1c0f 100644 --- a/etc/docker/Dockerfile +++ b/etc/docker/Dockerfile @@ -61,7 +61,7 @@ ENV OTBR_BUILD_DEPS apt-utils build-essential psmisc ninja-build cmake wget ca-c libavahi-client-dev libboost-dev libboost-filesystem-dev libboost-system-dev libjsoncpp-dev # Required for OpenThread Backbone CI -ENV OTBR_OT_BACKBONE_CI_DEPS curl +ENV OTBR_OT_BACKBONE_CI_DEPS curl lcov # Required and installed during build (script/bootstrap) when RELEASE=1, could be removed ENV OTBR_NORELEASE_DEPS \ From 693483e086d8802c6ac192596ec08d654af0fd86 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Wed, 28 Oct 2020 23:37:56 +0800 Subject: [PATCH 007/175] [backbone-router] add Backbone multicast routing (#532) This commit uses smcroute to implement multicast forwarding for MLR Listeners. Major changes include: - Implement multicast routing using smcroute - Install/uninstall smcroute in script/setup - Add OTBR_BACKBONE_ROUTER option and otbr-backbone-router library - Add new Dockerfile ARGs: BACKBONE_ROUTER and NAT64 --- .github/workflows/build.yml | 9 +- Android.mk | 1 + etc/docker/Dockerfile | 5 +- examples/platforms/beagleboneblack/default | 1 + examples/platforms/fedora/default | 1 + examples/platforms/raspbian/default | 1 + examples/platforms/ubuntu/default | 1 + script/_otbr | 17 +- script/_smcroute | 59 +++++++ script/bootstrap | 7 +- script/setup | 3 + script/update | 3 + src/CMakeLists.txt | 3 + src/agent/CMakeLists.txt | 3 + src/agent/agent_instance.cpp | 2 +- src/agent/agent_instance.hpp | 1 + src/agent/border_agent.cpp | 14 +- src/agent/border_agent.hpp | 5 + src/agent/instance_params.cpp | 45 +++++ src/agent/instance_params.hpp | 105 +++++++++++ src/agent/main.cpp | 12 +- src/agent/ncp.hpp | 14 +- src/agent/ncp_openthread.cpp | 28 +++ src/agent/ncp_openthread.hpp | 7 + src/backbone_router/CMakeLists.txt | 37 ++++ src/backbone_router/backbone_agent.cpp | 161 +++++++++++++++++ src/backbone_router/backbone_agent.hpp | 99 +++++++++++ src/backbone_router/smcroute_manager.cpp | 192 +++++++++++++++++++++ src/backbone_router/smcroute_manager.hpp | 127 ++++++++++++++ src/common/CMakeLists.txt | 3 + src/common/code_utils.hpp | 36 ++++ src/common/logging.cpp | 5 - src/common/logging.hpp | 12 +- src/common/types.cpp | 58 +++++++ src/common/types.hpp | 32 +++- src/utils/CMakeLists.txt | 1 + src/utils/system_utils.cpp | 67 +++++++ src/utils/system_utils.hpp | 62 +++++++ tests/mdns/CMakeLists.txt | 1 + third_party/openthread/repo | 2 +- 40 files changed, 1204 insertions(+), 38 deletions(-) create mode 100644 script/_smcroute create mode 100644 src/agent/instance_params.cpp create mode 100644 src/agent/instance_params.hpp create mode 100644 src/backbone_router/CMakeLists.txt create mode 100644 src/backbone_router/backbone_agent.cpp create mode 100644 src/backbone_router/backbone_agent.hpp create mode 100644 src/backbone_router/smcroute_manager.cpp create mode 100644 src/backbone_router/smcroute_manager.hpp create mode 100644 src/common/types.cpp create mode 100644 src/utils/system_utils.cpp create mode 100644 src/utils/system_utils.hpp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ac6b27f6628..2ae58a45147 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -169,9 +169,14 @@ jobs: submodules: true - name: Build OTBR Docker Image run: | - otbr_options="-DOTBR_BACKBONE_ROUTER=ON -DOT_DUA=ON -DOT_MLR=ON -DOTBR_COVERAGE=ON" + otbr_options="-DOT_DUA=ON -DOT_MLR=ON -DOTBR_COVERAGE=ON" otbr_image_name="otbr-ot12-backbone-ci" - docker build -t "${otbr_image_name}" -f etc/docker/Dockerfile . --build-arg REFERENCE_DEVICE=1 --build-arg OT_BACKBONE_CI=1 --build-arg OTBR_OPTIONS="${otbr_options}" + docker build -t "${otbr_image_name}" -f etc/docker/Dockerfile . \ + --build-arg BACKBONE_ROUTER=1 \ + --build-arg REFERENCE_DEVICE=${REFERENCE_DEVICE} \ + --build-arg OT_BACKBONE_CI=1 \ + --build-arg NAT64=0 \ + --build-arg OTBR_OPTIONS="${otbr_options}" - name: Bootstrap OpenThread Test run: | sudo rm /etc/apt/sources.list.d/* && sudo apt-get update diff --git a/Android.mk b/Android.mk index e89bae9a9eb..3cd4b01310c 100644 --- a/Android.mk +++ b/Android.mk @@ -92,6 +92,7 @@ LOCAL_CPPFLAGS += -std=c++14 LOCAL_SRC_FILES := \ src/agent/agent_instance.cpp \ + src/agent/instance_params.cpp \ src/agent/border_agent.cpp \ src/agent/main.cpp \ src/agent/ncp_openthread.cpp \ diff --git a/etc/docker/Dockerfile b/etc/docker/Dockerfile index e2955bd1c0f..25e328ae9c6 100644 --- a/etc/docker/Dockerfile +++ b/etc/docker/Dockerfile @@ -27,6 +27,7 @@ FROM ubuntu:focal +ARG BACKBONE_ROUTER ARG OT_BACKBONE_CI ARG OTBR_OPTIONS ARG DNS64 @@ -34,6 +35,7 @@ ARG NAT64 ARG REFERENCE_DEVICE ARG RELEASE +ENV BACKBONE_ROUTER=${BACKBONE_ROUTER:-0} ENV OT_BACKBONE_CI=${OT_BACKBONE_CI:-0} ENV OTBR_OPTIONS=${OTBR_OPTIONS} ENV DEBIAN_FRONTEND noninteractive @@ -58,7 +60,8 @@ 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 \ - libavahi-client-dev libboost-dev libboost-filesystem-dev libboost-system-dev libjsoncpp-dev + libavahi-client-dev libboost-dev libboost-filesystem-dev libboost-system-dev libjsoncpp-dev \ + autoconf automake pkg-config # Required for OpenThread Backbone CI ENV OTBR_OT_BACKBONE_CI_DEPS curl lcov diff --git a/examples/platforms/beagleboneblack/default b/examples/platforms/beagleboneblack/default index 6fe536ae60a..192d241f80d 100644 --- a/examples/platforms/beagleboneblack/default +++ b/examples/platforms/beagleboneblack/default @@ -38,3 +38,4 @@ DHCPV6_PD=1 NETWORK_MANAGER=1 # disabled unless specifically added for the device NETWORK_MANAGER_WIFI=0 +BACKBONE_ROUTER=0 diff --git a/examples/platforms/fedora/default b/examples/platforms/fedora/default index 7c4468e7316..1d732f78ded 100644 --- a/examples/platforms/fedora/default +++ b/examples/platforms/fedora/default @@ -32,3 +32,4 @@ NAT64=0 DNS64=0 DHCPV6_PD=0 NETWORK_MANAGER=0 +BACKBONE_ROUTER=0 diff --git a/examples/platforms/raspbian/default b/examples/platforms/raspbian/default index bc8dce30cbe..7e518a4a442 100644 --- a/examples/platforms/raspbian/default +++ b/examples/platforms/raspbian/default @@ -32,3 +32,4 @@ NAT64=1 DNS64=1 DHCPV6_PD=1 NETWORK_MANAGER=1 +BACKBONE_ROUTER=0 diff --git a/examples/platforms/ubuntu/default b/examples/platforms/ubuntu/default index fce15a150e1..7f7b5d4adc9 100644 --- a/examples/platforms/ubuntu/default +++ b/examples/platforms/ubuntu/default @@ -32,3 +32,4 @@ NAT64=1 DNS64=1 DHCPV6_PD=0 NETWORK_MANAGER=0 +BACKBONE_ROUTER=0 diff --git a/script/_otbr b/script/_otbr index 4392276e2c8..772fd752539 100644 --- a/script/_otbr +++ b/script/_otbr @@ -30,7 +30,8 @@ readonly OTBR_TOP_BUILDDIR="${BUILD_DIR}/otbr" readonly OTBR_TOP_SRCDIR="$PWD" readonly OTBR_OPTIONS="${OTBR_OPTIONS:-}" -readonly REFERENCE_DEVICE=${REFERENCE_DEVICE:-0} +readonly REFERENCE_DEVICE="${REFERENCE_DEVICE:-0}" +readonly BACKBONE_ROUTER="${BACKBONE_ROUTER:-0}" otbr_uninstall() { @@ -53,13 +54,6 @@ otbr_uninstall() fi } -install_reference_device_deps() -{ - with REFERENCE_DEVICE || return 0 - - sudo apt-get install -y --no-install-recommends radvd -} - otbr_install() { local otbr_options=() @@ -82,6 +76,11 @@ otbr_install() "-DOT_REFERENCE_DEVICE=ON" ) fi + if [[ ${BACKBONE_ROUTER} == "1" ]]; then + otbr_options+=( + "-DOTBR_BACKBONE_ROUTER=ON" + ) + fi (mkdir -p "${OTBR_TOP_BUILDDIR}" \ && cd "${OTBR_TOP_BUILDDIR}" \ @@ -98,8 +97,6 @@ otbr_install() else echo >&2 ' *** WARNING: systemctl not found. otbr cannot start on boot.' fi - - install_reference_device_deps } otbr_update() diff --git a/script/_smcroute b/script/_smcroute new file mode 100644 index 00000000000..714c764bfde --- /dev/null +++ b/script/_smcroute @@ -0,0 +1,59 @@ +#!/bin/bash +# +# 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. +# +# Description: +# This script manipulates smcroute configuration. +# + +smcroute_uninstall() +{ + with BACKBONE_ROUTER || return 0 + + sudo smcroutectl kill || true + + test -d "$BUILD_DIR"/smcroute || return 0 + + (cd "$BUILD_DIR"/smcroute \ + && (test ! -f config.status || sudo make uninstall)) +} + +smcroute_install() +{ + with BACKBONE_ROUTER || return 0 + + test -d "$BUILD_DIR"/smcroute || (cd "$BUILD_DIR" \ + && git clone -b ip6_mf --depth 1 https://github.com/librasungirl/smcroute.git) || die 'Failed to download source code of SMCRoute!' + + ( + cd "$BUILD_DIR"/smcroute || return 1 + test -f configure || ./autogen.sh + test -f config.status || ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var + make + sudo make install + ) +} diff --git a/script/bootstrap b/script/bootstrap index 3f3cb6de5a4..dae7d568581 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -43,7 +43,7 @@ install_packages_apt() libreadline-dev \ libncurses-dev - sudo apt-get install --no-install-recommends -y build-essential ninja-build cmake + sudo apt-get install --no-install-recommends -y build-essential ninja-build cmake automake autoconf pkg-config with RELEASE || sudo apt-get install --no-install-recommends -y libcpputest-dev @@ -86,6 +86,9 @@ install_packages_apt() # libjsoncpp sudo apt-get install --no-install-recommends -y libjsoncpp1 libjsoncpp-dev + + # reference device + without REFERENCE_DEVICE || sudo apt-get install --no-install-recommends -y radvd } install_packages_opkg() @@ -100,7 +103,7 @@ install_packages_rpm() else PM=yum fi - sudo $PM install -y gcc gcc-c++ + sudo $PM install -y gcc gcc-c++ automake autoconf pkg-config with RELEASE || sudo $PM install -y cmake ninja-build sudo $PM install -y dbus-devel sudo $PM install -y avahi avahi-devel diff --git a/script/setup b/script/setup index 480db78b6e9..2a77dcbada1 100755 --- a/script/setup +++ b/script/setup @@ -38,6 +38,7 @@ . script/_dns64 . script/_dhcpv6_pd . script/_network_manager +. script/_smcroute . script/_swapfile . script/_sudo_extend . script/_disable_services @@ -53,9 +54,11 @@ main() dhcpv6_pd_uninstall nat64_uninstall dns64_uninstall + smcroute_uninstall ipforward_uninstall ipforward_install + smcroute_install nat64_install dns64_install network_manager_install diff --git a/script/update b/script/update index a920f54929d..698e409a915 100755 --- a/script/update +++ b/script/update @@ -38,6 +38,7 @@ . script/_nat64 . script/_dns64 . script/_dhcpv6_pd +. script/_smcroute main() { @@ -48,9 +49,11 @@ main() dhcpv6_pd_uninstall nat64_uninstall dns64_uninstall + smcroute_uninstall ipforward_uninstall ipforward_install + smcroute_install nat64_install dns64_install dhcpv6_pd_install diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 21a5c199522..e9c186b94cb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -51,3 +51,6 @@ if(OTBR_REST) add_subdirectory(rest) endif() +if (OTBR_BACKBONE_ROUTER) + add_subdirectory(backbone_router) +endif() diff --git a/src/agent/CMakeLists.txt b/src/agent/CMakeLists.txt index 99236a5b888..4ddb760d03a 100644 --- a/src/agent/CMakeLists.txt +++ b/src/agent/CMakeLists.txt @@ -38,6 +38,8 @@ add_executable(otbr-agent ncp_openthread.hpp thread_helper.cpp thread_helper.hpp + instance_params.cpp + instance_params.hpp ) target_link_libraries(otbr-agent PRIVATE @@ -45,6 +47,7 @@ target_link_libraries(otbr-agent PRIVATE $<$:otbr-mdns> $<$:otbr-ubus> $<$:otbr-rest> + $<$:otbr-backbone-router> openthread-cli-ftd openthread-ftd openthread-posix diff --git a/src/agent/agent_instance.cpp b/src/agent/agent_instance.cpp index 1fd7962e32c..b84fca0dca6 100644 --- a/src/agent/agent_instance.cpp +++ b/src/agent/agent_instance.cpp @@ -55,7 +55,7 @@ otbrError AgentInstance::Init(void) mBorderAgent.Init(); exit: - otbrLogResult("Initialize OpenThread Border Router Agent", error); + otbrLogResult(error, "Initialize OpenThread Border Router Agent"); return error; } diff --git a/src/agent/agent_instance.hpp b/src/agent/agent_instance.hpp index 27853de8a26..950a699b10c 100644 --- a/src/agent/agent_instance.hpp +++ b/src/agent/agent_instance.hpp @@ -42,6 +42,7 @@ #include #include "agent/border_agent.hpp" +#include "agent/instance_params.hpp" #include "agent/ncp.hpp" namespace otbr { diff --git a/src/agent/border_agent.cpp b/src/agent/border_agent.cpp index 9df1fb5ffd1..49a39890a55 100644 --- a/src/agent/border_agent.cpp +++ b/src/agent/border_agent.cpp @@ -46,6 +46,7 @@ #include "agent/border_agent.hpp" #include "agent/ncp.hpp" +#include "agent/ncp_openthread.hpp" #include "agent/uris.hpp" #include "common/code_utils.hpp" #include "common/logging.hpp" @@ -87,6 +88,9 @@ BorderAgent::BorderAgent(Ncp::Controller *aNcp) : mPublisher(nullptr) #endif , mNcp(aNcp) +#if OTBR_ENABLE_BACKBONE_ROUTER + , mBackboneAgent(*reinterpret_cast(aNcp)) +#endif , mThreadStarted(false) { } @@ -106,8 +110,12 @@ void BorderAgent::Init(void) mNcp->On(Ncp::kEventThreadState, HandleThreadState, this); mNcp->On(Ncp::kEventPSKc, HandlePSKc, this); - otbrLogResult("Check if Thread is up", mNcp->RequestEvent(Ncp::kEventThreadState)); - otbrLogResult("Check if PSKc is initialized", mNcp->RequestEvent(Ncp::kEventPSKc)); +#if OTBR_ENABLE_BACKBONE_ROUTER + mBackboneAgent.Init(); +#endif + + otbrLogResult(mNcp->RequestEvent(Ncp::kEventThreadState), "Check if Thread is up"); + otbrLogResult(mNcp->RequestEvent(Ncp::kEventPSKc), "Check if PSKc is initialized"); } otbrError BorderAgent::Start(void) @@ -131,7 +139,7 @@ otbrError BorderAgent::Start(void) ExitNow(); exit: - otbrLogResult("Start Thread Border Agent", error); + otbrLogResult(error, "Start Thread Border Agent"); return error; } diff --git a/src/agent/border_agent.hpp b/src/agent/border_agent.hpp index ae58a4fde00..96115f01e89 100644 --- a/src/agent/border_agent.hpp +++ b/src/agent/border_agent.hpp @@ -36,7 +36,9 @@ #include +#include "agent/instance_params.hpp" #include "agent/ncp.hpp" +#include "backbone_router/backbone_agent.hpp" #include "mdns/mdns.hpp" namespace otbr { @@ -134,6 +136,9 @@ class BorderAgent Mdns::Publisher *mPublisher; Ncp::Controller *mNcp; +#if OTBR_ENABLE_BACKBONE_ROUTER + BackboneRouter::BackboneAgent mBackboneAgent; +#endif uint8_t mExtPanId[kSizeExtPanId]; bool mExtPanIdInitialized; diff --git a/src/agent/instance_params.cpp b/src/agent/instance_params.cpp new file mode 100644 index 00000000000..776193b6fd6 --- /dev/null +++ b/src/agent/instance_params.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * The file implements the agent instance parameters. + */ + +#include "agent/instance_params.hpp" + +namespace otbr { + +InstanceParams &InstanceParams::Get(void) +{ + static InstanceParams sInstanceParams; + + return sInstanceParams; +} + +} // namespace otbr diff --git a/src/agent/instance_params.hpp b/src/agent/instance_params.hpp new file mode 100644 index 00000000000..1cc25afe4b3 --- /dev/null +++ b/src/agent/instance_params.hpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2020, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes definition for Thread border router agent instance parameters. + */ + +#ifndef OTBR_AGENT_INSATNCE_PARAMS_HPP_ +#define OTBR_AGENT_INSATNCE_PARAMS_HPP_ + +namespace otbr { + +/** + * This class represents the agent instance parameters. + * + */ +class InstanceParams +{ +public: + /** + * This method gets the single `InstanceParams` instance. + * + * @returns The single `InstanceParams` instance. + * + */ + static InstanceParams &Get(void); + + /** + * This method sets the Thread network interface name. + * + * @param[in] aName The Thread network interface name. + * + */ + void SetThreadIfName(const char *aName) { mThreadIfName = aName; } + + /** + * This method gets the Thread network interface name. + * + * @returns The Thread network interface name. + * + */ + const char *GetThreadIfName(void) const { return mThreadIfName; } + +#if OTBR_ENABLE_BACKBONE_ROUTER + /** + * This method sets the Backbone network interface name. + * + * @param[in] aName The Backbone network interface name. + * + */ + void SetBackboneIfName(const char *aName) { mBackboneIfName = aName; } + + /** + * This method gets the Backbone network interface name. + * + * @returns The Backbone network interface name. + * + */ + const char *GetBackboneIfName(void) const { return mBackboneIfName; } +#endif + +private: + InstanceParams() + : mThreadIfName(nullptr) +#if OTBR_ENABLE_BACKBONE_ROUTER + , mBackboneIfName(nullptr) +#endif + { + } + + const char *mThreadIfName; +#if OTBR_ENABLE_BACKBONE_ROUTER + const char *mBackboneIfName; +#endif +}; + +} // namespace otbr + +#endif // OTBR_AGENT_INSATNCE_PARAMS_HPP_ diff --git a/src/agent/main.cpp b/src/agent/main.cpp index a60c28d7904..2e8c571df16 100644 --- a/src/agent/main.cpp +++ b/src/agent/main.cpp @@ -219,7 +219,7 @@ int main(int argc, char *argv[]) int opt; int ret = EXIT_SUCCESS; const char * interfaceName = kDefaultInterfaceName; - const char * backboneInterfaceName = nullptr; + const char * backboneInterfaceName = ""; otbr::Ncp::Controller *ncp = nullptr; bool verbose = false; bool printRadioVersion = false; @@ -282,12 +282,18 @@ int main(int argc, char *argv[]) VerifyOrExit(ncp != nullptr, ret = EXIT_FAILURE); otbrLog(OTBR_LOG_INFO, "Thread interface %s", interfaceName); - otbrLog(OTBR_LOG_INFO, "Backbone interface %s", - backboneInterfaceName == nullptr ? "(null)" : backboneInterfaceName); +#if OTBR_ENABLE_BACKBONE_ROUTER + otbrLog(OTBR_LOG_INFO, "Backbone interface %s", backboneInterfaceName); +#endif { otbr::AgentInstance instance(ncp); + otbr::InstanceParams::Get().SetThreadIfName(interfaceName); +#if OTBR_ENABLE_BACKBONE_ROUTER + otbr::InstanceParams::Get().SetBackboneIfName(backboneInterfaceName); +#endif + SuccessOrExit(ret = instance.Init()); if (printRadioVersion) diff --git a/src/agent/ncp.hpp b/src/agent/ncp.hpp index ddb8bda1c56..8dbd1b9d1ef 100644 --- a/src/agent/ncp.hpp +++ b/src/agent/ncp.hpp @@ -62,12 +62,14 @@ namespace Ncp { */ enum { - kEventExtPanId, ///< Extended PAN ID arrived. - kEventNetworkName, ///< Network name arrived. - kEventPSKc, ///< PSKc arrived. - kEventThreadState, ///< Thread State. - kEventThreadVersion, ///< Thread Version. - kEventUdpForwardStream, ///< UDP forward stream arrived. + kEventExtPanId, ///< Extended PAN ID arrived. + kEventNetworkName, ///< Network name arrived. + kEventPSKc, ///< PSKc arrived. + kEventThreadState, ///< Thread State. + kEventThreadVersion, ///< Thread Version. + kEventUdpForwardStream, ///< UDP forward stream arrived. + kEventBackboneRouterState, ///< Backbone Router State. + kEventBackboneRouterMulticastListenerEvent, ///< Backbone Router Multicast Listener event arrived. }; /** diff --git a/src/agent/ncp_openthread.cpp b/src/agent/ncp_openthread.cpp index 446cd0c6d9a..cd8837b5845 100644 --- a/src/agent/ncp_openthread.cpp +++ b/src/agent/ncp_openthread.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -122,6 +123,11 @@ otbrError ControllerOpenThread::Init(void) VerifyOrExit(result == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD); } +#if OTBR_ENABLE_BACKBONE_ROUTER + otBackboneRouterSetMulticastListenerCallback( + mInstance, &ControllerOpenThread::HandleBackboneRouterMulticastListenerEvent, this); +#endif + mThreadHelper = std::unique_ptr(new otbr::agent::ThreadHelper(mInstance, this)); exit: @@ -166,6 +172,13 @@ void ControllerOpenThread::HandleStateChanged(otChangedFlags aFlags) EventEmitter::Emit(kEventThreadState, attached); } +#if OTBR_ENABLE_BACKBONE_ROUTER + if (aFlags & OT_CHANGED_THREAD_BACKBONE_ROUTER_STATE) + { + EventEmitter::Emit(kEventBackboneRouterState); + } +#endif + mThreadHelper->StateChangedCallback(aFlags); } @@ -306,6 +319,21 @@ void ControllerOpenThread::RegisterResetHandler(std::function aHandl mResetHandlers.emplace_back(std::move(aHandler)); } +#if OTBR_ENABLE_BACKBONE_ROUTER +void ControllerOpenThread::HandleBackboneRouterMulticastListenerEvent(void * aContext, + otBackboneRouterMulticastListenerEvent aEvent, + const otIp6Address * aAddress) +{ + static_cast(aContext)->HandleBackboneRouterMulticastListenerEvent(aEvent, aAddress); +} + +void ControllerOpenThread::HandleBackboneRouterMulticastListenerEvent(otBackboneRouterMulticastListenerEvent aEvent, + const otIp6Address * aAddress) +{ + EventEmitter::Emit(kEventBackboneRouterMulticastListenerEvent, aEvent, aAddress); +} +#endif + Controller *Controller::Create(const char *aInterfaceName, const char *aRadioUrl, const char *aBackboneInterfaceName) { return new ControllerOpenThread(aInterfaceName, aRadioUrl, aBackboneInterfaceName); diff --git a/src/agent/ncp_openthread.hpp b/src/agent/ncp_openthread.hpp index f72e06089dd..9e7817ee77a 100644 --- a/src/agent/ncp_openthread.hpp +++ b/src/agent/ncp_openthread.hpp @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -155,6 +156,12 @@ class ControllerOpenThread : public Controller } void HandleStateChanged(otChangedFlags aFlags); + static void HandleBackboneRouterMulticastListenerEvent(void * aContext, + otBackboneRouterMulticastListenerEvent aEvent, + const otIp6Address * aAddress); + void HandleBackboneRouterMulticastListenerEvent(otBackboneRouterMulticastListenerEvent aEvent, + const otIp6Address * aAddress); + otInstance *mInstance; otPlatformConfig mConfig; diff --git a/src/backbone_router/CMakeLists.txt b/src/backbone_router/CMakeLists.txt new file mode 100644 index 00000000000..7614ccd7fe9 --- /dev/null +++ b/src/backbone_router/CMakeLists.txt @@ -0,0 +1,37 @@ +# +# 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. +# + +add_library(otbr-backbone-router + backbone_agent.cpp + smcroute_manager.cpp +) + +target_link_libraries(otbr-backbone-router PRIVATE + otbr-common + otbr-utils +) diff --git a/src/backbone_router/backbone_agent.cpp b/src/backbone_router/backbone_agent.cpp new file mode 100644 index 00000000000..da269e8d60b --- /dev/null +++ b/src/backbone_router/backbone_agent.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2020, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * The file implements the Thread Backbone agent. + */ + +#include "backbone_router/backbone_agent.hpp" + +#include +#include + +#include "common/code_utils.hpp" + +namespace otbr { +namespace BackboneRouter { + +BackboneAgent::BackboneAgent(otbr::Ncp::ControllerOpenThread &aNcp) + : mNcp(aNcp) + , mBackboneRouterState(OT_BACKBONE_ROUTER_STATE_DISABLED) +{ +} + +void BackboneAgent::Init(void) +{ + mNcp.On(Ncp::kEventBackboneRouterState, HandleBackboneRouterState, this); + mNcp.On(Ncp::kEventBackboneRouterMulticastListenerEvent, HandleBackboneRouterMulticastListenerEvent, this); + + mSMCRouteManager.Init(); + + HandleBackboneRouterState(); +} + +void BackboneAgent::HandleBackboneRouterState(void *aContext, int aEvent, va_list aArguments) +{ + OT_UNUSED_VARIABLE(aEvent); + OT_UNUSED_VARIABLE(aArguments); + + assert(aEvent == Ncp::kEventBackboneRouterState); + + static_cast(aContext)->HandleBackboneRouterState(); +} + +void BackboneAgent::HandleBackboneRouterState(void) +{ + otBackboneRouterState state = otBackboneRouterGetState(mNcp.GetInstance()); + bool wasPrimary = (mBackboneRouterState == OT_BACKBONE_ROUTER_STATE_PRIMARY); + + otbrLog(OTBR_LOG_DEBUG, "BackboneAgent: HandleBackboneRouterState: state=%d, mBackboneRouterState=%d", state, + mBackboneRouterState); + VerifyOrExit(mBackboneRouterState != state); + + mBackboneRouterState = state; + + if (IsPrimary()) + { + OnBecomePrimary(); + } + else if (wasPrimary) + { + OnResignPrimary(); + } + +exit: + return; +} + +void BackboneAgent::HandleBackboneRouterMulticastListenerEvent(void *aContext, int aEvent, va_list aArguments) +{ + OT_UNUSED_VARIABLE(aEvent); + + otBackboneRouterMulticastListenerEvent event; + const otIp6Address * address; + + assert(aEvent == Ncp::kEventBackboneRouterMulticastListenerEvent); + + event = static_cast(va_arg(aArguments, int)); + address = va_arg(aArguments, const otIp6Address *); + static_cast(aContext)->HandleBackboneRouterMulticastListenerEvent(event, *address); +} + +void BackboneAgent::HandleBackboneRouterMulticastListenerEvent(otBackboneRouterMulticastListenerEvent aEvent, + const otIp6Address & aAddress) +{ + otbrLog(OTBR_LOG_INFO, "BackboneAgent: Multicast Listener event: %d, address: %s, state: %s", aEvent, + Ip6Address(aAddress).ToString().c_str(), StateToString(mBackboneRouterState)); + + switch (aEvent) + { + case OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ADDED: + mSMCRouteManager.Add(Ip6Address(aAddress)); + break; + case OT_BACKBONE_ROUTER_MULTICAST_LISTENER_REMOVED: + mSMCRouteManager.Remove(Ip6Address(aAddress)); + break; + } +} + +void BackboneAgent::OnBecomePrimary(void) +{ + otbrLog(OTBR_LOG_NOTICE, "BackboneAgent: Backbone Router becomes Primary!"); + + mSMCRouteManager.Enable(); +} + +void BackboneAgent::OnResignPrimary(void) +{ + otbrLog(OTBR_LOG_NOTICE, "BackboneAgent: Backbone Router resigns Primary to %s!", + StateToString(mBackboneRouterState)); + + mSMCRouteManager.Disable(); +} + +const char *BackboneAgent::StateToString(otBackboneRouterState aState) +{ + const char *ret = "Unknown"; + + switch (aState) + { + case OT_BACKBONE_ROUTER_STATE_DISABLED: + ret = "Disabled"; + break; + case OT_BACKBONE_ROUTER_STATE_SECONDARY: + ret = "Secondary"; + break; + case OT_BACKBONE_ROUTER_STATE_PRIMARY: + ret = "Primary"; + break; + } + + return ret; +} + +} // namespace BackboneRouter +} // namespace otbr diff --git a/src/backbone_router/backbone_agent.hpp b/src/backbone_router/backbone_agent.hpp new file mode 100644 index 00000000000..1d8cd9a5390 --- /dev/null +++ b/src/backbone_router/backbone_agent.hpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2020, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes definition for Thread Backbone agent. + */ + +#ifndef BACKBONE_ROUTER_BACKBONE_AGENT_HPP_ +#define BACKBONE_ROUTER_BACKBONE_AGENT_HPP_ + +#include + +#include "agent/instance_params.hpp" +#include "agent/ncp_openthread.hpp" +#include "backbone_router/smcroute_manager.hpp" + +namespace otbr { +namespace BackboneRouter { + +/** + * @addtogroup border-router-backbone + * + * @brief + * This module includes definition for Thread Backbone agent. + * + * @{ + */ + +/** + * This class implements Thread Backbone agent functionality. + * + */ +class BackboneAgent +{ +public: + /** + * This constructor intiializes the `BackboneAgent` instance. + * + * @param[in] aNcp The Thread instance. + * + */ + BackboneAgent(otbr::Ncp::ControllerOpenThread &aNcp); + + /** + * This method initializes the Backbone agent. + * + */ + void Init(void); + +private: + void OnBecomePrimary(void); + void OnResignPrimary(void); + bool IsPrimary(void) const { return mBackboneRouterState == OT_BACKBONE_ROUTER_STATE_PRIMARY; } + static void HandleBackboneRouterState(void *aContext, int aEvent, va_list aArguments); + void HandleBackboneRouterState(void); + static void HandleBackboneRouterMulticastListenerEvent(void *aContext, int aEvent, va_list aArguments); + void HandleBackboneRouterMulticastListenerEvent(otBackboneRouterMulticastListenerEvent aEvent, + const otIp6Address & aAddress); + static const char *StateToString(otBackboneRouterState aState); + + otbr::Ncp::ControllerOpenThread &mNcp; + otBackboneRouterState mBackboneRouterState; + SMCRouteManager mSMCRouteManager; +}; + +#endif // OTBR_ENABLE_BACKBONE_ROUTER + +/** + * @} + */ + +} // namespace BackboneRouter +} // namespace otbr diff --git a/src/backbone_router/smcroute_manager.cpp b/src/backbone_router/smcroute_manager.cpp new file mode 100644 index 00000000000..f2a774ab3d5 --- /dev/null +++ b/src/backbone_router/smcroute_manager.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2020, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * The file implements the SMCRoute manager. + */ + +#include "backbone_router/smcroute_manager.hpp" + +#include +#include + +#include + +#include "common/code_utils.hpp" +#include "utils/system_utils.hpp" + +namespace otbr { + +namespace BackboneRouter { + +void SMCRouteManager::Init(void) +{ + assert(!mEnabled); + + StartSMCRouteService(); +} + +void SMCRouteManager::Enable(void) +{ + otbrError error = OTBR_ERROR_NONE; + + VerifyOrExit(!mEnabled); + + mEnabled = true; + + Flush(); + + // Add mroute rules: 65520 (0xfff0) allow outbound for MA scope >= admin (4) + SuccessOrExit(error = AllowOutboundMulticast()); + + // Add mroute rules for the current Multicast Listeners Table + for (const Ip6Address &address : mListenerSet) + { + SuccessOrExit(error = AddRoute(address)); + } + +exit: + otbrLogResult(error, "SMCRouteManager: %s", __FUNCTION__); +} + +void SMCRouteManager::Disable(void) +{ + otbrError error = OTBR_ERROR_NONE; + + VerifyOrExit(mEnabled); + + mEnabled = false; + + Flush(); + + // Remove mroute rules for the current Multicast Listeners Table + for (const Ip6Address &address : mListenerSet) + { + SuccessOrExit(error = DeleteRoute(address)); + } + + // Remove mroute rules: forbid outbound Multicast traffic + SuccessOrExit(error = ForbidOutboundMulticast()); + +exit: + otbrLogResult(error, "SMCRouteManager: %s", __FUNCTION__); +} + +void SMCRouteManager::StartSMCRouteService(void) +{ + otbrError error = OTBR_ERROR_NONE; + std::chrono::system_clock::time_point deadline; + + VerifyOrExit(SystemUtils::ExecuteCommand("smcroutectl kill || true") == 0, error = OTBR_ERROR_SMCROUTE); + VerifyOrExit(SystemUtils::ExecuteCommand("smcrouted") == 0, error = OTBR_ERROR_SMCROUTE); + + deadline = std::chrono::system_clock::now() + std::chrono::seconds(10); + + while (std::chrono::system_clock::now() < deadline) + { + usleep(10000); + + VerifyOrExit((error = Flush()) != OTBR_ERROR_NONE); + } + +exit: + SuccessOrDie(error, "Failed to start SMCRoute service"); +} + +void SMCRouteManager::Add(const Ip6Address &aAddress) +{ + otbrError error = OTBR_ERROR_NONE; + + assert(mListenerSet.find(aAddress) == mListenerSet.end()); + mListenerSet.insert(aAddress); + + VerifyOrExit(mEnabled); + + Flush(); + error = AddRoute(aAddress); + +exit: + otbrLogResult(error, "SMCRouteManager: AddRoute %s", aAddress.ToString().c_str()); +} + +void SMCRouteManager::Remove(const Ip6Address &aAddress) +{ + otbrError error = OTBR_ERROR_NONE; + + assert(mListenerSet.find(aAddress) != mListenerSet.end()); + mListenerSet.erase(aAddress); + + VerifyOrExit(mEnabled); + + Flush(); + error = DeleteRoute(aAddress); +exit: + otbrLogResult(error, "SMCRouteManager: RemoveRoute %s", aAddress.ToString().c_str()); +} + +otbrError SMCRouteManager::AllowOutboundMulticast(void) +{ + return SystemUtils::ExecuteCommand("smcroutectl add %s :: :: 65520 %s", InstanceParams::Get().GetThreadIfName(), + InstanceParams::Get().GetBackboneIfName()) == 0 + ? OTBR_ERROR_NONE + : OTBR_ERROR_SMCROUTE; +} + +otbrError SMCRouteManager::ForbidOutboundMulticast(void) +{ + return SystemUtils::ExecuteCommand("smcroutectl remove %s :: :: 65520 %s", InstanceParams::Get().GetThreadIfName(), + InstanceParams::Get().GetBackboneIfName()) == 0 + ? OTBR_ERROR_NONE + : OTBR_ERROR_SMCROUTE; +} + +otbrError SMCRouteManager::AddRoute(const Ip6Address &aAddress) +{ + return SystemUtils::ExecuteCommand("smcroutectl add %s :: %s %s", InstanceParams::Get().GetBackboneIfName(), + aAddress.ToString().c_str(), InstanceParams::Get().GetThreadIfName()) == 0 + ? OTBR_ERROR_NONE + : OTBR_ERROR_SMCROUTE; +} + +otbrError SMCRouteManager::DeleteRoute(const Ip6Address &aAddress) +{ + return SystemUtils::ExecuteCommand("smcroutectl del %s :: %s %s", InstanceParams::Get().GetBackboneIfName(), + aAddress.ToString().c_str(), InstanceParams::Get().GetThreadIfName()) == 0 + ? OTBR_ERROR_NONE + : OTBR_ERROR_SMCROUTE; +} + +otbrError SMCRouteManager::Flush(void) +{ + return SystemUtils::ExecuteCommand("smcroutectl flush") == 0 ? OTBR_ERROR_NONE : OTBR_ERROR_SMCROUTE; +} + +} // namespace BackboneRouter + +} // namespace otbr diff --git a/src/backbone_router/smcroute_manager.hpp b/src/backbone_router/smcroute_manager.hpp new file mode 100644 index 00000000000..0d6bb119e7b --- /dev/null +++ b/src/backbone_router/smcroute_manager.hpp @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2020, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes definition for SMCRoute manager. + */ + +#ifndef BACKBONE_ROUTER_SMCROUTE_MANAGER_HPP_ +#define BACKBONE_ROUTER_SMCROUTE_MANAGER_HPP_ + +#include +#include + +#include "agent/instance_params.hpp" +#include "agent/ncp_openthread.hpp" +#include "utils/system_utils.hpp" + +namespace otbr { +namespace BackboneRouter { + +/** + * @addtogroup border-router-backbone + * + * @brief + * This module includes definition for SMCRoute manager. + * + * @{ + */ + +/** + * This class implements SMCRoute manager functionality. + * + */ +class SMCRouteManager +{ +public: + /** + * This constructor initializes a SMCRoute manager instance. + * + */ + explicit SMCRouteManager() + : mEnabled(false) + { + } + + /** + * This method initializes a SMCRoute manager instance. + * + */ + void Init(void); + + /** + * This method enables the SMCRoute manager. + * + */ + void Enable(void); + + /** + * This method disables the SMCRoute manager. + * + */ + void Disable(void); + + /** + * This method adds a multicast route. + * + * NOTE: Multicast routes are only effective when the SMCRoute manager is enabled. + * + * @param[in] aAddress The multicast address. + * + */ + void Add(const Ip6Address &aAddress); + + /** + * This method removes a multicast route. + * + * @param[in] aAddress The multicast address. + * + */ + void Remove(const Ip6Address &aAddress); + +private: + void StartSMCRouteService(void); + otbrError Flush(void); + otbrError ForbidOutboundMulticast(void); + otbrError AllowOutboundMulticast(void); + otbrError AddRoute(const Ip6Address &aAddress); + otbrError DeleteRoute(const Ip6Address &aAddress); + + std::set mListenerSet; + bool mEnabled : 1; +}; + +/** + * @} + */ + +} // namespace BackboneRouter +} // namespace otbr + +#endif // BACKBONE_ROUTER_SMCROUTE_MANAGER_HPP_ diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 3408c147efa..9b9072d411d 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -28,8 +28,11 @@ add_library(otbr-common logging.cpp + types.cpp ) target_link_libraries(otbr-common PUBLIC otbr-config + openthread-ftd + openthread-posix ) diff --git a/src/common/code_utils.hpp b/src/common/code_utils.hpp index e374d55a668..c8a8eaf83f3 100644 --- a/src/common/code_utils.hpp +++ b/src/common/code_utils.hpp @@ -65,6 +65,24 @@ } \ } while (false) +/** + * This macro verifies a given error status to be successful (compared against value zero (0)), otherwise, it emits a + * given error messages and exits the program. + * + * @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 \ + { \ + if ((aStatus) != 0) \ + { \ + otbrLog(OTBR_LOG_EMERG, "FAILED %s:%d - %s", __FUNCTION__, __LINE__, aMessage); \ + exit(-1); \ + } \ + } while (false) + /** * This checks for the specified condition, which is expected to * commonly be true, and both executes @a ... and branches to the @@ -85,6 +103,24 @@ } \ } while (false) +/** + * This macro checks for the specified condition, which is expected to commonly be true, + * and both prints the message and terminates the program if the condition is false. + * + * @param[in] aCondition The condition to verify + * @param[in] aMessage A message (text string) to print on failure. + * + */ +#define VerifyOrDie(aCondition, aMessage) \ + do \ + { \ + if (!(aCondition)) \ + { \ + otbrLog(OTBR_LOG_EMERG, "FAILED %s:%d - %s", __FUNCTION__, __LINE__, aMessage); \ + exit(-1); \ + } \ + } while (false) + /** * This unconditionally executes @a ... and branches to the local * label 'exit'. diff --git a/src/common/logging.cpp b/src/common/logging.cpp index bf1e8a1a1de..062028c9d22 100644 --- a/src/common/logging.cpp +++ b/src/common/logging.cpp @@ -163,11 +163,6 @@ const char *otbrErrorString(otbrError aError) return error; } -void otbrLogResult(const char *aAction, otbrError aError) -{ - otbrLog((aError == OTBR_ERROR_NONE ? OTBR_LOG_INFO : OTBR_LOG_WARNING), "%s: %s", aAction, otbrErrorString(aError)); -} - void otbrLogDeinit(void) { closelog(); diff --git a/src/common/logging.hpp b/src/common/logging.hpp index d65887b2429..cee374442d0 100644 --- a/src/common/logging.hpp +++ b/src/common/logging.hpp @@ -85,16 +85,22 @@ void otbrLogInit(const char *aIdent, int aLevel, bool aPrintStderr); void otbrLog(int aLevel, const char *aFormat, ...); /** - * This function log a action result according to @p aError. + * This macro log a action result according to @p aError. * * If @p aError is OTBR_ERROR_NONE, the log level will be OTBR_LOG_INFO, * otherwise OTBR_LOG_WARNING. * - * @param[in] aAction The action description. * @param[in] aError The action result. + * @param[in] aFormat Format string as in printf. * */ -void otbrLogResult(const char *aAction, otbrError aError); +#define otbrLogResult(aError, aFormat, ...) \ + do \ + { \ + otbrError _err = (aError); \ + otbrLog(_err == OTBR_ERROR_NONE ? OTBR_LOG_INFO : OTBR_LOG_WARNING, aFormat ": %s", ##__VA_ARGS__, \ + otbrErrorString(_err)); \ + } while (0) /** * This function log at level @p aLevel. diff --git a/src/common/types.cpp b/src/common/types.cpp new file mode 100644 index 00000000000..4a40b747100 --- /dev/null +++ b/src/common/types.cpp @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#include +#include + +#include "common/code_utils.hpp" +#include "common/logging.hpp" +#include "common/types.hpp" + +namespace otbr { + +Ip6Address::Ip6Address(const otIp6Address &aAddress) +{ + static_assert(sizeof(*this) == sizeof(aAddress), "wrong Ip6Address size"); + + m32[0] = aAddress.mFields.m32[0]; + m32[1] = aAddress.mFields.m32[1]; + m32[2] = aAddress.mFields.m32[2]; + m32[3] = aAddress.mFields.m32[3]; +} + +std::string Ip6Address::ToString() const +{ + char strbuf[INET6_ADDRSTRLEN]; + + VerifyOrDie(inet_ntop(AF_INET6, this->m8, strbuf, sizeof(strbuf)) != nullptr, + "Failed to convert Ip6 address to string"); + + return std::string(strbuf); +} + +} // namespace otbr diff --git a/src/common/types.hpp b/src/common/types.hpp index 99987cad7bc..33f653e27e8 100644 --- a/src/common/types.hpp +++ b/src/common/types.hpp @@ -37,9 +37,12 @@ #include "openthread-br/config.h" #include +#include #include #include +#include + #ifndef IN6ADDR_ANY /** * Any IPv6 address literal. @@ -64,7 +67,8 @@ enum otbrError OTBR_ERROR_DBUS = -2, ///< DBus error. OTBR_ERROR_MDNS = -3, ///< MDNS error. OTBR_ERROR_OPENTHREAD = -4, ///< OpenThread error. - OTBR_ERROR_REST = -5 ///< Rest Server error. + OTBR_ERROR_REST = -5, ///< Rest Server error. + OTBR_ERROR_SMCROUTE = -6, ///< SMCRoute error. }; namespace otbr { @@ -109,6 +113,24 @@ class Ip6Address m8[15] = aLocator & 0xff; } + /** + * Constructor with an Thread Ip6 address. + * + * @param[in] aAddress The Thread Ip6 address. + * + */ + Ip6Address(const otIp6Address &aAddress); + + /** + * This method overloads `<` operator and compares if the Ip6 address is smaller than the other address. + * + * @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; } + /** * Retrieve the 16-bit Thread locator. * @@ -117,6 +139,14 @@ class Ip6Address */ uint16_t ToLocator(void) const { return static_cast(m8[14] << 8 | m8[15]); } + /** + * This method returns the string representation for the Ip6 address. + * + * @returns The string representation of the Ip6 address. + * + */ + std::string ToString() const; + union { uint8_t m8[16]; diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index fb47f28c9ab..e76f0466088 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -33,6 +33,7 @@ add_library(otbr-utils pskc.cpp steering_data.cpp strcpy_utils.cpp + system_utils.cpp ) target_link_libraries(otbr-utils PRIVATE otbr-common diff --git a/src/utils/system_utils.cpp b/src/utils/system_utils.cpp new file mode 100644 index 00000000000..9a935c03edb --- /dev/null +++ b/src/utils/system_utils.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * The file implements POSIX system utilities. + */ + +#include "system_utils.hpp" + +#include +#include +#include + +#include "common/logging.hpp" + +namespace otbr { +namespace SystemUtils { + +enum +{ + kSystemCommandMaxLength = 1024, ///< Max length of a system call command. +}; + +int ExecuteCommand(const char *aFormat, ...) +{ + char cmd[kSystemCommandMaxLength]; + int exitCode; + va_list args; + + va_start(args, aFormat); + vsnprintf(cmd, sizeof(cmd), aFormat, args); + va_end(args); + + exitCode = system(cmd); + + otbrLog(exitCode == 0 ? OTBR_LOG_INFO : OTBR_LOG_WARNING, "$?=%-3d: %s", exitCode, cmd); + return exitCode; +} + +} // namespace SystemUtils +} // namespace otbr diff --git a/src/utils/system_utils.hpp b/src/utils/system_utils.hpp new file mode 100644 index 00000000000..4ae2dad1597 --- /dev/null +++ b/src/utils/system_utils.hpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes definitions for POSIX system utilities. + */ + +#ifndef OTBR_UTILS_SYSTEM_UTILS_HPP_ +#define OTBR_UTILS_SYSTEM_UTILS_HPP_ + +namespace otbr { +namespace SystemUtils { + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * This method formats a system command to execute. + * + * @param[in] aFormat A pointer to the format string. + * @param[in] ... Arguments for the format specification. + * + * @returns The command exit code. + * + */ +int ExecuteCommand(const char *aFormat, ...); + +#ifdef __cplusplus +} +#endif + +} // namespace SystemUtils +} // namespace otbr + +#endif // OTBR_UTILS_SYSTEM_UTILS_HPP_ diff --git a/tests/mdns/CMakeLists.txt b/tests/mdns/CMakeLists.txt index 108014a0995..a602a7545dd 100644 --- a/tests/mdns/CMakeLists.txt +++ b/tests/mdns/CMakeLists.txt @@ -33,6 +33,7 @@ add_executable(otbr-test-mdns target_link_libraries(otbr-test-mdns PRIVATE otbr-config otbr-mdns + openthread-ftd ) add_test( diff --git a/third_party/openthread/repo b/third_party/openthread/repo index 7a24666bf45..8707b638942 160000 --- a/third_party/openthread/repo +++ b/third_party/openthread/repo @@ -1 +1 @@ -Subproject commit 7a24666bf45b92f2a2bedd0559411c7ce019832c +Subproject commit 8707b638942fa396fe0c3c11a918f79082aadb8e From c8c0e81da69c99d689ed3145461ea598fba3f591 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Fri, 30 Oct 2020 02:35:56 +0800 Subject: [PATCH 008/175] [web-service] escape networkname (#579) - Use dataset for forming network. - Escape whitespaces in networkname --- src/web/web-service/wpan_service.cpp | 87 ++++++++++++++++++++-------- src/web/web-service/wpan_service.hpp | 8 +++ 2 files changed, 70 insertions(+), 25 deletions(-) diff --git a/src/web/web-service/wpan_service.cpp b/src/web/web-service/wpan_service.cpp index b272e6d9f74..0f0b1d561ce 100644 --- a/src/web/web-service/wpan_service.cpp +++ b/src/web/web-service/wpan_service.cpp @@ -34,6 +34,8 @@ #include "web/web-service/wpan_service.hpp" #include +#include +#include #include "common/byteswap.hpp" #include "common/code_utils.hpp" @@ -74,16 +76,8 @@ std::string WpanService::HandleJoinNetworkRequest(const std::string &aJoinReques } VerifyOrExit(client.FactoryReset(), ret = kWpanStatus_LeaveFailed); - VerifyOrExit(client.Execute("dataset init new") != nullptr, ret = kWpanStatus_SetFailed); - VerifyOrExit(client.Execute("dataset masterkey %s", masterKey.c_str()) != nullptr, ret = kWpanStatus_SetFailed); - VerifyOrExit(client.Execute("dataset networkname %s", mNetworks[index].mNetworkName) != nullptr, - ret = kWpanStatus_SetFailed); - VerifyOrExit(client.Execute("dataset channel %u", mNetworks[index].mChannel) != nullptr, - ret = kWpanStatus_SetFailed); - VerifyOrExit(client.Execute("dataset extpanid %016" PRIx64, mNetworks[index].mExtPanId) != nullptr, - ret = kWpanStatus_SetFailed); - VerifyOrExit(client.Execute("dataset panid %u", mNetworks[index].mPanId) != nullptr, ret = kWpanStatus_SetFailed); - VerifyOrExit(client.Execute("dataset commit active") != nullptr, ret = kWpanStatus_SetFailed); + VerifyOrExit((ret = commitActiveDataset(client, masterKey, mNetworks[index].mNetworkName, mNetworks[index].mChannel, + mNetworks[index].mExtPanId, mNetworks[index].mPanId)) == kWpanStatus_Ok); VerifyOrExit(client.Execute("ifconfig up") != nullptr, ret = kWpanStatus_JoinFailed); VerifyOrExit(client.Execute("thread start") != nullptr, ret = kWpanStatus_JoinFailed); VerifyOrExit(client.Execute("prefix add %s paso%s", prefix.c_str(), (defaultRoute ? "r" : "")) != nullptr, @@ -117,8 +111,8 @@ std::string WpanService::HandleFormNetworkRequest(const std::string &aFormReques uint16_t channel; std::string networkName; std::string passphrase; - std::string panId; - std::string extPanId; + uint16_t panId; + uint64_t extPanId; bool defaultRoute; int ret = kWpanStatus_Ok; otbr::Web::OpenThreadClient client; @@ -127,16 +121,17 @@ std::string WpanService::HandleFormNetworkRequest(const std::string &aFormReques pskcStr[OT_PSKC_MAX_LENGTH * 2] = '\0'; // for manipulating with strlen VerifyOrExit(reader.parse(aFormRequest.c_str(), root) == true, ret = kWpanStatus_ParseRequestFailed); - masterKey = root["masterKey"].asString(); - prefix = root["prefix"].asString(); - channel = root["channel"].asUInt(); - networkName = root["networkName"].asString(); - passphrase = root["passphrase"].asString(); - panId = root["panId"].asString(); - extPanId = root["extPanId"].asString(); + masterKey = root["masterKey"].asString(); + prefix = root["prefix"].asString(); + channel = root["channel"].asUInt(); + networkName = root["networkName"].asString(); + passphrase = root["passphrase"].asString(); + VerifyOrExit(sscanf(root["panId"].asString().c_str(), "%hx", &panId) == 1, ret = kWpanStatus_ParseRequestFailed); + VerifyOrExit(sscanf(root["extPanId"].asString().c_str(), "%" PRIx64, &extPanId) == 1, + ret = kWpanStatus_ParseRequestFailed); defaultRoute = root["defaultRoute"].asBool(); - otbr::Utils::Hex2Bytes(extPanId.c_str(), extPanIdBytes, OT_EXTENDED_PANID_LENGTH); + otbr::Utils::Hex2Bytes(root["extPanId"].asString().c_str(), extPanIdBytes, OT_EXTENDED_PANID_LENGTH); otbr::Utils::Bytes2Hex(psk.ComputePskc(extPanIdBytes, networkName.c_str(), passphrase.c_str()), OT_PSKC_MAX_LENGTH, pskcStr); @@ -146,11 +141,8 @@ std::string WpanService::HandleFormNetworkRequest(const std::string &aFormReques } VerifyOrExit(client.FactoryReset(), ret = kWpanStatus_LeaveFailed); - VerifyOrExit(client.Execute("masterkey %s", masterKey.c_str()) != nullptr, ret = kWpanStatus_SetFailed); - VerifyOrExit(client.Execute("networkname %s", networkName.c_str()) != nullptr, ret = kWpanStatus_SetFailed); - VerifyOrExit(client.Execute("channel %u", channel) != nullptr, ret = kWpanStatus_SetFailed); - VerifyOrExit(client.Execute("extpanid %s", extPanId.c_str()) != nullptr, ret = kWpanStatus_SetFailed); - VerifyOrExit(client.Execute("panid %s", panId.c_str()) != nullptr, ret = kWpanStatus_SetFailed); + VerifyOrExit((ret = commitActiveDataset(client, masterKey, networkName, channel, extPanId, panId)) == + kWpanStatus_Ok); VerifyOrExit(client.Execute("pskc %s", pskcStr) != nullptr, ret = kWpanStatus_SetFailed); VerifyOrExit(client.Execute("ifconfig up") != nullptr, ret = kWpanStatus_FormFailed); VerifyOrExit(client.Execute("thread start") != nullptr, ret = kWpanStatus_FormFailed); @@ -445,5 +437,50 @@ std::string WpanService::HandleCommission(const std::string &aCommissionRequest) return response; } +int WpanService::commitActiveDataset(otbr::Web::OpenThreadClient &aClient, + const std::string & aMasterKey, + const std::string & aNetworkName, + uint16_t aChannel, + uint64_t aExtPanId, + uint16_t aPanId) +{ + int ret = kWpanStatus_Ok; + + VerifyOrExit(aClient.Execute("dataset init new") != nullptr, ret = kWpanStatus_SetFailed); + VerifyOrExit(aClient.Execute("dataset masterkey %s", aMasterKey.c_str()) != nullptr, ret = kWpanStatus_SetFailed); + VerifyOrExit(aClient.Execute("dataset networkname %s", escapeOtCliEscapable(aNetworkName).c_str()) != nullptr, + ret = kWpanStatus_SetFailed); + VerifyOrExit(aClient.Execute("dataset channel %u", aChannel) != nullptr, ret = kWpanStatus_SetFailed); + VerifyOrExit(aClient.Execute("dataset extpanid %016" PRIx64, aExtPanId) != nullptr, ret = kWpanStatus_SetFailed); + VerifyOrExit(aClient.Execute("dataset panid %u", aPanId) != nullptr, ret = kWpanStatus_SetFailed); + VerifyOrExit(aClient.Execute("dataset commit active") != nullptr, ret = kWpanStatus_SetFailed); + +exit: + return ret; +} + +std::string WpanService::escapeOtCliEscapable(const std::string &aArg) +{ + std::stringbuf strbuf; + + for (char c : aArg) + { + switch (c) + { + case ' ': + case '\t': + case '\r': + case '\n': + case '\\': + strbuf.sputc('\\'); + // Fallthrough + default: + strbuf.sputc(c); + } + } + + return strbuf.str(); +} + } // namespace Web } // namespace otbr diff --git a/src/web/web-service/wpan_service.hpp b/src/web/web-service/wpan_service.hpp index fdc65bbd19c..54a86a74a57 100644 --- a/src/web/web-service/wpan_service.hpp +++ b/src/web/web-service/wpan_service.hpp @@ -174,6 +174,14 @@ class WpanService std::string CommissionDevice(const char *aPskd, const char *aNetworkPassword); private: + int commitActiveDataset(otbr::Web::OpenThreadClient &aClient, + const std::string & aMasterKey, + const std::string & aNetworkName, + uint16_t aChannel, + uint64_t aExtPanId, + uint16_t aPanId); + static std::string escapeOtCliEscapable(const std::string &aArg); + WpanNetworkInfo mNetworks[OT_SCANNED_NET_BUFFER_SIZE]; int mNetworksCount; char mIfName[IFNAMSIZ]; From 58d50b7306ca6d4cf1da8b221b556c218ee7983c Mon Sep 17 00:00:00 2001 From: Moandor Date: Fri, 30 Oct 2020 10:56:55 +0800 Subject: [PATCH 009/175] [common] remove client dependency of OpenThread header (#601) This removes the dependency of openthread/ip6.h from common/types.hpp. --- src/backbone_router/backbone_agent.cpp | 6 +++--- src/common/types.cpp | 9 ++------- src/common/types.hpp | 8 +++----- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/backbone_router/backbone_agent.cpp b/src/backbone_router/backbone_agent.cpp index da269e8d60b..8b8e071a6a7 100644 --- a/src/backbone_router/backbone_agent.cpp +++ b/src/backbone_router/backbone_agent.cpp @@ -109,15 +109,15 @@ void BackboneAgent::HandleBackboneRouterMulticastListenerEvent(otBackboneRouterM const otIp6Address & aAddress) { otbrLog(OTBR_LOG_INFO, "BackboneAgent: Multicast Listener event: %d, address: %s, state: %s", aEvent, - Ip6Address(aAddress).ToString().c_str(), StateToString(mBackboneRouterState)); + Ip6Address(aAddress.mFields.m8).ToString().c_str(), StateToString(mBackboneRouterState)); switch (aEvent) { case OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ADDED: - mSMCRouteManager.Add(Ip6Address(aAddress)); + mSMCRouteManager.Add(Ip6Address(aAddress.mFields.m8)); break; case OT_BACKBONE_ROUTER_MULTICAST_LISTENER_REMOVED: - mSMCRouteManager.Remove(Ip6Address(aAddress)); + mSMCRouteManager.Remove(Ip6Address(aAddress.mFields.m8)); break; } } diff --git a/src/common/types.cpp b/src/common/types.cpp index 4a40b747100..f96e3263e52 100644 --- a/src/common/types.cpp +++ b/src/common/types.cpp @@ -35,14 +35,9 @@ namespace otbr { -Ip6Address::Ip6Address(const otIp6Address &aAddress) +Ip6Address::Ip6Address(const uint8_t (&aAddress)[16]) { - static_assert(sizeof(*this) == sizeof(aAddress), "wrong Ip6Address size"); - - m32[0] = aAddress.mFields.m32[0]; - m32[1] = aAddress.mFields.m32[1]; - m32[2] = aAddress.mFields.m32[2]; - m32[3] = aAddress.mFields.m32[3]; + memcpy(m8, aAddress, sizeof(m8)); } std::string Ip6Address::ToString() const diff --git a/src/common/types.hpp b/src/common/types.hpp index 33f653e27e8..44819ab655b 100644 --- a/src/common/types.hpp +++ b/src/common/types.hpp @@ -41,8 +41,6 @@ #include #include -#include - #ifndef IN6ADDR_ANY /** * Any IPv6 address literal. @@ -114,12 +112,12 @@ class Ip6Address } /** - * Constructor with an Thread Ip6 address. + * Constructor with an Ip6 address. * - * @param[in] aAddress The Thread Ip6 address. + * @param[in] aAddress The Ip6 address. * */ - Ip6Address(const otIp6Address &aAddress); + Ip6Address(const uint8_t (&aAddress)[16]); /** * This method overloads `<` operator and compares if the Ip6 address is smaller than the other address. From ba6fad61bc0e0f2c77406c008d028af3b92f7526 Mon Sep 17 00:00:00 2001 From: Rongli Sun Date: Fri, 30 Oct 2020 11:07:41 +0800 Subject: [PATCH 010/175] [cmake] update OT_LOG_LEVEL for debug build (#582) This commit also turns on OT_LOG_LEVEL_DYNAMIC to allow dynamic log level control. --- third_party/openthread/CMakeLists.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/third_party/openthread/CMakeLists.txt b/third_party/openthread/CMakeLists.txt index c9aa033bade..fda2cf71364 100644 --- a/third_party/openthread/CMakeLists.txt +++ b/third_party/openthread/CMakeLists.txt @@ -34,6 +34,14 @@ set(OT_COMMISSIONER ON CACHE BOOL "enable commissioner" FORCE) set(OT_DAEMON ON CACHE BOOL "enable daemon mode" FORCE) set(OT_JOINER ON CACHE BOOL "enable joiner" FORCE) set(OT_LEGACY ON CACHE STRING "enable legacy network support" FORCE) + +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + set(OT_LOG_LEVEL "DEBG" CACHE STRING "set OpenThread log level to DEBG" FORCE) +else() + set(OT_LOG_LEVEL "INFO" CACHE STRING "set OpenThread log level to INFO" FORCE) +endif() + +set(OT_LOG_LEVEL_DYNAMIC ON CACHE BOOL "enable dynamic log level control" FORCE) set(OT_MAC_FILTER ON CACHE STRING "enable MAC filter" FORCE) set(OT_MBEDTLS_CONFIG_FILE "\"${PROJECT_SOURCE_DIR}/third_party/openthread/mbedtls-config.h\"" CACHE STRING "use mbedtls-config.h of this project" FORCE) set(OT_PLATFORM "posix" CACHE STRING "use posix platform" FORCE) @@ -47,8 +55,6 @@ add_subdirectory(repo EXCLUDE_FROM_ALL) target_compile_definitions(ot-config INTERFACE "-DOPENTHREAD_CONFIG_LOG_CLI=1" - "-DOPENTHREAD_CONFIG_LOG_LEVEL=OT_LOG_LEVEL_INFO" "-DOPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS=3" "-DOPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE=1" ) - From 32e0914508f43e4991fee71efc46db69b5e2211c Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Sat, 31 Oct 2020 03:02:08 +0800 Subject: [PATCH 011/175] [agent] add region support (#567) The commit adds region support which will determine the preferred channels and the allowed channels when forming or joining a Thread network. - Add region and channel mask logic. - Add region to command line arguments. - Add d-bus get and set api. --- Android.mk | 1 + src/agent/main.cpp | 43 ++++++++++------ src/agent/ncp_openthread.hpp | 18 +++++++ src/agent/thread_helper.cpp | 7 ++- src/common/CMakeLists.txt | 1 + src/common/region_code.cpp | 70 ++++++++++++++++++++++++++ src/common/region_code.hpp | 58 +++++++++++++++++++++ src/dbus/client/thread_api_dbus.cpp | 10 ++++ src/dbus/client/thread_api_dbus.hpp | 22 ++++++++ src/dbus/common/constants.hpp | 1 + src/dbus/server/dbus_thread_object.cpp | 34 ++++++++++++- src/dbus/server/dbus_thread_object.hpp | 2 + src/dbus/server/introspect.xml | 4 ++ tests/dbus/test-client | 2 +- tests/dbus/test_dbus_client.cpp | 14 ++++++ 15 files changed, 267 insertions(+), 20 deletions(-) create mode 100644 src/common/region_code.cpp create mode 100644 src/common/region_code.hpp diff --git a/Android.mk b/Android.mk index 3cd4b01310c..c1b3d5cf7b0 100644 --- a/Android.mk +++ b/Android.mk @@ -98,6 +98,7 @@ LOCAL_SRC_FILES := \ src/agent/ncp_openthread.cpp \ src/agent/thread_helper.cpp \ src/common/logging.cpp \ + src/common/region_code.cpp \ src/dbus/common/dbus_message_dump.cpp \ src/dbus/common/dbus_message_helper.cpp \ src/dbus/common/dbus_message_helper_openthread.cpp \ diff --git a/src/agent/main.cpp b/src/agent/main.cpp index 2e8c571df16..c24942382b6 100644 --- a/src/agent/main.cpp +++ b/src/agent/main.cpp @@ -47,6 +47,7 @@ #include "agent/ncp_openthread.hpp" #include "common/code_utils.hpp" #include "common/logging.hpp" +#include "common/region_code.hpp" #include "common/types.hpp" #if OTBR_ENABLE_REST_SERVER #include "rest/rest_web_server.hpp" @@ -81,6 +82,7 @@ enum OTBR_OPT_VERSION = 'V', OTBR_OPT_SHORTMAX = 128, OTBR_OPT_RADIO_VERSION, + OTBR_OPT_REGION, }; // Default poll timeout. @@ -95,6 +97,7 @@ static const struct option kOptions[] = { {"verbose", no_argument, nullptr, OTBR_OPT_VERBOSE}, {"version", no_argument, nullptr, OTBR_OPT_VERSION}, {"radio-version", no_argument, nullptr, OTBR_OPT_RADIO_VERSION}, + {"reg", required_argument, nullptr, OTBR_OPT_REGION}, {0, 0, 0, 0}}; static void HandleSignal(int aSignal) @@ -193,7 +196,7 @@ static int Mainloop(otbr::AgentInstance &aInstance, const char *aInterfaceName) static void PrintHelp(const char *aProgramName) { - fprintf(stderr, "Usage: %s [-I interfaceName] [-d DEBUG_LEVEL] [-v] RADIO_URL\n", aProgramName); + fprintf(stderr, "Usage: %s [--reg region] [-I interfaceName] [-d DEBUG_LEVEL] [-v] RADIO_URL\n", aProgramName); fprintf(stderr, "%s", otSysGetRadioUrlHelpString()); } @@ -215,14 +218,16 @@ static void OnAllocateFailed(void) int main(int argc, char *argv[]) { - int logLevel = OTBR_LOG_INFO; - int opt; - int ret = EXIT_SUCCESS; - const char * interfaceName = kDefaultInterfaceName; - const char * backboneInterfaceName = ""; - otbr::Ncp::Controller *ncp = nullptr; - bool verbose = false; - bool printRadioVersion = false; + int logLevel = OTBR_LOG_INFO; + int opt; + int ret = EXIT_SUCCESS; + const char * interfaceName = kDefaultInterfaceName; + const char * backboneInterfaceName = ""; + otbr::Ncp::Controller * ncp = nullptr; + otbr::Ncp::ControllerOpenThread *ncpOpenThread = nullptr; + bool verbose = false; + bool printRadioVersion = false; + std::string regionCode; std::set_new_handler(OnAllocateFailed); @@ -267,6 +272,10 @@ int main(int argc, char *argv[]) printRadioVersion = true; break; + case OTBR_OPT_REGION: + regionCode = optarg; + break; + default: PrintHelp(argv[0]); ExitNow(ret = EXIT_FAILURE); @@ -278,13 +287,21 @@ int main(int argc, char *argv[]) otbrLog(OTBR_LOG_INFO, "Running %s", OTBR_PACKAGE_VERSION); VerifyOrExit(optind < argc, ret = EXIT_FAILURE); - ncp = otbr::Ncp::Controller::Create(interfaceName, argv[optind], backboneInterfaceName); + ncp = otbr::Ncp::Controller::Create(interfaceName, argv[optind], backboneInterfaceName); + ncpOpenThread = static_cast(ncp); VerifyOrExit(ncp != nullptr, ret = EXIT_FAILURE); otbrLog(OTBR_LOG_INFO, "Thread interface %s", interfaceName); #if OTBR_ENABLE_BACKBONE_ROUTER otbrLog(OTBR_LOG_INFO, "Backbone interface %s", backboneInterfaceName); #endif + otbrLog(OTBR_LOG_INFO, "Backbone interface %s", + backboneInterfaceName == nullptr ? "(null)" : backboneInterfaceName); + if (!regionCode.empty()) + { + otbrLog(OTBR_LOG_INFO, "Region %s", regionCode.c_str()); + } + ncpOpenThread->SetRegionCode(regionCode); { otbr::AgentInstance instance(ncp); @@ -298,16 +315,12 @@ int main(int argc, char *argv[]) if (printRadioVersion) { - ControllerOpenThread *ncpOpenThread = reinterpret_cast(ncp); - PrintRadioVersion(ncpOpenThread->GetInstance()); ExitNow(ret = EXIT_SUCCESS); } #if OTBR_ENABLE_OPENWRT - ControllerOpenThread *ncpThread = reinterpret_cast(ncp); - - UbusServerInit(ncpThread, &sThreadMutex); + UbusServerInit(ncpOpenThread, &sThreadMutex); std::thread(UbusServerRun).detach(); #endif SuccessOrExit(ret = Mainloop(instance, interfaceName)); diff --git a/src/agent/ncp_openthread.hpp b/src/agent/ncp_openthread.hpp index 9e7817ee77a..0ad3915f38e 100644 --- a/src/agent/ncp_openthread.hpp +++ b/src/agent/ncp_openthread.hpp @@ -43,6 +43,7 @@ #include "ncp.hpp" #include "agent/thread_helper.hpp" +#include "common/region_code.hpp" namespace otbr { namespace Ncp { @@ -88,6 +89,22 @@ class ControllerOpenThread : public Controller */ otbr::agent::ThreadHelper *GetThreadHelper(void) { return mThreadHelper.get(); } + /** + * This method sets the region code. + * + * @param[in] aCode The region code. + * + */ + void SetRegionCode(const std::string &aCode) { mRegionCode = aCode; } + + /** + * This method gets the region code. + * + * @retval The region code. + * + */ + std::string GetRegionCode(void) { return mRegionCode; } + /** * This method updates the fd_set to poll. * @@ -169,6 +186,7 @@ class ControllerOpenThread : public Controller std::multimap> mTimers; bool mTriedAttach; std::vector> mResetHandlers; + std::string mRegionCode; }; } // namespace Ncp diff --git a/src/agent/thread_helper.cpp b/src/agent/thread_helper.cpp index 6cf3802bc34..80d6b7e25db 100644 --- a/src/agent/thread_helper.cpp +++ b/src/agent/thread_helper.cpp @@ -45,6 +45,7 @@ #include "common/byteswap.hpp" #include "common/code_utils.hpp" #include "common/logging.hpp" +#include "common/region_code.hpp" namespace otbr { namespace agent { @@ -186,6 +187,8 @@ void ThreadHelper::Attach(const std::string & aNetworkName, otExtendedPanId extPanId; otMasterKey masterKey; otPskc pskc; + uint32_t preferredChannelMask = GetPreferredChannelMaskForRegion(mNcp->GetRegionCode()); + uint32_t supportedChannelMask = GetSupportedChannelMaskForRegion(mNcp->GetRegionCode()); uint32_t channelMask; uint8_t channel; @@ -241,11 +244,11 @@ void ThreadHelper::Attach(const std::string & aNetworkName, SuccessOrExit(error = otThreadSetExtendedPanId(mInstance, &extPanId)); SuccessOrExit(error = otThreadSetMasterKey(mInstance, &masterKey)); - channelMask = otPlatRadioGetPreferredChannelMask(mInstance) & aChannelMask; + channelMask = otLinkGetSupportedChannelMask(mInstance) & preferredChannelMask & aChannelMask; if (channelMask == 0) { - channelMask = otLinkGetSupportedChannelMask(mInstance) & aChannelMask; + channelMask = otLinkGetSupportedChannelMask(mInstance) & supportedChannelMask & aChannelMask; } VerifyOrExit(channelMask != 0, otbrLog(OTBR_LOG_WARNING, "Invalid channel mask"), error = OT_ERROR_INVALID_ARGS); diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 9b9072d411d..21c0e2e1c30 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -29,6 +29,7 @@ add_library(otbr-common logging.cpp types.cpp + region_code.cpp ) target_link_libraries(otbr-common diff --git a/src/common/region_code.cpp b/src/common/region_code.cpp new file mode 100644 index 00000000000..28a2c4cc942 --- /dev/null +++ b/src/common/region_code.cpp @@ -0,0 +1,70 @@ +/* + * 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. + */ + +#include "region_code.hpp" + +namespace { + +constexpr uint32_t kChannelMask11To24 = 0x1fff800; +constexpr uint32_t kChannelMask11To25 = 0x3fff800; +constexpr uint32_t kChannelMask11To26 = 0x7fff800; + +constexpr char kRegionCodeUS[] = "US"; +constexpr char kRegionCodeCA[] = "CA"; + +} // namespace + +namespace otbr { + +uint32_t GetSupportedChannelMaskForRegion(const std::string &aRegionCode) +{ + uint32_t mask = kChannelMask11To26; + + // US or CA + if (aRegionCode == kRegionCodeUS || aRegionCode == kRegionCodeCA) + { + mask = kChannelMask11To25; + } + + return mask; +} + +uint32_t GetPreferredChannelMaskForRegion(const std::string &aRegionCode) +{ + uint32_t mask = kChannelMask11To26; + + // US or CA + if (aRegionCode == kRegionCodeUS || aRegionCode == kRegionCodeCA) + { + mask = kChannelMask11To24; + } + + return mask; +} + +} // namespace otbr diff --git a/src/common/region_code.hpp b/src/common/region_code.hpp new file mode 100644 index 00000000000..3073e92a0bc --- /dev/null +++ b/src/common/region_code.hpp @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#ifndef OTBR_COMMON_REGION_CODE_HPP_ +#define OTBR_COMMON_REGION_CODE_HPP_ + +#include + +namespace otbr { + +/** + * This method returns the supported channel mask for a region code. + * + * + * @param[in] aRegionCode The region code. + * @returns The supported channel mask. + * + */ +uint32_t GetSupportedChannelMaskForRegion(const std::string &aRegionCode); + +/** + * This method returns the preferred channel mask for a region code. + * + * @param[in] aRegionCode The region code. + * + * @returns The preferred channel mask. + * + */ +uint32_t GetPreferredChannelMaskForRegion(const std::string &aRegionCode); + +} // namespace otbr + +#endif // OTBR_COMMON_REGION_CODE_HPP_ diff --git a/src/dbus/client/thread_api_dbus.cpp b/src/dbus/client/thread_api_dbus.cpp index 80f8c3df7b6..3ca3ec0c20c 100644 --- a/src/dbus/client/thread_api_dbus.cpp +++ b/src/dbus/client/thread_api_dbus.cpp @@ -374,6 +374,11 @@ ClientError ThreadApiDBus::SetLinkMode(const LinkModeConfig &aConfig) return SetProperty(OTBR_DBUS_PROPERTY_LINK_MODE, aConfig); } +ClientError ThreadApiDBus::SetRegion(const std::string &aRegion) +{ + return SetProperty(OTBR_DBUS_PROPERTY_REGION, aRegion); +} + ClientError ThreadApiDBus::GetLinkMode(LinkModeConfig &aConfig) { return GetProperty(OTBR_DBUS_PROPERTY_LINK_MODE, aConfig); @@ -510,6 +515,11 @@ ClientError ThreadApiDBus::GetExternalRoutes(std::vector &aExtern return GetProperty(OTBR_DBUS_PROPERTY_EXTERNAL_ROUTES, aExternalRoutes); } +ClientError ThreadApiDBus::GetRegion(std::string &aRegion) +{ + return GetProperty(OTBR_DBUS_PROPERTY_REGION, aRegion); +} + std::string ThreadApiDBus::GetInterfaceName(void) { return mInterfaceName; diff --git a/src/dbus/client/thread_api_dbus.hpp b/src/dbus/client/thread_api_dbus.hpp index 665d3b07cb7..fa9c2e53595 100644 --- a/src/dbus/client/thread_api_dbus.hpp +++ b/src/dbus/client/thread_api_dbus.hpp @@ -267,6 +267,17 @@ class ThreadApiDBus */ ClientError SetLinkMode(const LinkModeConfig &aConfig); + /** + * This method sets the region. + * + * @param[in] aRegion The region, can be CA, US or WW. + * + * @retval ERROR_NONE successfully performed the dbus function call + * @retval ERROR_DBUS dbus encode/decode error + * + */ + ClientError SetRegion(const std::string &aRegion); + /** * This method gets the link operating mode. * @@ -580,6 +591,17 @@ class ThreadApiDBus */ ClientError GetExternalRoutes(std::vector &aExternalRoutes); + /** + * This method gets the region. + * + * @param[out] aRegion The region, can be CA, US or WW. + * + * @retval ERROR_NONE successfully performed the dbus function call + * @retval ERROR_DBUS dbus encode/decode error + * + */ + ClientError GetRegion(std::string &aRegion); + /** * This method returns the network interface name the client is bound to. * diff --git a/src/dbus/common/constants.hpp b/src/dbus/common/constants.hpp index 8a254a94aba..ec0d1d0f58a 100644 --- a/src/dbus/common/constants.hpp +++ b/src/dbus/common/constants.hpp @@ -79,6 +79,7 @@ #define OTBR_DBUS_PROPERTY_INSTANT_RSSI "InstantRssi" #define OTBR_DBUS_PROPERTY_RADIO_TX_POWER "RadioTxPower" #define OTBR_DBUS_PROPERTY_EXTERNAL_ROUTES "ExternalRoutes" +#define OTBR_DBUS_PROPERTY_REGION "Region" #define OTBR_ROLE_NAME_DISABLED "disabled" #define OTBR_ROLE_NAME_DETACHED "detached" diff --git a/src/dbus/server/dbus_thread_object.cpp b/src/dbus/server/dbus_thread_object.cpp index 685b2548681..936deec4a93 100644 --- a/src/dbus/server/dbus_thread_object.cpp +++ b/src/dbus/server/dbus_thread_object.cpp @@ -40,6 +40,7 @@ #include #include "common/byteswap.hpp" +#include "common/region_code.hpp" #include "dbus/common/constants.hpp" #include "dbus/server/dbus_agent.hpp" #include "dbus/server/dbus_thread_object.hpp" @@ -139,6 +140,9 @@ otbrError DBusThreadObject::Init(void) std::bind(&DBusThreadObject::SetLegacyUlaPrefixHandler, this, _1)); RegisterSetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_LINK_MODE, std::bind(&DBusThreadObject::SetLinkModeHandler, this, _1)); + RegisterSetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_REGION, + std::bind(&DBusThreadObject::SetRegionHandler, this, _1)); + RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_LINK_MODE, std::bind(&DBusThreadObject::GetLinkModeHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_DEVICE_ROLE, @@ -192,6 +196,8 @@ otbrError DBusThreadObject::Init(void) std::bind(&DBusThreadObject::GetRadioTxPowerHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_EXTERNAL_ROUTES, std::bind(&DBusThreadObject::GetExternalRoutesHandler, this, _1)); + RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_REGION, + std::bind(&DBusThreadObject::GetRegionHandler, this, _1)); return error; } @@ -489,6 +495,18 @@ otError DBusThreadObject::SetLinkModeHandler(DBusMessageIter &aIter) return error; } +otError DBusThreadObject::SetRegionHandler(DBusMessageIter &aIter) +{ + std::string regionCode; + otError error = OT_ERROR_NONE; + + VerifyOrExit(DBusMessageExtractFromVariant(&aIter, regionCode) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); + mNcp->SetRegionCode(regionCode); + +exit: + return error; +} + otError DBusThreadObject::GetLinkModeHandler(DBusMessageIter &aIter) { auto threadHelper = mNcp->GetThreadHelper(); @@ -663,8 +681,9 @@ otError DBusThreadObject::GetIp6CountersHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetSupportedChannelMaskHandler(DBusMessageIter &aIter) { auto threadHelper = mNcp->GetThreadHelper(); - uint32_t channelMask = otLinkGetSupportedChannelMask(threadHelper->GetInstance()); - otError error = OT_ERROR_NONE; + uint32_t channelMask = otLinkGetSupportedChannelMask(threadHelper->GetInstance()) & + GetSupportedChannelMaskForRegion(mNcp->GetRegionCode()); + otError error = OT_ERROR_NONE; VerifyOrExit(DBusMessageEncodeToVariant(&aIter, channelMask) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); @@ -961,5 +980,16 @@ otError DBusThreadObject::GetExternalRoutesHandler(DBusMessageIter &aIter) return error; } +otError DBusThreadObject::GetRegionHandler(DBusMessageIter &aIter) +{ + otError error = OT_ERROR_NONE; + std::string regionName(mNcp->GetRegionCode()); + + VerifyOrExit(DBusMessageEncodeToVariant(&aIter, regionName) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); + +exit: + return error; +} + } // namespace DBus } // namespace otbr diff --git a/src/dbus/server/dbus_thread_object.hpp b/src/dbus/server/dbus_thread_object.hpp index 4893935b4da..4d7364f98db 100644 --- a/src/dbus/server/dbus_thread_object.hpp +++ b/src/dbus/server/dbus_thread_object.hpp @@ -86,6 +86,7 @@ class DBusThreadObject : public DBusObject otError SetMeshLocalPrefixHandler(DBusMessageIter &aIter); otError SetLegacyUlaPrefixHandler(DBusMessageIter &aIter); otError SetLinkModeHandler(DBusMessageIter &aIter); + otError SetRegionHandler(DBusMessageIter &aIter); otError GetLinkModeHandler(DBusMessageIter &aIter); otError GetDeviceRoleHandler(DBusMessageIter &aIter); @@ -113,6 +114,7 @@ class DBusThreadObject : public DBusObject otError GetInstantRssiHandler(DBusMessageIter &aIter); otError GetRadioTxPowerHandler(DBusMessageIter &aIter); otError GetExternalRoutesHandler(DBusMessageIter &aIter); + otError GetRegionHandler(DBusMessageIter &aIter); void ReplyScanResult(DBusRequest &aRequest, otError aError, const std::vector &aResult); diff --git a/src/dbus/server/introspect.xml b/src/dbus/server/introspect.xml index 0850c5f9270..0fc7b7dd902 100644 --- a/src/dbus/server/introspect.xml +++ b/src/dbus/server/introspect.xml @@ -334,6 +334,10 @@ + + + + diff --git a/tests/dbus/test-client b/tests/dbus/test-client index 2026c049572..47c6d4593ec 100755 --- a/tests/dbus/test-client +++ b/tests/dbus/test-client @@ -54,7 +54,7 @@ main() sudo install -m 644 "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent.conf /etc/dbus-1/system.d/"${OTBR_DBUS_SERVER_CONF}" sudo service dbus reload sudo "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent -d7 -I wpan0 --radio-version "spinel+hdlc+forkpty://$(command -v ot-rcp)?forkpty-arg=1" | grep "OPENTHREAD" - sudo "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent -d7 -I wpan0 "spinel+hdlc+forkpty://$(command -v ot-rcp)?forkpty-arg=1" & + sudo "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent --reg WW -d7 -I wpan0 "spinel+hdlc+forkpty://$(command -v ot-rcp)?forkpty-arg=1" & trap on_exit EXIT sleep 5 sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl factoryreset diff --git a/tests/dbus/test_dbus_client.cpp b/tests/dbus/test_dbus_client.cpp index deb324a7922..06f04a52a34 100644 --- a/tests/dbus/test_dbus_client.cpp +++ b/tests/dbus/test_dbus_client.cpp @@ -117,6 +117,8 @@ int main() std::vector masterKey = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; uint16_t channel = 11; + std::string region; + uint32_t channelMask; for (auto &&result : aResult) { @@ -130,6 +132,18 @@ int main() cfg.mDeviceType = true; api->SetLinkMode(cfg); + api->SetRegion("US"); + api->GetRegion(region); + TEST_ASSERT(region == "US"); + api->GetSupportedChannelMask(channelMask); + TEST_ASSERT((channelMask & (1 << 26)) == 0); + + api->SetRegion("WW"); + api->GetRegion(region); + TEST_ASSERT(region == "WW"); + api->GetSupportedChannelMask(channelMask); + TEST_ASSERT((channelMask & (1 << 26)) != 0); + api->Attach("Test", 0x3456, extpanid, masterKey, {}, 1 << channel, [&api, channel, extpanid](ClientError aError) { printf("Attach result %d\n", static_cast(aError)); From 31e3e98757439ce4f573e9060e463f607fbb47f6 Mon Sep 17 00:00:00 2001 From: kangping Date: Mon, 2 Nov 2020 23:17:05 +0800 Subject: [PATCH 012/175] [rest] update following openthread API changes (#598) --- src/openwrt/ubus/otubus.cpp | 22 ++++++++++++++++------ src/openwrt/ubus/otubus.hpp | 9 +++++++-- src/rest/resource.cpp | 20 ++++++++++++++++---- src/rest/resource.hpp | 19 ++++++------------- third_party/openthread/repo | 2 +- 5 files changed, 46 insertions(+), 26 deletions(-) diff --git a/src/openwrt/ubus/otubus.cpp b/src/openwrt/ubus/otubus.cpp index d50e344db6a..d9f62977b67 100644 --- a/src/openwrt/ubus/otubus.cpp +++ b/src/openwrt/ubus/otubus.cpp @@ -1304,10 +1304,12 @@ int UbusServer::UbusGetInformation(struct ubus_context * aContext, return 0; } -void UbusServer::HandleDiagnosticGetResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo, void *aContext) +void UbusServer::HandleDiagnosticGetResponse(otError aError, + otMessage * aMessage, + const otMessageInfo *aMessageInfo, + void * aContext) { - static_cast(aContext)->HandleDiagnosticGetResponse(aMessage, - *static_cast(aMessageInfo)); + static_cast(aContext)->HandleDiagnosticGetResponse(aError, aMessage, aMessageInfo); } static bool IsRoutingLocator(const otIp6Address *aAddress) @@ -1322,7 +1324,7 @@ static bool IsRoutingLocator(const otIp6Address *aAddress) aAddress->mFields.m8[14] < kAloc16Mask && (aAddress->mFields.m8[14] & kRloc16ReservedBitMask) == 0); } -void UbusServer::HandleDiagnosticGetResponse(otMessage *aMessage, const otMessageInfo &aMessageInfo) +void UbusServer::HandleDiagnosticGetResponse(otError aError, otMessage *aMessage, const otMessageInfo *aMessageInfo) { uint16_t rloc16; uint16_t sockRloc16 = 0; @@ -1332,14 +1334,16 @@ void UbusServer::HandleDiagnosticGetResponse(otMessage *aMessage, const otMessag otNetworkDiagTlv diagTlv; otNetworkDiagIterator iterator = OT_NETWORK_DIAGNOSTIC_ITERATOR_INIT; + SuccessOrExit(aError); + char networkdata[20]; sprintf(networkdata, "networkdata%d", sBufNum); sJsonUri = blobmsg_open_table(&mNetworkdataBuf, networkdata); sBufNum++; - if (IsRoutingLocator(&aMessageInfo.mSockAddr)) + if (IsRoutingLocator(&aMessageInfo->mSockAddr)) { - sockRloc16 = aMessageInfo.mPeerAddr.mFields.m16[7]; + sockRloc16 = aMessageInfo->mPeerAddr.mFields.m16[7]; sprintf(xrloc, "0x%04x", sockRloc16); blobmsg_add_string(&mNetworkdataBuf, "rloc", xrloc); } @@ -1409,6 +1413,12 @@ void UbusServer::HandleDiagnosticGetResponse(otMessage *aMessage, const otMessag } blobmsg_close_table(&mNetworkdataBuf, sJsonUri); + +exit: + if (aError != OT_ERROR_NONE) + { + otbrLog(OTBR_LOG_WARNING, "failed to receive diagnostic response: %s", otThreadErrorToString(aError)); + } } int UbusServer::UbusSetInformation(struct ubus_context * aContext, diff --git a/src/openwrt/ubus/otubus.hpp b/src/openwrt/ubus/otubus.hpp index f5c0e3ad13f..d1c9f47c94d 100644 --- a/src/openwrt/ubus/otubus.hpp +++ b/src/openwrt/ubus/otubus.hpp @@ -757,21 +757,26 @@ class UbusServer /** * This method handle initial diagnostic get response. * + * @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. * @param[in] aContext A pointer to the context. * */ - static void HandleDiagnosticGetResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo, void *aContext); + static void HandleDiagnosticGetResponse(otError aError, + otMessage * aMessage, + const otMessageInfo *aMessageInfo, + void * aContext); /** * This method handle diagnosticget response. * + * @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(otMessage *aMessage, const otMessageInfo &aMessageInfo); + void HandleDiagnosticGetResponse(otError aError, otMessage *aMessage, const otMessageInfo *aMessageInfo); private: bool mIfFinishScan; diff --git a/src/rest/resource.cpp b/src/rest/resource.cpp index 865e1e6728b..8d7519b76a9 100644 --- a/src/rest/resource.cpp +++ b/src/rest/resource.cpp @@ -545,13 +545,15 @@ void Resource::Diagnostic(const Request &aRequest, Response &aResponse) const } } -void Resource::DiagnosticResponseHandler(otMessage *aMessage, const otMessageInfo *aMessageInfo, void *aContext) +void Resource::DiagnosticResponseHandler(otError aError, + otMessage * aMessage, + const otMessageInfo *aMessageInfo, + void * aContext) { - static_cast(aContext)->DiagnosticResponseHandler(aMessage, - *static_cast(aMessageInfo)); + static_cast(aContext)->DiagnosticResponseHandler(aError, aMessage, aMessageInfo); } -void Resource::DiagnosticResponseHandler(otMessage *aMessage, const otMessageInfo) +void Resource::DiagnosticResponseHandler(otError aError, const otMessage *aMessage, const otMessageInfo *aMessageInfo) { std::vector diagSet; otNetworkDiagTlv diagTlv; @@ -560,6 +562,10 @@ void Resource::DiagnosticResponseHandler(otMessage *aMessage, const otMessageInf char rloc[7]; std::string keyRloc = "0xffee"; + SuccessOrExit(aError); + + (void)aMessageInfo; + while ((error = otThreadGetNextDiagnosticTlv(aMessage, &iterator, &diagTlv)) == OT_ERROR_NONE) { if (diagTlv.mType == OT_NETWORK_DIAGNOSTIC_TLV_SHORT_ADDRESS) @@ -570,6 +576,12 @@ void Resource::DiagnosticResponseHandler(otMessage *aMessage, const otMessageInf diagSet.push_back(diagTlv); } UpdateDiag(keyRloc, diagSet); + +exit: + if (aError != OT_ERROR_NONE) + { + otbrLog(OTBR_LOG_WARNING, "failed to get diagnostic data: %s", otThreadErrorToString(aError)); + } } } // namespace rest diff --git a/src/rest/resource.hpp b/src/rest/resource.hpp index 80c9aca79b5..51efcafd92a 100644 --- a/src/rest/resource.hpp +++ b/src/rest/resource.hpp @@ -101,18 +101,6 @@ class Resource */ void ErrorHandler(Response &aResponse, HttpStatusCode aErrorCode) const; - /** - * This method is a pre-defined callback function used for call another private method when diagnostic information - * arrives. - * - * @param[in] aMessage A pointer to the message buffer containing the received Network Diagnostic - * Get response payload. - * @param[in] aMessageInfo A pointer to the message info for @p aMessage . - * @param[in] aContext A pointer to application-specific context. - * - */ - static void DiagnosticResponseHandler(otMessage *aMessage, const otMessageInfo *aMessageInfo, void *aContext); - private: typedef void (Resource::*ResourceHandler)(const Request &aRequest, Response &aResponse) const; typedef void (Resource::*ResourceCallbackHandler)(const Request &aRequest, Response &aResponse); @@ -140,7 +128,12 @@ class Resource void DeleteOutDatedDiagnostic(void); void UpdateDiag(std::string aKey, std::vector &aDiag); - void DiagnosticResponseHandler(otMessage *aMessage, const otMessageInfo); + + static void DiagnosticResponseHandler(otError aError, + otMessage * aMessage, + const otMessageInfo *aMessageInfo, + void * aContext); + void DiagnosticResponseHandler(otError aError, const otMessage *aMessage, const otMessageInfo *aMessageInfo); otInstance * mInstance; ControllerOpenThread *mNcp; diff --git a/third_party/openthread/repo b/third_party/openthread/repo index 8707b638942..fc159a706f0 160000 --- a/third_party/openthread/repo +++ b/third_party/openthread/repo @@ -1 +1 @@ -Subproject commit 8707b638942fa396fe0c3c11a918f79082aadb8e +Subproject commit fc159a706f0f1fbdffb526cad8e5847209dd6b14 From e5b713c2103de3219845643233c381d3d40dfbec Mon Sep 17 00:00:00 2001 From: IHIDCHAOS Date: Mon, 2 Nov 2020 23:19:34 +0800 Subject: [PATCH 013/175] [openwrt] fix otbr attempt to call global 'threadget' (a nil value) (#602) On OpenWrt 19.07, modify the order to avoid call "connect_ubus" and "threadget" failed. --- src/openwrt/view/admin_thread/thread_setting.htm | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/openwrt/view/admin_thread/thread_setting.htm b/src/openwrt/view/admin_thread/thread_setting.htm index cfc16776767..aba88ea3c27 100644 --- a/src/openwrt/view/admin_thread/thread_setting.htm +++ b/src/openwrt/view/admin_thread/thread_setting.htm @@ -2,7 +2,6 @@ local ubus = require "ubus" local sys = require "luci.sys" local utl = require "luci.util" - local state = threadget("state").State function connect_ubus(methods) local result @@ -17,6 +16,16 @@ return result end + function threadget(action) + local result = connect_ubus(action) + + return result + end + + local state = threadget("state").State + + + function addrlist() local k, v local l = { } @@ -30,11 +39,7 @@ return l end - function threadget(action) - local result = connect_ubus(action) - return result - end -%> <%+header%> From d6138832f4c8794cef76f7d085d93643c9e1de87 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Tue, 3 Nov 2020 22:49:08 +0800 Subject: [PATCH 014/175] [backbone-router] implement Backbone ND proxy (#581) This commit implements the ND Proxy on OTBR for Thread 1.2 DUA feature: - Add NdProxyManager for ND Proxy Management - Start NdProxyManager if BBR is Primary and Domain Prefix is set - Stop NdProxyManager if BBR is not Primary or Domain Prefix is not set - Send Neighbor Advertisement (NA) for DUA registration (registered or renewed) - Receive and respond to Neighbor Solicitation (Multicast) - Join the solicited node multicast group for DUAs - Receive Neighbor Solicitation messages using raw ICMPv6 socket - Receive and respond to Neighbor Solicitation (Unicast) - Use ip6tables to redirect Neighbor Solicitation (Unicast) messages to nfqueue - Receive and handle Neighbor Solicitation (Unicast) from nfqueue (verified that it works) --- etc/docker/Dockerfile | 2 +- script/bootstrap | 3 + src/agent/border_agent.cpp | 7 + src/agent/border_agent.hpp | 5 +- src/agent/ncp.hpp | 2 + src/agent/ncp_openthread.cpp | 29 ++ src/agent/ncp_openthread.hpp | 11 + src/backbone_router/CMakeLists.txt | 2 + src/backbone_router/backbone_agent.cpp | 80 ++++ src/backbone_router/backbone_agent.hpp | 51 ++- src/backbone_router/constants.hpp | 71 +++ src/backbone_router/nd_proxy.cpp | 573 +++++++++++++++++++++++++ src/backbone_router/nd_proxy.hpp | 189 ++++++++ src/common/code_utils.hpp | 6 + src/common/logging.cpp | 24 +- src/common/types.cpp | 73 ++++ src/common/types.hpp | 197 ++++++++- third_party/openthread/repo | 2 +- tools/CMakeLists.txt | 1 + 19 files changed, 1307 insertions(+), 21 deletions(-) create mode 100644 src/backbone_router/constants.hpp create mode 100644 src/backbone_router/nd_proxy.cpp create mode 100644 src/backbone_router/nd_proxy.hpp diff --git a/etc/docker/Dockerfile b/etc/docker/Dockerfile index 25e328ae9c6..e61b71509eb 100644 --- a/etc/docker/Dockerfile +++ b/etc/docker/Dockerfile @@ -61,7 +61,7 @@ ENV OTBR_DOCKER_DEPS git ca-certificates 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 \ libavahi-client-dev libboost-dev libboost-filesystem-dev libboost-system-dev libjsoncpp-dev \ - autoconf automake pkg-config + autoconf automake pkg-config libnetfilter-queue-dev # Required for OpenThread Backbone CI ENV OTBR_OT_BACKBONE_CI_DEPS curl lcov diff --git a/script/bootstrap b/script/bootstrap index dae7d568581..e6a6c63041a 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -89,6 +89,9 @@ install_packages_apt() # reference device without REFERENCE_DEVICE || sudo apt-get install --no-install-recommends -y radvd + + # backbone-router + without BACKBONE_ROUTER || sudo apt-get install --no-install-recommends -y iptables libnetfilter-queue1 libnetfilter-queue-dev } install_packages_opkg() diff --git a/src/agent/border_agent.cpp b/src/agent/border_agent.cpp index 49a39890a55..cb927854a86 100644 --- a/src/agent/border_agent.cpp +++ b/src/agent/border_agent.cpp @@ -180,6 +180,10 @@ void BorderAgent::UpdateFdSet(fd_set & aReadFdSet, int & aMaxFd, timeval &aTimeout) { +#if OTBR_ENABLE_BACKBONE_ROUTER + mBackboneAgent.UpdateFdSet(aReadFdSet, aWriteFdSet, aErrorFdSet, aMaxFd, aTimeout); +#endif + if (mPublisher != nullptr) { mPublisher->UpdateFdSet(aReadFdSet, aWriteFdSet, aErrorFdSet, aMaxFd, aTimeout); @@ -188,6 +192,9 @@ void BorderAgent::UpdateFdSet(fd_set & aReadFdSet, void BorderAgent::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet, const fd_set &aErrorFdSet) { +#if OTBR_ENABLE_BACKBONE_ROUTER + mBackboneAgent.Process(aReadFdSet, aWriteFdSet, aErrorFdSet); +#endif if (mPublisher != nullptr) { mPublisher->Process(aReadFdSet, aWriteFdSet, aErrorFdSet); diff --git a/src/agent/border_agent.hpp b/src/agent/border_agent.hpp index 96115f01e89..e7ca30ef67f 100644 --- a/src/agent/border_agent.hpp +++ b/src/agent/border_agent.hpp @@ -38,9 +38,12 @@ #include "agent/instance_params.hpp" #include "agent/ncp.hpp" -#include "backbone_router/backbone_agent.hpp" #include "mdns/mdns.hpp" +#if OTBR_ENABLE_BACKBONE_ROUTER +#include "backbone_router/backbone_agent.hpp" +#endif + namespace otbr { /** diff --git a/src/agent/ncp.hpp b/src/agent/ncp.hpp index 8dbd1b9d1ef..5973cdded13 100644 --- a/src/agent/ncp.hpp +++ b/src/agent/ncp.hpp @@ -69,6 +69,8 @@ enum kEventThreadVersion, ///< Thread Version. kEventUdpForwardStream, ///< UDP forward stream arrived. kEventBackboneRouterState, ///< Backbone Router State. + kEventBackboneRouterDomainPrefixEvent, ///< Backbone Router Domain Prefix event. + kEventBackboneRouterNdProxyEvent, ///< Backbone Router ND Proxy event arrived. kEventBackboneRouterMulticastListenerEvent, ///< Backbone Router Multicast Listener event arrived. }; diff --git a/src/agent/ncp_openthread.cpp b/src/agent/ncp_openthread.cpp index cd8837b5845..ee2519c6d3f 100644 --- a/src/agent/ncp_openthread.cpp +++ b/src/agent/ncp_openthread.cpp @@ -124,6 +124,9 @@ otbrError ControllerOpenThread::Init(void) } #if OTBR_ENABLE_BACKBONE_ROUTER + otBackboneRouterSetDomainPrefixCallback(mInstance, &ControllerOpenThread::HandleBackboneRouterDomainPrefixEvent, + this); + otBackboneRouterSetNdProxyCallback(mInstance, &ControllerOpenThread::HandleBackboneRouterNdProxyEvent, this); otBackboneRouterSetMulticastListenerCallback( mInstance, &ControllerOpenThread::HandleBackboneRouterMulticastListenerEvent, this); #endif @@ -320,6 +323,32 @@ void ControllerOpenThread::RegisterResetHandler(std::function aHandl } #if OTBR_ENABLE_BACKBONE_ROUTER +void ControllerOpenThread::HandleBackboneRouterDomainPrefixEvent(void * aContext, + otBackboneRouterDomainPrefixEvent aEvent, + const otIp6Prefix * aDomainPrefix) +{ + static_cast(aContext)->HandleBackboneRouterDomainPrefixEvent(aEvent, aDomainPrefix); +} + +void ControllerOpenThread::HandleBackboneRouterDomainPrefixEvent(otBackboneRouterDomainPrefixEvent aEvent, + const otIp6Prefix * aDomainPrefix) +{ + EventEmitter::Emit(kEventBackboneRouterDomainPrefixEvent, aEvent, aDomainPrefix); +} + +void ControllerOpenThread::HandleBackboneRouterNdProxyEvent(void * aContext, + otBackboneRouterNdProxyEvent aEvent, + const otIp6Address * aAddress) +{ + static_cast(aContext)->HandleBackboneRouterNdProxyEvent(aEvent, aAddress); +} + +void ControllerOpenThread::HandleBackboneRouterNdProxyEvent(otBackboneRouterNdProxyEvent aEvent, + const otIp6Address * aAddress) +{ + EventEmitter::Emit(kEventBackboneRouterNdProxyEvent, aEvent, aAddress); +} + void ControllerOpenThread::HandleBackboneRouterMulticastListenerEvent(void * aContext, otBackboneRouterMulticastListenerEvent aEvent, const otIp6Address * aAddress) diff --git a/src/agent/ncp_openthread.hpp b/src/agent/ncp_openthread.hpp index 0ad3915f38e..be52e55082c 100644 --- a/src/agent/ncp_openthread.hpp +++ b/src/agent/ncp_openthread.hpp @@ -173,6 +173,17 @@ class ControllerOpenThread : public Controller } void HandleStateChanged(otChangedFlags aFlags); + static void HandleBackboneRouterDomainPrefixEvent(void * aContext, + otBackboneRouterDomainPrefixEvent aEvent, + const otIp6Prefix * aDomainPrefix); + void HandleBackboneRouterDomainPrefixEvent(otBackboneRouterDomainPrefixEvent aEvent, + const otIp6Prefix * aDomainPrefix); + + static void HandleBackboneRouterNdProxyEvent(void * aContext, + otBackboneRouterNdProxyEvent aEvent, + const otIp6Address * aAddress); + void HandleBackboneRouterNdProxyEvent(otBackboneRouterNdProxyEvent aEvent, const otIp6Address *aAddress); + static void HandleBackboneRouterMulticastListenerEvent(void * aContext, otBackboneRouterMulticastListenerEvent aEvent, const otIp6Address * aAddress); diff --git a/src/backbone_router/CMakeLists.txt b/src/backbone_router/CMakeLists.txt index 7614ccd7fe9..84d1b9a62f6 100644 --- a/src/backbone_router/CMakeLists.txt +++ b/src/backbone_router/CMakeLists.txt @@ -28,10 +28,12 @@ add_library(otbr-backbone-router backbone_agent.cpp + nd_proxy.cpp smcroute_manager.cpp ) target_link_libraries(otbr-backbone-router PRIVATE otbr-common otbr-utils + netfilter_queue ) diff --git a/src/backbone_router/backbone_agent.cpp b/src/backbone_router/backbone_agent.cpp index 8b8e071a6a7..2a61df5cd7e 100644 --- a/src/backbone_router/backbone_agent.cpp +++ b/src/backbone_router/backbone_agent.cpp @@ -34,6 +34,8 @@ #include "backbone_router/backbone_agent.hpp" #include +#include + #include #include "common/code_utils.hpp" @@ -44,14 +46,18 @@ namespace BackboneRouter { BackboneAgent::BackboneAgent(otbr::Ncp::ControllerOpenThread &aNcp) : mNcp(aNcp) , mBackboneRouterState(OT_BACKBONE_ROUTER_STATE_DISABLED) + , mNdProxyManager(aNcp) { } void BackboneAgent::Init(void) { mNcp.On(Ncp::kEventBackboneRouterState, HandleBackboneRouterState, this); + mNcp.On(Ncp::kEventBackboneRouterDomainPrefixEvent, HandleBackboneRouterDomainPrefixEvent, this); + mNcp.On(Ncp::kEventBackboneRouterNdProxyEvent, HandleBackboneRouterNdProxyEvent, this); mNcp.On(Ncp::kEventBackboneRouterMulticastListenerEvent, HandleBackboneRouterMulticastListenerEvent, this); + mNdProxyManager.Init(); mSMCRouteManager.Init(); HandleBackboneRouterState(); @@ -126,6 +132,11 @@ void BackboneAgent::OnBecomePrimary(void) { otbrLog(OTBR_LOG_NOTICE, "BackboneAgent: Backbone Router becomes Primary!"); + if (mDomainPrefix.IsValid()) + { + mNdProxyManager.Enable(mDomainPrefix); + } + mSMCRouteManager.Enable(); } @@ -134,6 +145,7 @@ void BackboneAgent::OnResignPrimary(void) otbrLog(OTBR_LOG_NOTICE, "BackboneAgent: Backbone Router resigns Primary to %s!", StateToString(mBackboneRouterState)); + mNdProxyManager.Disable(); mSMCRouteManager.Disable(); } @@ -156,6 +168,74 @@ const char *BackboneAgent::StateToString(otBackboneRouterState aState) return ret; } +void BackboneAgent::UpdateFdSet(fd_set & aReadFdSet, + fd_set & aWriteFdSet, + fd_set & aErrorFdSet, + int & aMaxFd, + timeval &aTimeout) const +{ + mNdProxyManager.UpdateFdSet(aReadFdSet, aWriteFdSet, aErrorFdSet, aMaxFd, aTimeout); +} + +void BackboneAgent::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet, const fd_set &aErrorFdSet) +{ + mNdProxyManager.Process(aReadFdSet, aWriteFdSet, aErrorFdSet); +} + +void BackboneAgent::HandleBackboneRouterDomainPrefixEvent(void *aContext, int aEvent, va_list aArguments) +{ + OT_UNUSED_VARIABLE(aEvent); + + otBackboneRouterDomainPrefixEvent event; + const otIp6Prefix * domainPrefix; + + assert(aEvent == Ncp::kEventBackboneRouterDomainPrefixEvent); + + event = static_cast(va_arg(aArguments, int)); + domainPrefix = va_arg(aArguments, const otIp6Prefix *); + static_cast(aContext)->HandleBackboneRouterDomainPrefixEvent(event, domainPrefix); +} + +void BackboneAgent::HandleBackboneRouterDomainPrefixEvent(otBackboneRouterDomainPrefixEvent aEvent, + const otIp6Prefix * aDomainPrefix) +{ + if (aEvent == OT_BACKBONE_ROUTER_DOMAIN_PREFIX_REMOVED) + { + mDomainPrefix.Clear(); + } + else + { + assert(aDomainPrefix != nullptr); + mDomainPrefix.Set(*aDomainPrefix); + assert(mDomainPrefix.IsValid()); + } + + VerifyOrExit(IsPrimary() && aEvent != OT_BACKBONE_ROUTER_DOMAIN_PREFIX_REMOVED); + + mNdProxyManager.Disable(); + mNdProxyManager.Enable(mDomainPrefix); +exit: + return; +} + +void BackboneAgent::HandleBackboneRouterNdProxyEvent(void *aContext, int aEvent, va_list aArguments) +{ + OT_UNUSED_VARIABLE(aEvent); + + otBackboneRouterNdProxyEvent event; + const otIp6Address * address; + + assert(aEvent == Ncp::kEventBackboneRouterNdProxyEvent); + + event = static_cast(va_arg(aArguments, int)); + address = va_arg(aArguments, const otIp6Address *); + static_cast(aContext)->HandleBackboneRouterNdProxyEvent(event, address); +} + +void BackboneAgent::HandleBackboneRouterNdProxyEvent(otBackboneRouterNdProxyEvent aEvent, const otIp6Address *aDua) +{ + mNdProxyManager.HandleBackboneRouterNdProxyEvent(aEvent, aDua); +} } // namespace BackboneRouter } // namespace otbr diff --git a/src/backbone_router/backbone_agent.hpp b/src/backbone_router/backbone_agent.hpp index 1d8cd9a5390..1ca1220384c 100644 --- a/src/backbone_router/backbone_agent.hpp +++ b/src/backbone_router/backbone_agent.hpp @@ -38,6 +38,7 @@ #include "agent/instance_params.hpp" #include "agent/ncp_openthread.hpp" +#include "backbone_router/nd_proxy.hpp" #include "backbone_router/smcroute_manager.hpp" namespace otbr { @@ -73,20 +74,54 @@ class BackboneAgent */ void Init(void); + /** + * This method updates the fd_set and timeout for mainloop. + * + * @param[inout] aReadFdSet A reference to fd_set for polling read. + * @param[inout] aWriteFdSet A reference to fd_set for polling read. + * @param[inout] aErrorFdSet A reference to fd_set for polling error. + * @param[inout] aMaxFd A reference to the current max fd in @p aReadFdSet and @p aWriteFdSet. + * @param[inout] aTimeout A reference to the timeout. + * + */ + void UpdateFdSet(fd_set & aReadFdSet, + fd_set & aWriteFdSet, + fd_set & aErrorFdSet, + int & aMaxFd, + timeval &aTimeout) const; + + /** + * This method performs border agent processing. + * + * @param[in] aReadFdSet A reference to read file descriptors. + * @param[in] aWriteFdSet A reference to write file descriptors. + * @param[in] aErrorFdSet A reference to error file descriptors. + * + */ + void Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet, const fd_set &aErrorFdSet); + private: - void OnBecomePrimary(void); - void OnResignPrimary(void); - bool IsPrimary(void) const { return mBackboneRouterState == OT_BACKBONE_ROUTER_STATE_PRIMARY; } - static void HandleBackboneRouterState(void *aContext, int aEvent, va_list aArguments); - void HandleBackboneRouterState(void); - static void HandleBackboneRouterMulticastListenerEvent(void *aContext, int aEvent, va_list aArguments); - void HandleBackboneRouterMulticastListenerEvent(otBackboneRouterMulticastListenerEvent aEvent, - const otIp6Address & aAddress); + void OnBecomePrimary(void); + void OnResignPrimary(void); + bool IsPrimary(void) const { return mBackboneRouterState == OT_BACKBONE_ROUTER_STATE_PRIMARY; } + static void HandleBackboneRouterState(void *aContext, int aEvent, va_list aArguments); + void HandleBackboneRouterState(void); + static void HandleBackboneRouterDomainPrefixEvent(void *aContext, int aEvent, va_list aArguments); + void HandleBackboneRouterDomainPrefixEvent(otBackboneRouterDomainPrefixEvent aEvent, + const otIp6Prefix * aDomainPrefix); + static void HandleBackboneRouterNdProxyEvent(void *aContext, int aEvent, va_list aArguments); + void HandleBackboneRouterNdProxyEvent(otBackboneRouterNdProxyEvent aEvent, const otIp6Address *aAddress); + static void HandleBackboneRouterMulticastListenerEvent(void *aContext, int aEvent, va_list aArguments); + void HandleBackboneRouterMulticastListenerEvent(otBackboneRouterMulticastListenerEvent aEvent, + const otIp6Address & aAddress); + static const char *StateToString(otBackboneRouterState aState); otbr::Ncp::ControllerOpenThread &mNcp; otBackboneRouterState mBackboneRouterState; SMCRouteManager mSMCRouteManager; + NdProxyManager mNdProxyManager; + Ip6Prefix mDomainPrefix; }; #endif // OTBR_ENABLE_BACKBONE_ROUTER diff --git a/src/backbone_router/constants.hpp b/src/backbone_router/constants.hpp new file mode 100644 index 00000000000..836eeb1a820 --- /dev/null +++ b/src/backbone_router/constants.hpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes definition for Thread Backbone constants. + */ + +#ifndef BACKBONE_CONSTANTS_HPP_ +#define BACKBONE_CONSTANTS_HPP_ + +#include + +#include "agent/ncp_openthread.hpp" +#include "backbone_router/nd_proxy.hpp" +#include "backbone_router/smcroute_manager.hpp" + +namespace otbr { +namespace BackboneRouter { + +/** + * @addtogroup border-router-bbr + * + * @brief + * This module includes definition for Thread Backbone constants. + * + * @{ + */ + +/** + * Backbone configurations. + * + */ +enum +{ + kDuaRecentTime = 20, ///< Time period (in seconds) during which a DUA registration is considered 'recent' at a BBR. +}; + +/** + * @} + */ + +} // namespace BackboneRouter +} // namespace otbr + +#endif // BACKBONE_CONSTANTS_HPP_ diff --git a/src/backbone_router/nd_proxy.cpp b/src/backbone_router/nd_proxy.cpp new file mode 100644 index 00000000000..897d814aad8 --- /dev/null +++ b/src/backbone_router/nd_proxy.cpp @@ -0,0 +1,573 @@ +/* + * Copyright (c) 2020, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * The file implements the ND Proxy management. + */ + +#include "backbone_router/nd_proxy.hpp" + +#include + +#include +#include +#include +#include +#include +#include + +#if __linux__ +#include +#else +#error "Platform not supported" +#endif + +#include "backbone_router/constants.hpp" +#include "common/code_utils.hpp" +#include "common/logging.hpp" +#include "common/types.hpp" + +namespace otbr { +namespace BackboneRouter { + +void NdProxyManager::Enable(const Ip6Prefix &aDomainPrefix) +{ + otbrError error = OTBR_ERROR_NONE; + + VerifyOrExit(!IsEnabled()); + + assert(aDomainPrefix.IsValid()); + mDomainPrefix = aDomainPrefix; + + SuccessOrExit(error = InitIcmp6RawSocket()); + SuccessOrExit(error = UpdateMacAddress()); + SuccessOrExit(error = InitNetfilterQueue()); + + // Add ip6tables rule for unicast ICMPv6 messages + VerifyOrExit(SystemUtils::ExecuteCommand( + "ip6tables -t raw -A PREROUTING -6 -d %s -p icmpv6 --icmpv6-type neighbor-solicitation -i %s -j " + "NFQUEUE --queue-num 88", + mDomainPrefix.ToString().c_str(), InstanceParams::Get().GetBackboneIfName()) == 0, + error = OTBR_ERROR_ERRNO); + +exit: + if (error != OTBR_ERROR_NONE) + { + FiniNetfilterQueue(); + FiniIcmp6RawSocket(); + } + + otbrLogResult(error, "NdProxyManager: %s", __FUNCTION__); +} + +void NdProxyManager::Disable(void) +{ + otbrError error = OTBR_ERROR_NONE; + + VerifyOrExit(IsEnabled()); + + FiniNetfilterQueue(); + FiniIcmp6RawSocket(); + + // Remove ip6tables rule for unicast ICMPv6 messages + VerifyOrExit(SystemUtils::ExecuteCommand( + "ip6tables -t raw -D PREROUTING -6 -d %s -p icmpv6 --icmpv6-type neighbor-solicitation -i %s -j " + "NFQUEUE --queue-num 88", + mDomainPrefix.ToString().c_str(), InstanceParams::Get().GetBackboneIfName()) == 0, + error = OTBR_ERROR_ERRNO); + +exit: + otbrLogResult(error, "NdProxyManager: %s", __FUNCTION__); +} + +void NdProxyManager::Init(void) +{ + mBackboneIfIndex = if_nametoindex(InstanceParams::Get().GetBackboneIfName()); + VerifyOrDie(mBackboneIfIndex > 0, "if_nametoindex failed"); +} + +void NdProxyManager::UpdateFdSet(fd_set & aReadFdSet, + fd_set & aWriteFdSet, + fd_set & aErrorFdSet, + int & aMaxFd, + timeval &aTimeout) const +{ + OTBR_UNUSED_VARIABLE(aWriteFdSet); + OTBR_UNUSED_VARIABLE(aErrorFdSet); + OTBR_UNUSED_VARIABLE(aTimeout); + + if (mIcmp6RawSock >= 0) + { + FD_SET(mIcmp6RawSock, &aReadFdSet); + aMaxFd = std::max(aMaxFd, mIcmp6RawSock); + } + + if (mUnicastNsQueueSock >= 0) + { + FD_SET(mUnicastNsQueueSock, &aReadFdSet); + aMaxFd = std::max(aMaxFd, mUnicastNsQueueSock); + } +} + +void NdProxyManager::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet, const fd_set &aErrorFdSet) +{ + OTBR_UNUSED_VARIABLE(aWriteFdSet); + OTBR_UNUSED_VARIABLE(aErrorFdSet); + + VerifyOrExit(IsEnabled()); + + if (FD_ISSET(mIcmp6RawSock, &aReadFdSet)) + { + ProcessMulticastNeighborSolicition(); + } + + if (FD_ISSET(mUnicastNsQueueSock, &aReadFdSet)) + { + ProcessUnicastNeighborSolicition(); + } +exit: + return; +} + +void NdProxyManager::ProcessMulticastNeighborSolicition() +{ + struct msghdr msghdr; + sockaddr_in6 sin6; + struct iovec iovec; + ssize_t len; + struct icmp6_hdr *icmp6header; + struct cmsghdr * cmsghdr; + unsigned char cbuf[2 * CMSG_SPACE(sizeof(struct in6_pktinfo))]; + uint8_t packet[kMaxICMP6PacketSize]; + otbrError error = OTBR_ERROR_NONE; + bool found = false; + + iovec.iov_len = kMaxICMP6PacketSize; + iovec.iov_base = packet; + + msghdr.msg_name = &sin6; + msghdr.msg_namelen = sizeof(sin6); + msghdr.msg_iov = &iovec; + msghdr.msg_iovlen = 1; + msghdr.msg_control = cbuf; + msghdr.msg_controllen = sizeof(cbuf); + + len = recvmsg(mIcmp6RawSock, &msghdr, 0); + + VerifyOrExit(len >= static_cast(sizeof(struct icmp6_hdr)), error = OTBR_ERROR_ERRNO); + + { + Ip6Address &src = *reinterpret_cast(&sin6.sin6_addr); + + icmp6header = reinterpret_cast(packet); + + // only process neighbor solicit + VerifyOrExit(icmp6header->icmp6_type == ND_NEIGHBOR_SOLICIT, error = OTBR_ERROR_PARSE); + + otbrLog(OTBR_LOG_DEBUG, "NdProxyManager: Received ND-NS from %s", src.ToString().c_str()); + + for (cmsghdr = CMSG_FIRSTHDR(&msghdr); cmsghdr; cmsghdr = CMSG_NXTHDR(&msghdr, cmsghdr)) + { + if (cmsghdr->cmsg_level != IPPROTO_IPV6) + { + continue; + } + + switch (cmsghdr->cmsg_type) + { + case IPV6_PKTINFO: + if (cmsghdr->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) + { + struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsghdr); + Ip6Address & dst = *reinterpret_cast(&pktinfo->ipi6_addr); + uint32_t ifindex = pktinfo->ipi6_ifindex; + + for (const Ip6Address &ipaddr : mNdProxySet) + { + if (ipaddr.ToSolicitedNodeMulticastAddress() == dst) + { + found = true; + break; + } + } + + otbrLog(OTBR_LOG_DEBUG, "NdProxyManager: dst=%s, ifindex=%d, proxying=%s", dst.ToString().c_str(), + ifindex, found ? "Y" : "N"); + } + break; + + case IPV6_HOPLIMIT: + if (cmsghdr->cmsg_len == CMSG_LEN(sizeof(int))) + { + int hops = *(int *)CMSG_DATA(cmsghdr); + + otbrLog(OTBR_LOG_DEBUG, "NdProxyManager: hops=%d (%s)", hops, hops == 255 ? "Good" : "Bad"); + + VerifyOrExit(hops == 255); + } + break; + } + } + + VerifyOrExit(found, error = OTBR_ERROR_NOT_FOUND); + + { + struct nd_neighbor_solicit *ns = reinterpret_cast(packet); + Ip6Address & target = *reinterpret_cast(&ns->nd_ns_target); + + otbrLog(OTBR_LOG_INFO, "NdProxyManager: send solicited NA for multicast NS: src=%s, target=%s", + src.ToString().c_str(), target.ToString().c_str()); + + SendNeighborAdvertisement(target, src); + } + } + +exit: + otbrLogResult(error, "NdProxyManager: %s", __FUNCTION__); +} + +void NdProxyManager::ProcessUnicastNeighborSolicition(void) +{ + otbrError error = OTBR_ERROR_NONE; + char packet[kMaxICMP6PacketSize]; + ssize_t len; + + VerifyOrExit((len = recv(mUnicastNsQueueSock, packet, sizeof(packet), 0)) >= 0, error = OTBR_ERROR_ERRNO); + VerifyOrExit(nfq_handle_packet(mNfqHandler, packet, len) == 0, error = OTBR_ERROR_ERRNO); + + error = OTBR_ERROR_NONE; + +exit: + otbrLogResult(error, "NdProxyManager: %s", __FUNCTION__); +} + +void NdProxyManager::HandleBackboneRouterNdProxyEvent(otBackboneRouterNdProxyEvent aEvent, const otIp6Address *aDua) +{ + Ip6Address target; + + if (aEvent != OT_BACKBONE_ROUTER_NDPROXY_CLEARED) + { + assert(aDua != nullptr); + target = Ip6Address(aDua->mFields.m8); + } + + switch (aEvent) + { + case OT_BACKBONE_ROUTER_NDPROXY_ADDED: + case OT_BACKBONE_ROUTER_NDPROXY_RENEWED: + { + bool isNewInsert = mNdProxySet.insert(target).second; + + if (isNewInsert) + { + JoinSolicitedNodeMulticastGroup(target); + } + + SendNeighborAdvertisement(target, Ip6Address::GetLinkLocalAllNodesMulticastAddress()); + break; + } + case OT_BACKBONE_ROUTER_NDPROXY_REMOVED: + mNdProxySet.erase(target); + LeaveSolicitedNodeMulticastGroup(target); + break; + case OT_BACKBONE_ROUTER_NDPROXY_CLEARED: + for (const Ip6Address &proxingTarget : mNdProxySet) + { + LeaveSolicitedNodeMulticastGroup(proxingTarget); + } + mNdProxySet.clear(); + break; + } +} + +void NdProxyManager::SendNeighborAdvertisement(const Ip6Address &aTarget, const Ip6Address &aDst) +{ + uint8_t packet[kMaxICMP6PacketSize]; + uint16_t len = 0; + struct nd_neighbor_advert &na = *reinterpret_cast(packet); + struct nd_opt_hdr & opt = *reinterpret_cast(packet + sizeof(struct nd_neighbor_advert)); + bool isSolicited = !aDst.IsMulticast(); + sockaddr_in6 dst; + otbrError error = OTBR_ERROR_NONE; + otBackboneRouterNdProxyInfo aNdProxyInfo; + + VerifyOrExit(otBackboneRouterGetNdProxyInfo(mNcp.GetInstance(), reinterpret_cast(&aTarget), + &aNdProxyInfo) == OT_ERROR_NONE, + error = OTBR_ERROR_OPENTHREAD); + + memset(packet, 0, sizeof(packet)); + + na.nd_na_type = ND_NEIGHBOR_ADVERT; + na.nd_na_code = 0; + // set Solicited + na.nd_na_flags_reserved = isSolicited ? ND_NA_FLAG_SOLICITED : 0; + // set Router + na.nd_na_flags_reserved |= ND_NA_FLAG_ROUTER; + // set Override + na.nd_na_flags_reserved |= aNdProxyInfo.mTimeSinceLastTransaction <= kDuaRecentTime ? ND_NA_FLAG_OVERRIDE : 0; + + memcpy(&na.nd_na_target, aTarget.m8, sizeof(Ip6Address)); + len += sizeof(struct nd_neighbor_advert); + + opt.nd_opt_type = ND_OPT_TARGET_LINKADDR; + opt.nd_opt_len = 1; + + memcpy(reinterpret_cast(&opt) + 2, mMacAddress.m8, sizeof(mMacAddress)); + + len += (opt.nd_opt_len * 8); + + aDst.CopyTo(dst); + + VerifyOrExit(sendto(mIcmp6RawSock, packet, len, 0, reinterpret_cast(&dst), sizeof(dst)) == len, + error = OTBR_ERROR_ERRNO); + +exit: + otbrLogResult(error, "NdProxyManager: %s", __FUNCTION__); +} + +otbrError NdProxyManager::UpdateMacAddress(void) +{ + otbrError error = OTBR_ERROR_NONE; + +#if !__APPLE__ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, InstanceParams::Get().GetBackboneIfName(), sizeof(ifr.ifr_name) - 1); + + VerifyOrExit(ioctl(mIcmp6RawSock, SIOCGIFHWADDR, &ifr) != -1, error = OTBR_ERROR_ERRNO); + memcpy(mMacAddress.m8, ifr.ifr_hwaddr.sa_data, sizeof(mMacAddress)); +#else + ExitNow(error = OTBR_ERROR_NOT_IMPLEMENTED); +#endif +exit: + otbrLogResult(error, "NdProxyManager: UpdateMacAddress to %s", mMacAddress.ToString().c_str()); + return error; +} + +otbrError NdProxyManager::InitIcmp6RawSocket(void) +{ + otbrError error = OTBR_ERROR_NONE; + int on = 1; + int hops = 255; + struct icmp6_filter filter; + + mIcmp6RawSock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + VerifyOrExit(mIcmp6RawSock >= 0, error = OTBR_ERROR_ERRNO); + +#if __linux__ + VerifyOrExit(setsockopt(mIcmp6RawSock, SOL_SOCKET, SO_BINDTODEVICE, InstanceParams::Get().GetBackboneIfName(), + strlen(InstanceParams::Get().GetBackboneIfName())) == 0, + error = OTBR_ERROR_ERRNO); +#else // __NetBSD__ || __FreeBSD__ || __APPLE__ + VerifyOrExit(setsockopt(mIcmp6RawSock, IPPROTO_IP, IP_BOUND_IF, mBackboneIfName.c_str(), mBackboneIfName.size()), + error = OTBR_ERROR_ERRNO); +#endif // __linux__ + + VerifyOrExit(setsockopt(mIcmp6RawSock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) == 0, + error = OTBR_ERROR_ERRNO); + VerifyOrExit(setsockopt(mIcmp6RawSock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)) == 0, + error = OTBR_ERROR_ERRNO); + VerifyOrExit(setsockopt(mIcmp6RawSock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops)) == 0, + error = OTBR_ERROR_ERRNO); + VerifyOrExit(setsockopt(mIcmp6RawSock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, sizeof(hops)) == 0, + error = OTBR_ERROR_ERRNO); + + ICMP6_FILTER_SETBLOCKALL(&filter); + ICMP6_FILTER_SETPASS(ND_NEIGHBOR_SOLICIT, &filter); + + VerifyOrExit(setsockopt(mIcmp6RawSock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) == 0, + error = OTBR_ERROR_ERRNO); +exit: + if (error != OTBR_ERROR_NONE) + { + FiniIcmp6RawSocket(); + } + + return error; +} + +void NdProxyManager::FiniIcmp6RawSocket(void) +{ + if (mIcmp6RawSock != -1) + { + close(mIcmp6RawSock); + mIcmp6RawSock = -1; + } +} + +otbrError NdProxyManager::InitNetfilterQueue(void) +{ + otbrError error = OTBR_ERROR_ERRNO; + + VerifyOrExit((mNfqHandler = nfq_open()) != nullptr); + VerifyOrExit(nfq_unbind_pf(mNfqHandler, AF_INET6) >= 0); + VerifyOrExit(nfq_bind_pf(mNfqHandler, AF_INET6) >= 0); + + VerifyOrExit((mNfqQueueHandler = nfq_create_queue(mNfqHandler, 88, HandleNetfilterQueue, this)) != nullptr); + VerifyOrExit(nfq_set_mode(mNfqQueueHandler, NFQNL_COPY_PACKET, 0xffff) >= 0); + VerifyOrExit((mUnicastNsQueueSock = nfq_fd(mNfqHandler)) >= 0); + + error = OTBR_ERROR_NONE; + +exit: + otbrLogResult(error, "NdProxyManager: %s", __FUNCTION__); + + if (error != OTBR_ERROR_NONE) + { + FiniNetfilterQueue(); + } + + return error; +} + +void NdProxyManager::FiniNetfilterQueue(void) +{ + if (mUnicastNsQueueSock != -1) + { + close(mUnicastNsQueueSock); + mUnicastNsQueueSock = -1; + } + + if (mNfqQueueHandler != nullptr) + { + nfq_destroy_queue(mNfqQueueHandler); + mNfqQueueHandler = nullptr; + } + + if (mNfqHandler != nullptr) + { + nfq_close(mNfqHandler); + mNfqHandler = nullptr; + } +} + +int NdProxyManager::HandleNetfilterQueue(struct nfq_q_handle *aNfQueueHandler, + struct nfgenmsg * aNfMsg, + struct nfq_data * aNfData, + void * aContext) +{ + return static_cast(aContext)->HandleNetfilterQueue(aNfQueueHandler, aNfMsg, aNfData); +} + +int NdProxyManager::HandleNetfilterQueue(struct nfq_q_handle *aNfQueueHandler, + struct nfgenmsg * aNfMsg, + struct nfq_data * aNfData) +{ + OTBR_UNUSED_VARIABLE(aNfMsg); + + struct nfqnl_msg_packet_hdr *ph; + unsigned char * data; + uint32_t id = 0; + int ret = 0; + int len = 0; + int verdict = NF_ACCEPT; + + Ip6Address dst; + Ip6Address src; + struct icmp6_hdr *icmp6header = nullptr; + struct ip6_hdr * ip6header = nullptr; + otbrError error = OTBR_ERROR_NONE; + + if ((ph = nfq_get_msg_packet_hdr(aNfData)) != nullptr) + { + id = ntohl(ph->packet_id); + otbrLog(OTBR_LOG_DEBUG, "NdProxyManager: %s: id %d", __FUNCTION__, id); + } + + VerifyOrExit((len = nfq_get_payload(aNfData, &data)) > 0, error = OTBR_ERROR_PARSE); + + ip6header = reinterpret_cast(data); + src = *reinterpret_cast(&ip6header->ip6_src); + dst = *reinterpret_cast(&ip6header->ip6_dst); + + VerifyOrExit(ip6header->ip6_nxt == IPPROTO_ICMPV6); + + otbrLog(OTBR_LOG_DEBUG, "NdProxyManager: Handle Neighbor Solicitation: from %s to %s", src.ToString().c_str(), + dst.ToString().c_str()); + + icmp6header = reinterpret_cast(data + sizeof(struct ip6_hdr)); + VerifyOrExit(icmp6header->icmp6_type == ND_NEIGHBOR_SOLICIT); + + VerifyOrExit(mNdProxySet.find(dst) != mNdProxySet.end(), error = OTBR_ERROR_NOT_FOUND); + + { + struct nd_neighbor_solicit &ns = *reinterpret_cast(data + sizeof(struct ip6_hdr)); + Ip6Address & target = *reinterpret_cast(&ns.nd_ns_target); + + otbrLog(OTBR_LOG_DEBUG, "NdProxyManager: %s: target: %s, hoplimit %d", __FUNCTION__, target.ToString().c_str(), + ip6header->ip6_hlim); + VerifyOrExit(ip6header->ip6_hlim == 255, error = OTBR_ERROR_PARSE); + SendNeighborAdvertisement(target, src); + verdict = NF_DROP; + } + +exit: + ret = nfq_set_verdict(aNfQueueHandler, id, verdict, len, data); + + otbrLogResult(error, "NdProxyManager: %s (nfq_set_verdict id %d, ret %d verdict %d)", __FUNCTION__, id, ret, + verdict); + + return ret; +} + +void NdProxyManager::JoinSolicitedNodeMulticastGroup(const Ip6Address &aTarget) const +{ + ipv6_mreq mreq; + otbrError error = OTBR_ERROR_NONE; + Ip6Address solicitedMulticastAddress = aTarget.ToSolicitedNodeMulticastAddress(); + + mreq.ipv6mr_interface = mBackboneIfIndex; + solicitedMulticastAddress.CopyTo(mreq.ipv6mr_multiaddr); + + VerifyOrExit(setsockopt(mIcmp6RawSock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == 0, + error = OTBR_ERROR_ERRNO); +exit: + otbrLogResult(error, "NdProxyManager: JoinSolicitedNodeMulticastGroup of %s: %s", aTarget.ToString().c_str(), + solicitedMulticastAddress.ToString().c_str()); +} + +void NdProxyManager::LeaveSolicitedNodeMulticastGroup(const Ip6Address &aTarget) const +{ + ipv6_mreq mreq; + otbrError error = OTBR_ERROR_NONE; + Ip6Address solicitedMulticastAddress = aTarget.ToSolicitedNodeMulticastAddress(); + + mreq.ipv6mr_interface = mBackboneIfIndex; + solicitedMulticastAddress.CopyTo(mreq.ipv6mr_multiaddr); + + VerifyOrExit(setsockopt(mIcmp6RawSock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, sizeof(mreq)) == 0, + error = OTBR_ERROR_ERRNO); +exit: + otbrLogResult(error, "NdProxyManager: LeaveSolicitedNodeMulticastGroup of %s: %s", aTarget.ToString().c_str(), + solicitedMulticastAddress.ToString().c_str()); +} + +} // namespace BackboneRouter +} // namespace otbr diff --git a/src/backbone_router/nd_proxy.hpp b/src/backbone_router/nd_proxy.hpp new file mode 100644 index 00000000000..c6667f71427 --- /dev/null +++ b/src/backbone_router/nd_proxy.hpp @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2020, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes definition for ICMPv6 Neighbor Advertisement (ND) proxy management. + */ + +#ifndef ND_PROXY_HPP_ +#define ND_PROXY_HPP_ + +#ifdef __APPLE__ +#define __APPLE_USE_RFC_3542 +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include "agent/ncp_openthread.hpp" +#include "common/types.hpp" + +namespace otbr { +namespace BackboneRouter { + +/** + * @addtogroup border-router-bbr + * + * @brief + * This module includes definition for ND Proxy manager. + * + * @{ + */ + +/** + * This class implements ND Proxy manager. + * + */ +class NdProxyManager +{ +public: + /** + * This constructor initializes a NdProxyManager instance. + * + */ + explicit NdProxyManager(otbr::Ncp::ControllerOpenThread &aNcp) + : mNcp(aNcp) + , mIcmp6RawSock(-1) + , mUnicastNsQueueSock(-1) + , mNfqHandler(nullptr) + , mNfqQueueHandler(nullptr) + { + } + + /** + * This method initializes a ND Proxy manager instance. + * + */ + void Init(void); + + /** + * 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); + + /** + * This method updates the fd_set and timeout for mainloop. + * + * @param[inout] aReadFdSet A reference to fd_set for polling read. + * @param[inout] aWriteFdSet A reference to fd_set for polling read. + * @param[inout] aErrorFdSet A reference to fd_set for polling error. + * @param[inout] aMaxFd A reference to the current max fd in @p aReadFdSet and @p aWriteFdSet. + * @param[inout] aTimeout A reference to the timeout. + * + */ + void UpdateFdSet(fd_set & aReadFdSet, + fd_set & aWriteFdSet, + fd_set & aErrorFdSet, + int & aMaxFd, + timeval &aTimeout) const; + + /** + * This method performs border agent processing. + * + * @param[in] aReadFdSet A reference to read file descriptors. + * @param[in] aWriteFdSet A reference to write file descriptors. + * @param[in] aErrorFdSet A reference to error file descriptors. + * + */ + void Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet, const fd_set &aErrorFdSet); + + /** + * This method handles a Backbone Router ND Proxy event. + * + * @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); + + /** + * 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; } + +private: + enum + { + kMaxICMP6PacketSize = 1500, ///< Max size of an ICMP6 packet in bytes. + }; + + void SendNeighborAdvertisement(const Ip6Address &aTarget, const Ip6Address &aDst); + otbrError UpdateMacAddress(void); + otbrError InitIcmp6RawSocket(void); + void FiniIcmp6RawSocket(void); + otbrError InitNetfilterQueue(void); + void FiniNetfilterQueue(void); + void ProcessMulticastNeighborSolicition(void); + void ProcessUnicastNeighborSolicition(void); + void JoinSolicitedNodeMulticastGroup(const Ip6Address &aTarget) const; + void LeaveSolicitedNodeMulticastGroup(const Ip6Address &aTarget) const; + static int HandleNetfilterQueue(struct nfq_q_handle *aNfQueueHandler, + struct nfgenmsg * aNfMsg, + struct nfq_data * aNfData, + void * aContext); + int HandleNetfilterQueue(struct nfq_q_handle *aNfQueueHandler, struct nfgenmsg *aNfMsg, struct nfq_data *aNfData); + + otbr::Ncp::ControllerOpenThread &mNcp; + std::set mNdProxySet; + uint32_t mBackboneIfIndex; + int mIcmp6RawSock; + int mUnicastNsQueueSock; + struct nfq_handle * mNfqHandler; ///< A pointer to an NFQUEUE handler. + struct nfq_q_handle * mNfqQueueHandler; ///< A pointer to a newly created queue. + MacAddress mMacAddress; + Ip6Prefix mDomainPrefix; +}; + +/** + * @} + */ + +} // namespace BackboneRouter +} // namespace otbr + +#endif // ND_PROXY_HPP_ diff --git a/src/common/code_utils.hpp b/src/common/code_utils.hpp index c8a8eaf83f3..bd0140fc9cf 100644 --- a/src/common/code_utils.hpp +++ b/src/common/code_utils.hpp @@ -29,6 +29,8 @@ #ifndef OTBR_COMMON_CODE_UTILS_HPP_ #define OTBR_COMMON_CODE_UTILS_HPP_ +#include + /** * This aligns the pointer to @p aAlignType. * @@ -141,5 +143,9 @@ } while (false) #define OTBR_NOOP +#define OTBR_UNUSED_VARIABLE(variable) ((void)(variable)) + +#define OTBR_TOOL_PACKED_BEGIN OT_TOOL_PACKED_BEGIN +#define OTBR_TOOL_PACKED_END OT_TOOL_PACKED_END #endif // OTBR_COMMON_CODE_UTILS_HPP_ diff --git a/src/common/logging.cpp b/src/common/logging.cpp index 062028c9d22..c35ed674f59 100644 --- a/src/common/logging.cpp +++ b/src/common/logging.cpp @@ -132,7 +132,7 @@ void otbrDump(int aLevel, const char *aPrefix, const void *aMemory, size_t aSize const char *otbrErrorString(otbrError aError) { - const char *error = nullptr; + const char *error; switch (aError) { @@ -156,8 +156,28 @@ const char *otbrErrorString(otbrError aError) error = "OpenThread error"; break; + case OTBR_ERROR_SMCROUTE: + error = "SMCRoute error"; + break; + + case OTBR_ERROR_NOT_FOUND: + error = "Not found"; + break; + + case OTBR_ERROR_PARSE: + error = "Parse error"; + break; + + case OTBR_ERROR_NOT_IMPLEMENTED: + error = "Not implemented"; + break; + + case OTBR_ERROR_INVALID_ARGS: + error = "Invalid arguments"; + break; + default: - assert(false); + error = "Unknown"; } return error; diff --git a/src/common/types.cpp b/src/common/types.cpp index f96e3263e52..21a3ade2f89 100644 --- a/src/common/types.cpp +++ b/src/common/types.cpp @@ -27,6 +27,7 @@ */ #include +#include #include #include "common/code_utils.hpp" @@ -50,4 +51,76 @@ std::string Ip6Address::ToString() const return std::string(strbuf); } +Ip6Address Ip6Address::ToSolicitedNodeMulticastAddress(void) const +{ + Ip6Address ma(Ip6Address::GetSolicitedMulticastAddressPrefix()); + + ma.m8[13] = m8[13]; + ma.m8[14] = m8[14]; + ma.m8[15] = m8[15]; + + return ma; +} + +void Ip6Address::CopyTo(struct sockaddr_in6 &aSockAddr) const +{ + memset(&aSockAddr, 0, sizeof(aSockAddr)); + CopyTo(aSockAddr.sin6_addr); + aSockAddr.sin6_family = AF_INET6; +} + +void Ip6Address::CopyTo(struct in6_addr &aIn6Addr) const +{ + memcpy(aIn6Addr.s6_addr, m8, sizeof(aIn6Addr.s6_addr)); +} + +otbrError Ip6Address::FromString(const char *aStr, Ip6Address &aAddr) +{ + int ret; + + ret = inet_pton(AF_INET6, aStr, &aAddr.m8); + + return ret == 1 ? OTBR_ERROR_NONE : OTBR_ERROR_INVALID_ARGS; +} + +Ip6Address Ip6Address::FromString(const char *aStr) +{ + Ip6Address addr; + + SuccessOrDie(FromString(aStr, addr), "inet_pton failed"); + + return addr; +} + +void Ip6Prefix::Set(const otIp6Prefix &aPrefix) +{ + memcpy(reinterpret_cast(this), &aPrefix, sizeof(*this)); +} + +std::string Ip6Prefix::ToString() const +{ + std::stringbuf strBuilder; + char strbuf[INET6_ADDRSTRLEN]; + + VerifyOrDie(inet_ntop(AF_INET6, mPrefix.m8, strbuf, sizeof(strbuf)) != nullptr, + "Failed to convert Ip6 prefix to string"); + + strBuilder.sputn(strbuf, strlen(strbuf)); + strBuilder.sputc('/'); + + sprintf(strbuf, "%d", mLength); + strBuilder.sputn(strbuf, strlen(strbuf)); + + return strBuilder.str(); +} + +std::string MacAddress::ToString(void) const +{ + char strbuf[sizeof(m8) * 3]; + + snprintf(strbuf, sizeof(strbuf), "%02x:%02x:%02x:%02x:%02x:%02x", m8[0], m8[1], m8[2], m8[3], m8[4], m8[5]); + + return std::string(strbuf); +} + } // namespace otbr diff --git a/src/common/types.hpp b/src/common/types.hpp index 44819ab655b..fe4d0dd7e19 100644 --- a/src/common/types.hpp +++ b/src/common/types.hpp @@ -41,6 +41,8 @@ #include #include +#include "common/code_utils.hpp" + #ifndef IN6ADDR_ANY /** * Any IPv6 address literal. @@ -54,6 +56,12 @@ #define OTBR_MASTER_KEY_SIZE 16 #define OTBR_PSKC_SIZE 16 +/** + * Forward declaration for otIp6Prefix to avoid including + * + */ +struct otIp6Prefix; + /** * This enumeration represents error codes used throughout OpenThread Border Router. */ @@ -61,12 +69,16 @@ enum otbrError { OTBR_ERROR_NONE = 0, ///< No error. - OTBR_ERROR_ERRNO = -1, ///< Error defined by errno. - OTBR_ERROR_DBUS = -2, ///< DBus error. - OTBR_ERROR_MDNS = -3, ///< MDNS error. - OTBR_ERROR_OPENTHREAD = -4, ///< OpenThread error. - OTBR_ERROR_REST = -5, ///< Rest Server error. - OTBR_ERROR_SMCROUTE = -6, ///< SMCRoute error. + OTBR_ERROR_ERRNO = -1, ///< Error defined by errno. + OTBR_ERROR_DBUS = -2, ///< DBus error. + OTBR_ERROR_MDNS = -3, ///< MDNS error. + OTBR_ERROR_OPENTHREAD = -4, ///< OpenThread error. + OTBR_ERROR_REST = -5, ///< Rest Server error. + OTBR_ERROR_SMCROUTE = -6, ///< SMCRoute error. + OTBR_ERROR_NOT_FOUND = -7, ///< Not found. + OTBR_ERROR_PARSE = -8, ///< Parse error. + OTBR_ERROR_NOT_IMPLEMENTED = -9, ///< Not implemented error. + OTBR_ERROR_INVALID_ARGS = -10, ///< Invalid arguments error. }; namespace otbr { @@ -79,10 +91,14 @@ enum kSizeEui64 = 8, ///< Size of Eui64. }; +static constexpr char kSolicitedMulticastAddressPrefix[] = "ff02::01:ff00:0"; +static constexpr char kLinkLocalAllNodesMulticastAddress[] = "ff02::01"; + /** * This class implements the Ipv6 address functionality. * */ +OTBR_TOOL_PACKED_BEGIN class Ip6Address { public: @@ -129,6 +145,16 @@ class Ip6Address */ bool operator<(const Ip6Address &aOther) const { return memcmp(this, &aOther, sizeof(Ip6Address)) < 0; } + /** + * This method overloads `==` operator and compares if the Ip6 address is equal to the other address. + * + * @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]; } + /** * Retrieve the 16-bit Thread locator. * @@ -137,13 +163,83 @@ class Ip6Address */ uint16_t ToLocator(void) const { return static_cast(m8[14] << 8 | m8[15]); } + /** + * This method returns the solicited node multicast address. + * + * @returns The solicited node multicast address. + * + */ + Ip6Address ToSolicitedNodeMulticastAddress(void) const; + /** * This method returns the string representation for the Ip6 address. * * @returns The string representation of the Ip6 address. * */ - std::string ToString() const; + std::string ToString(void) const; + + /** + * 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; } + + /** + * 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) + { + static Ip6Address sLinkLocalAllNodesMulticastAddress = FromString(kLinkLocalAllNodesMulticastAddress); + + return sLinkLocalAllNodesMulticastAddress; + } + + /** + * 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) + { + static Ip6Address sSolicitedMulticastAddressPrefix = FromString(kSolicitedMulticastAddressPrefix); + + return sSolicitedMulticastAddressPrefix; + } + + /** + * This function converts Ip6 addresses from text to `Ip6Address`. + * + * @param[in] aStr The Ip6 address text. + * @param[out] aAddr A reference to `Ip6Address` to output the Ip6 address. + * + * @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); + + /** + * This method copies the Ip6 address to a `sockaddr_in6` structure. + * + * @param[out] aSockAddr The `sockaddr_in6` structure to copy the Ip6 adress to. + * + */ + void CopyTo(struct sockaddr_in6 &aSockAddr) const; + + /** + * This method copies the Ip6 address to a `in6_addr` structure. + * + * @param[out] aIn6Addr The `in6_addr` structure to copy the Ip6 adress to. + * + */ + void CopyTo(struct in6_addr &aIn6Addr) const; union { @@ -152,7 +248,92 @@ class Ip6Address uint32_t m32[4]; uint64_t m64[2]; }; -}; + +private: + static Ip6Address FromString(const char *aStr); + +} OTBR_TOOL_PACKED_END; + +/** + * This class represents a Ipv6 prefix. + * + */ +OTBR_TOOL_PACKED_BEGIN +class Ip6Prefix +{ +public: + /** + * Default constructor. + * + */ + Ip6Prefix(void) { Clear(); } + + /** + * 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); + + /** + * 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)); } + + /** + * 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; } + + Ip6Address mPrefix; ///< The IPv6 prefix. + uint8_t mLength; ///< The IPv6 prefix length (in bits). +} OTBR_TOOL_PACKED_END; + +/** + * This class represents an ethernet MAC address. + */ +OTBR_TOOL_PACKED_BEGIN +class MacAddress +{ +public: + /** + * Default constructor. + * + */ + MacAddress(void) + { + m16[0] = 0; + m16[1] = 0; + m16[2] = 0; + } + + /** + * This method returns the string representation for the MAC address. + * + * @returns The string representation of the MAC address. + * + */ + std::string ToString(void) const; + + union + { + uint8_t m8[6]; + uint16_t m16[3]; + }; +} OTBR_TOOL_PACKED_END; } // namespace otbr diff --git a/third_party/openthread/repo b/third_party/openthread/repo index fc159a706f0..0b0d6eef1d5 160000 --- a/third_party/openthread/repo +++ b/third_party/openthread/repo @@ -1 +1 @@ -Subproject commit fc159a706f0f1fbdffb526cad8e5847209dd6b14 +Subproject commit 0b0d6eef1d569c77a6cc08c3d4a39b76ea3e33c0 diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index b153a58635b..5a06fbe9ffc 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -41,6 +41,7 @@ add_executable(steering-data ) target_link_libraries(steering-data PRIVATE otbr-config + otbr-common otbr-utils mbedtls ) From d79d1335500a8b5a8b9230ff735cd1008e3dc73e Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Wed, 4 Nov 2020 00:11:37 +0800 Subject: [PATCH 015/175] [github-actions] build docker image for reference device (#591) This commit enhances the docker build test to use more options. --- .github/workflows/docker.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c60a6959c8e..f8014305509 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -45,9 +45,15 @@ jobs: strategy: matrix: include: - - build_args: "" + - image_tag: "latest" + build_args: "" push: yes - - build_args: "--build-arg OT_BACKBONE_CI=1" + - image_tag: "reference-device" + build_args: "--build-arg REFERENCE_DEVICE=1 --build-arg BACKBONE_ROUTER=1 --build-arg OTBR_OPTIONS='-DOT_DUA=ON -DOT_MLR=ON' --build-arg NAT64=0" + push: yes + - image_tag: "test" + build_args: "--build-arg REFERENCE_DEVICE=1 --build-arg BACKBONE_ROUTER=1 --build-arg OTBR_OPTIONS='-DOT_DUA=ON -DOT_MLR=ON' --build-arg OT_BACKBONE_CI=1" + push: no steps: - uses: actions/checkout@v2 with: @@ -64,18 +70,18 @@ jobs: run: | DOCKER_IMAGE=openthread/otbr DOCKER_PLATFORMS=linux/amd64,linux/arm/v7,linux/arm64 - VERSION=latest + VERSION=${{ matrix.image_tag }} TAGS="--tag ${DOCKER_IMAGE}:${VERSION}" echo ::set-output name=docker_image::${DOCKER_IMAGE} echo ::set-output name=version::${VERSION} - echo ::set-output name=buildx_args::--platform ${DOCKER_PLATFORMS} \ + echo ::set-output name=buildx_args::"--platform ${DOCKER_PLATFORMS} \ --build-arg VERSION=${VERSION} \ --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \ --build-arg VCS_REF=${GITHUB_SHA::8} \ ${{ matrix.build_args }} \ - ${TAGS} --file etc/docker/Dockerfile . + ${TAGS} --file etc/docker/Dockerfile ." - name: Docker Buildx (build) run: | From 997eae00eb79994deb859eb55de99628fecea0ec Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Wed, 4 Nov 2020 10:41:03 -0800 Subject: [PATCH 016/175] [pretty] downgrade to clang-format v9.0 (#603) --- CONTRIBUTING.md | 2 +- STYLE_GUIDE.md | 2 +- script/clang-format | 10 +++++----- tests/scripts/bootstrap.sh | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9e6b4f7a29b..7d0ea0a1c11 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -109,7 +109,7 @@ This will open up a text editor where you can specify which commits to squash. #### Coding Conventions and Style -OpenThread uses and enforces the [OpenThread Coding Conventions and Style](STYLE_GUIDE.md) on all code, except for code located in [third_party](third_party). Use `script/make-pretty` and `script/make-pretty check` to automatically reformat code and check for code-style compliance, respectively. OpenThread currently requires [clang-format v10.0.0](http://releases.llvm.org/download.html#10.0.0) for C/C++ and [yapf](https://github.com/google/yapf) for Python. +OpenThread uses and enforces the [OpenThread Coding Conventions and Style](STYLE_GUIDE.md) on all code, except for code located in [third_party](third_party). Use `script/make-pretty` and `script/make-pretty check` to automatically reformat code and check for code-style compliance, respectively. OpenThread currently requires [clang-format v9.0.0](https://releases.llvm.org/download.html#9.0.0) for C/C++ and [yapf](https://github.com/google/yapf) for Python. As part of the cleanup process, you should also run `script/make-pretty check` to ensure that your code passes the baseline code style checks. diff --git a/STYLE_GUIDE.md b/STYLE_GUIDE.md index 68f6edbb8c6..0c42f78efbf 100644 --- a/STYLE_GUIDE.md +++ b/STYLE_GUIDE.md @@ -111,7 +111,7 @@ - OpenThread uses `script/make-pretty` to reformat code and enforce code format and style. `script/make-pretty check` is included in OpenThread's continuous integration and must pass before a pull request is merged. -- `script/make-pretty` requires [clang-format v10.0.0](http://releases.llvm.org/download.html#10.0.0) for C/C++ and [yapf](https://github.com/google/yapf) for Python. +- `script/make-pretty` requires [clang-format v9.0.0](https://releases.llvm.org/download.html#9.0.0) for C/C++ and [yapf](https://github.com/google/yapf) for Python. ### File Names diff --git a/script/clang-format b/script/clang-format index addb7fa47fc..01b9535e0c2 100755 --- a/script/clang-format +++ b/script/clang-format @@ -27,7 +27,7 @@ # POSSIBILITY OF SUCH DAMAGE. # -CLANG_FORMAT_VERSION="clang-format version 10.0" +CLANG_FORMAT_VERSION="clang-format version 9.0" die() { @@ -39,18 +39,18 @@ die() # expand_aliases shell option is set using shopt. shopt -s expand_aliases -if command -v clang-format-10 >/dev/null; then - alias clang-format=clang-format-10 +if command -v clang-format-9 >/dev/null; then + alias clang-format=clang-format-9 elif command -v clang-format >/dev/null; then case "$(clang-format --version)" in "$CLANG_FORMAT_VERSION"*) ;; *) - die "$(clang-format --version); clang-format 10.0 required" + die "$(clang-format --version); clang-format 9.0 required" ;; esac else - die "clang-format 10.0 required" + die "clang-format 9.0 required" fi clang-format "$@" || die diff --git a/tests/scripts/bootstrap.sh b/tests/scripts/bootstrap.sh index 94423419efd..f8d5428b748 100755 --- a/tests/scripts/bootstrap.sh +++ b/tests/scripts/bootstrap.sh @@ -126,7 +126,7 @@ case "$(uname)" in fi if [ "$BUILD_TARGET" == pretty-check ]; then - sudo apt-get install -y clang-format-10 shellcheck + sudo apt-get install -y clang-format-9 shellcheck sudo snap install shfmt fi From ea8fe65f28cd9262ff1a83d015b6e4dcc38efbd4 Mon Sep 17 00:00:00 2001 From: IHIDCHAOS Date: Sun, 8 Nov 2020 11:37:20 +0800 Subject: [PATCH 017/175] [openwrt] fix startup script no effect (#605) The statement script needs to be on the first line, otherwise executing "/etc/init.d/otbr-agent start" has no effect. --- src/openwrt/otbr-agent.init.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openwrt/otbr-agent.init.in b/src/openwrt/otbr-agent.init.in index d42777b2ae2..1f326eed90b 100755 --- a/src/openwrt/otbr-agent.init.in +++ b/src/openwrt/otbr-agent.init.in @@ -1,3 +1,4 @@ +#!/bin/sh /etc/rc.common # # Copyright (c) 2020, The OpenThread Authors. # All rights reserved. @@ -26,7 +27,6 @@ # POSSIBILITY OF SUCH DAMAGE. # -#!/bin/sh /etc/rc.common START=90 From a37e299ffe7b2f444f06e1e904a27b184596ab02 Mon Sep 17 00:00:00 2001 From: Moandor Date: Mon, 9 Nov 2020 15:29:06 +0800 Subject: [PATCH 018/175] [code-utils] remove client dependency of toolchain.h (#606) This removes the dependency of openthread/platform/toolchain.h from common/code_utils.hpp. --- src/common/code_utils.hpp | 56 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/src/common/code_utils.hpp b/src/common/code_utils.hpp index bd0140fc9cf..2b2d0469f79 100644 --- a/src/common/code_utils.hpp +++ b/src/common/code_utils.hpp @@ -29,8 +29,6 @@ #ifndef OTBR_COMMON_CODE_UTILS_HPP_ #define OTBR_COMMON_CODE_UTILS_HPP_ -#include - /** * This aligns the pointer to @p aAlignType. * @@ -145,7 +143,57 @@ #define OTBR_NOOP #define OTBR_UNUSED_VARIABLE(variable) ((void)(variable)) -#define OTBR_TOOL_PACKED_BEGIN OT_TOOL_PACKED_BEGIN -#define OTBR_TOOL_PACKED_END OT_TOOL_PACKED_END +/** + * @def OTBR_TOOL_PACKED_BEGIN + * + * Compiler-specific indication that a class or struct must be byte packed. + * + */ + +/** + * @def OTBR_TOOL_PACKED_END + * + * Compiler-specific indication at the end of a byte packed class or struct. + * + */ + +// =========== TOOLCHAIN SELECTION : START =========== + +#if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM) || defined(__TI_ARM__) + +// https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html +// http://www.keil.com/support/man/docs/armcc/armcc_chr1359124973480.htm + +#define OTBR_TOOL_PACKED_BEGIN +#define OTBR_TOOL_PACKED_END __attribute__((packed)) + +#elif defined(__ICCARM__) || defined(__ICC8051__) + +// http://supp.iar.com/FilesPublic/UPDINFO/004916/arm/doc/EWARM_DevelopmentGuide.ENU.pdf + +#include "intrinsics.h" + +#define OTBR_TOOL_PACKED_BEGIN __packed +#define OTBR_TOOL_PACKED_END + +#elif defined(__SDCC) + +// Structures are packed by default in sdcc, as it primarily targets 8-bit MCUs. + +#define OTBR_TOOL_PACKED_BEGIN +#define OTBR_TOOL_PACKED_END + +#else + +#error "Error: No valid Toolchain specified" + +// Symbols for Doxygen + +#define OTBR_TOOL_PACKED_BEGIN +#define OTBR_TOOL_PACKED_END + +#endif + +// =========== TOOLCHAIN SELECTION : END =========== #endif // OTBR_COMMON_CODE_UTILS_HPP_ From 39ccbb438c17ae964081313caa64ed3e2b89e114 Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Tue, 10 Nov 2020 23:17:28 +0800 Subject: [PATCH 019/175] [cli] add cli support for region code (#607) This allows users to get/set the region code over OpenThread cli. --- src/agent/ncp_openthread.cpp | 36 ++++++++++++++++++++++++++++++++++++ src/agent/ncp_openthread.hpp | 6 ++++++ tests/dbus/test-client | 3 +++ 3 files changed, 45 insertions(+) diff --git a/src/agent/ncp_openthread.cpp b/src/agent/ncp_openthread.cpp index ee2519c6d3f..e11ca5526fc 100644 --- a/src/agent/ncp_openthread.cpp +++ b/src/agent/ncp_openthread.cpp @@ -60,6 +60,11 @@ using std::chrono::steady_clock; namespace otbr { namespace Ncp { +const otCliCommand ControllerOpenThread::sRegionCommand = { + "region", + &ControllerOpenThread::HandleRegionCommand, +}; + ControllerOpenThread::ControllerOpenThread(const char *aInterfaceName, const char *aRadioUrl, const char *aBackboneInterfaceName) @@ -132,6 +137,7 @@ otbrError ControllerOpenThread::Init(void) #endif mThreadHelper = std::unique_ptr(new otbr::agent::ThreadHelper(mInstance, this)); + otCliSetUserCommands(&sRegionCommand, 1, this); exit: return error; @@ -322,6 +328,36 @@ void ControllerOpenThread::RegisterResetHandler(std::function aHandl mResetHandlers.emplace_back(std::move(aHandler)); } +void ControllerOpenThread::HandleRegionCommand(void *aContext, uint8_t aArgLength, char **aArgs) +{ + ControllerOpenThread *controller = static_cast(aContext); + controller->HandleRegionCommand(aArgLength, aArgs); +} + +void ControllerOpenThread::HandleRegionCommand(uint8_t aArgLength, char **aArgs) +{ + if (aArgLength == 0) + { + otCliOutputFormat("%s\nDone\n", mRegionCode.c_str()); + } + else if (aArgLength == 1) + { + if (strnlen(aArgs[0], 3) == 2) + { + mRegionCode = aArgs[0]; + otCliOutputFormat("Done\n"); + } + else + { + otCliOutputFormat("Error: InvalidArgs\n"); + } + } + else + { + otCliOutputFormat("Error: InvalidArgs\n"); + } +} + #if OTBR_ENABLE_BACKBONE_ROUTER void ControllerOpenThread::HandleBackboneRouterDomainPrefixEvent(void * aContext, otBackboneRouterDomainPrefixEvent aEvent, diff --git a/src/agent/ncp_openthread.hpp b/src/agent/ncp_openthread.hpp index be52e55082c..68b7fb2ce32 100644 --- a/src/agent/ncp_openthread.hpp +++ b/src/agent/ncp_openthread.hpp @@ -38,6 +38,7 @@ #include #include +#include #include #include @@ -190,6 +191,9 @@ class ControllerOpenThread : public Controller void HandleBackboneRouterMulticastListenerEvent(otBackboneRouterMulticastListenerEvent aEvent, const otIp6Address * aAddress); + static void HandleRegionCommand(void *aContext, uint8_t aArgLength, char **aArgs); + void HandleRegionCommand(uint8_t aArgLength, char **aArgs); + otInstance *mInstance; otPlatformConfig mConfig; @@ -198,6 +202,8 @@ class ControllerOpenThread : public Controller bool mTriedAttach; std::vector> mResetHandlers; std::string mRegionCode; + + static const otCliCommand sRegionCommand; }; } // namespace Ncp diff --git a/tests/dbus/test-client b/tests/dbus/test-client index 47c6d4593ec..afb6a3561d0 100755 --- a/tests/dbus/test-client +++ b/tests/dbus/test-client @@ -57,6 +57,9 @@ main() sudo "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent --reg WW -d7 -I wpan0 "spinel+hdlc+forkpty://$(command -v ot-rcp)?forkpty-arg=1" & trap on_exit EXIT sleep 5 + sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl region US | grep Done + sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl region | grep US + sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl region WW | grep Done sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl factoryreset sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \ --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \ From 6d4960622142c66f74712d114e4e61817cc390b2 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Fri, 20 Nov 2020 00:07:28 +0800 Subject: [PATCH 020/175] [docker] build arm/v7 image based on ubuntu:bionic (#614) --- .github/workflows/docker.yml | 24 +++++++++++++++++++++++- etc/docker/Dockerfile | 3 ++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index f8014305509..4227deb76e8 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -47,12 +47,33 @@ jobs: include: - image_tag: "latest" build_args: "" + base_image: "ubuntu:bionic" + platforms: "linux/arm/v7" + push: yes + - image_tag: "latest" + build_args: "" + base_image: "ubuntu:focal" + platforms: "linux/amd64,linux/arm64" push: yes - image_tag: "reference-device" build_args: "--build-arg REFERENCE_DEVICE=1 --build-arg BACKBONE_ROUTER=1 --build-arg OTBR_OPTIONS='-DOT_DUA=ON -DOT_MLR=ON' --build-arg NAT64=0" + base_image: "ubuntu:bionic" + platforms: "linux/arm/v7" push: yes + - image_tag: "reference-device" + build_args: "--build-arg REFERENCE_DEVICE=1 --build-arg BACKBONE_ROUTER=1 --build-arg OTBR_OPTIONS='-DOT_DUA=ON -DOT_MLR=ON' --build-arg NAT64=0" + base_image: "ubuntu:focal" + platforms: "linux/amd64,linux/arm64" + push: yes + - image_tag: "test" + build_args: "--build-arg REFERENCE_DEVICE=1 --build-arg BACKBONE_ROUTER=1 --build-arg OTBR_OPTIONS='-DOT_DUA=ON -DOT_MLR=ON' --build-arg OT_BACKBONE_CI=1" + base_image: "ubuntu:bionic" + platforms: "linux/arm/v7" + push: no - image_tag: "test" build_args: "--build-arg REFERENCE_DEVICE=1 --build-arg BACKBONE_ROUTER=1 --build-arg OTBR_OPTIONS='-DOT_DUA=ON -DOT_MLR=ON' --build-arg OT_BACKBONE_CI=1" + base_image: "ubuntu:focal" + platforms: "linux/amd64,linux/arm64" push: no steps: - uses: actions/checkout@v2 @@ -69,7 +90,7 @@ jobs: id: prepare run: | DOCKER_IMAGE=openthread/otbr - DOCKER_PLATFORMS=linux/amd64,linux/arm/v7,linux/arm64 + DOCKER_PLATFORMS=${{ matrix.platforms }} VERSION=${{ matrix.image_tag }} TAGS="--tag ${DOCKER_IMAGE}:${VERSION}" @@ -77,6 +98,7 @@ jobs: echo ::set-output name=docker_image::${DOCKER_IMAGE} echo ::set-output name=version::${VERSION} echo ::set-output name=buildx_args::"--platform ${DOCKER_PLATFORMS} \ + --build-arg BASE_IMAGE=${{ matrix.base_image }} \ --build-arg VERSION=${VERSION} \ --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \ --build-arg VCS_REF=${GITHUB_SHA::8} \ diff --git a/etc/docker/Dockerfile b/etc/docker/Dockerfile index e61b71509eb..ee230bd5d3e 100644 --- a/etc/docker/Dockerfile +++ b/etc/docker/Dockerfile @@ -25,7 +25,8 @@ # POSSIBILITY OF SUCH DAMAGE. # -FROM ubuntu:focal +ARG BASE_IMAGE=ubuntu:focal +FROM ${BASE_IMAGE} ARG BACKBONE_ROUTER ARG OT_BACKBONE_CI From e7a40cfb0d0b01017e987efb08559224410fef81 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Fri, 20 Nov 2020 14:40:50 +0800 Subject: [PATCH 021/175] [docker] build docker images using both bionic and focal (#617) This commit builds Docker images using different parent ubuntu images: - otbr:latest --- ubuntu:bionic - otbr:reference-device --- ubuntu:bionic - otbr:test --- ubuntu:bionic - otbr:focal --- ubuntu:focal --- .github/workflows/docker.yml | 22 ++++++---------------- etc/docker/Dockerfile | 2 +- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 4227deb76e8..ac7434b219e 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -46,34 +46,24 @@ jobs: matrix: include: - image_tag: "latest" - build_args: "" base_image: "ubuntu:bionic" - platforms: "linux/arm/v7" - push: yes - - image_tag: "latest" build_args: "" + platforms: "linux/amd64,linux/arm/v7,linux/arm64" + push: yes + - image_tag: "focal" base_image: "ubuntu:focal" + build_args: "" platforms: "linux/amd64,linux/arm64" push: yes - image_tag: "reference-device" - build_args: "--build-arg REFERENCE_DEVICE=1 --build-arg BACKBONE_ROUTER=1 --build-arg OTBR_OPTIONS='-DOT_DUA=ON -DOT_MLR=ON' --build-arg NAT64=0" base_image: "ubuntu:bionic" - platforms: "linux/arm/v7" - push: yes - - image_tag: "reference-device" build_args: "--build-arg REFERENCE_DEVICE=1 --build-arg BACKBONE_ROUTER=1 --build-arg OTBR_OPTIONS='-DOT_DUA=ON -DOT_MLR=ON' --build-arg NAT64=0" - base_image: "ubuntu:focal" - platforms: "linux/amd64,linux/arm64" + platforms: "linux/amd64,linux/arm/v7,linux/arm64" push: yes - image_tag: "test" - build_args: "--build-arg REFERENCE_DEVICE=1 --build-arg BACKBONE_ROUTER=1 --build-arg OTBR_OPTIONS='-DOT_DUA=ON -DOT_MLR=ON' --build-arg OT_BACKBONE_CI=1" base_image: "ubuntu:bionic" - platforms: "linux/arm/v7" - push: no - - image_tag: "test" build_args: "--build-arg REFERENCE_DEVICE=1 --build-arg BACKBONE_ROUTER=1 --build-arg OTBR_OPTIONS='-DOT_DUA=ON -DOT_MLR=ON' --build-arg OT_BACKBONE_CI=1" - base_image: "ubuntu:focal" - platforms: "linux/amd64,linux/arm64" + platforms: "linux/amd64,linux/arm/v7,linux/arm64" push: no steps: - uses: actions/checkout@v2 diff --git a/etc/docker/Dockerfile b/etc/docker/Dockerfile index ee230bd5d3e..0c5d989afa8 100644 --- a/etc/docker/Dockerfile +++ b/etc/docker/Dockerfile @@ -25,7 +25,7 @@ # POSSIBILITY OF SUCH DAMAGE. # -ARG BASE_IMAGE=ubuntu:focal +ARG BASE_IMAGE=ubuntu:bionic FROM ${BASE_IMAGE} ARG BACKBONE_ROUTER From 8bbfe8ae9c51eada304aa00b83fd2e84715eabdd Mon Sep 17 00:00:00 2001 From: Yakun Xu Date: Sun, 22 Nov 2020 10:15:29 +0800 Subject: [PATCH 022/175] [test] fix build check on macOS (#621) --- .github/workflows/macOS.yml | 26 ++++++++++++++++++++++++++ .travis.yml | 3 --- .travis/script.sh | 7 ------- 3 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/macOS.yml diff --git a/.github/workflows/macOS.yml b/.github/workflows/macOS.yml new file mode 100644 index 00000000000..6e6d7f55513 --- /dev/null +++ b/.github/workflows/macOS.yml @@ -0,0 +1,26 @@ +name: macOS + +on: [push, pull_request] + +jobs: + + cancel-previous-runs: + runs-on: ubuntu-latest + steps: + - uses: rokroskar/workflow-run-cleanup-action@master + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + if: "github.ref != 'refs/heads/master'" + + build-check: + runs-on: macos-10.15 + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Bootstrap + run: | + brew reinstall boost cmake cpputest dbus jsoncpp ninja + - name: Build + run: | + OTBR_OPTIONS='-DOTBR_MDNS=OFF' ./script/test build diff --git a/.travis.yml b/.travis.yml index 85f96c0c582..e2f3bca8d2a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,3 @@ jobs: - env: BUILD_TARGET="docker-check" OT_POSIX_CONFIG_RCP_BUS=SPI OTBR_COVERAGE=1 VERBOSE=1 - env: BUILD_TARGET="openwrt-check" VERBOSE=1 - env: BUILD_TARGET="meshcop" OTBR_COVERAGE=1 VERBOSE=1 - - env: BUILD_TARGET="macOS" - os: osx - language: "generic" diff --git a/.travis/script.sh b/.travis/script.sh index 5432e6a884a..05e6be4e470 100755 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -53,13 +53,6 @@ case $BUILD_TARGET in otbr-dbus-check) .travis/check-otbr-dbus ;; - - macOS) - # On Travis, brew install fails when a package is already installed, so use reinstall here instead of ./script/bootstrap - brew unlink python@2 || true - brew reinstall boost cmake cpputest dbus jsoncpp ninja - OTBR_OPTIONS='-DOTBR_MDNS=OFF' ./script/test build - ;; *) false ;; From 16182d6e0ef03d149999476421e22eeb77fe2a00 Mon Sep 17 00:00:00 2001 From: Yakun Xu Date: Sun, 22 Nov 2020 12:16:06 +0800 Subject: [PATCH 023/175] [openwrt] fix rloc16 in little endian system (#618) --- src/openwrt/ubus/otubus.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/openwrt/ubus/otubus.cpp b/src/openwrt/ubus/otubus.cpp index d9f62977b67..78b954ce193 100644 --- a/src/openwrt/ubus/otubus.cpp +++ b/src/openwrt/ubus/otubus.cpp @@ -1190,16 +1190,13 @@ int UbusServer::UbusGetInformation(struct ubus_context * aContext, uint8_t tlvTypes[OT_NETWORK_DIAGNOSTIC_TYPELIST_MAX_ENTRIES]; uint8_t count = 0; char multicastAddr[10] = "ff03::2"; - long value; blob_buf_init(&mNetworkdataBuf, 0); SuccessOrExit(error = otIp6AddressFromString(multicastAddr, &address)); - value = 5; - tlvTypes[count++] = static_cast(value); - value = 16; - tlvTypes[count++] = static_cast(value); + tlvTypes[count++] = static_cast(OT_NETWORK_DIAGNOSTIC_TLV_ROUTE); + tlvTypes[count++] = static_cast(OT_NETWORK_DIAGNOSTIC_TLV_CHILD_TABLE); sBufNum = 0; otThreadSendDiagnosticGet(mController->GetInstance(), &address, tlvTypes, count); @@ -1343,7 +1340,7 @@ void UbusServer::HandleDiagnosticGetResponse(otError aError, otMessage *aMessage if (IsRoutingLocator(&aMessageInfo->mSockAddr)) { - sockRloc16 = aMessageInfo->mPeerAddr.mFields.m16[7]; + sockRloc16 = ntohs(aMessageInfo->mPeerAddr.mFields.m16[7]); sprintf(xrloc, "0x%04x", sockRloc16); blobmsg_add_string(&mNetworkdataBuf, "rloc", xrloc); } From 8974f9b3228a19523685bfd36f0b2eaa846af84e Mon Sep 17 00:00:00 2001 From: Yakun Xu Date: Tue, 24 Nov 2020 15:01:50 +0800 Subject: [PATCH 024/175] [rest] fix show ip address on little endian system (#619) --- src/rest/json.cpp | 16 +++------------- tests/rest/test_rest.py | 17 ++++++++--------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/rest/json.cpp b/src/rest/json.cpp index 2e4450a1e8e..f2c7c837ef7 100644 --- a/src/rest/json.cpp +++ b/src/rest/json.cpp @@ -29,6 +29,7 @@ #include "rest/json.hpp" #include "common/code_utils.hpp" +#include "common/types.hpp" extern "C" { #include @@ -108,20 +109,9 @@ static cJSON *Mode2Json(const otLinkModeConfig &aMode) static cJSON *IpAddr2Json(const otIp6Address &aAddress) { - std::string serilizedIpAddr; - char ipAddrField[5]; + Ip6Address addr(aAddress.mFields.m8); - for (size_t i = 0; i < 8; ++i) - { - sprintf(ipAddrField, "%x", aAddress.mFields.m16[i]); - if (i >= 1) - { - serilizedIpAddr += ":"; - } - serilizedIpAddr += std::string(ipAddrField); - } - - return cJSON_CreateString(serilizedIpAddr.c_str()); + return cJSON_CreateString(addr.ToString().c_str()); } static cJSON *ChildTableEntry2Json(const otNetworkDiagChildEntry &aChildEntry) diff --git a/tests/rest/test_rest.py b/tests/rest/test_rest.py index dde32dd9752..6a846489f38 100644 --- a/tests/rest/test_rest.py +++ b/tests/rest/test_rest.py @@ -29,6 +29,7 @@ import urllib.request import urllib.error +import ipaddress import json import re from threading import Thread @@ -36,6 +37,9 @@ rest_api_addr = "http://0.0.0.0:8081" +def assert_is_ipv6_address(string): + assert (type(ipaddress.ip_address(string)) is ipaddress.IPv6Address) + def get_data_from_url(url, result, index): response = urllib.request.urlopen(urllib.request.Request(url)) body = response.read() @@ -148,9 +152,7 @@ def diagnostics_check(data): for ip6_address in ip6_address_list: assert (type(ip6_address) == str) - assert (re.match( - r'^[a-f0-9]+:[a-f0-9]+:[a-f0-9]+:[a-f0-9]+:[a-f0-9]+:[a-f0-9]+:[a-f0-9]+:[a-f0-9]+$', - ip6_address) is not None) + assert_is_ipv6_address(ip6_address) mac_counters = diag["MACCounters"] assert (type(mac_counters) == dict) @@ -200,9 +202,8 @@ def node_check(data): assert (key in data) assert (type(data[key]) == value) - assert (re.match( - r'^[a-f0-9]+:[a-f0-9]+:[a-f0-9]+:[a-f0-9]+:[a-f0-9]+:[a-f0-9]+:[a-f0-9]+:[a-f0-9]+$', - data["RlocAddress"]) is not None) + assert_is_ipv6_address(data["RlocAddress"]) + assert (re.match(r'^[A-F0-9]{16}$', data["ExtAddress"]) is not None) assert (re.match(r'[A-F0-9]{16}', data["ExtPanId"]) is not None) @@ -224,9 +225,7 @@ def node_rloc_check(data): assert (type(data) == str) - assert (re.match( - r'^[a-f0-9]+:[a-f0-9]+:[a-f0-9]+:[a-f0-9]+:[a-f0-9]+:[a-f0-9]+:[a-f0-9]+:[a-f0-9]+$', - data) is not None) + assert_is_ipv6_address(data) return True From 2e13721203eb541aa43ed9980b7e9d8282dd5629 Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Tue, 24 Nov 2020 15:07:20 +0800 Subject: [PATCH 025/175] [agent] fix the process of generating extPanId (#622) --- src/agent/thread_helper.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/agent/thread_helper.cpp b/src/agent/thread_helper.cpp index 80d6b7e25db..a87414af4a2 100644 --- a/src/agent/thread_helper.cpp +++ b/src/agent/thread_helper.cpp @@ -210,7 +210,9 @@ void ThreadHelper::Attach(const std::string & aNetworkName, } else { - while (aExtPanId != UINT64_MAX) + *reinterpret_cast(&extPanId) = UINT64_MAX; + + while (*reinterpret_cast(&extPanId) == UINT64_MAX) { RandomFill(extPanId.m8, sizeof(extPanId.m8)); } From 87eaeb8d07769e39b40a3b8de44481a4d8818ab9 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Wed, 25 Nov 2020 00:58:00 +0800 Subject: [PATCH 026/175] [nit] fix BACKBONE_ROUTER readonly warning (#623) --- script/_otbr | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/script/_otbr b/script/_otbr index 772fd752539..66729465e96 100644 --- a/script/_otbr +++ b/script/_otbr @@ -31,7 +31,6 @@ readonly OTBR_TOP_BUILDDIR="${BUILD_DIR}/otbr" readonly OTBR_TOP_SRCDIR="$PWD" readonly OTBR_OPTIONS="${OTBR_OPTIONS:-}" readonly REFERENCE_DEVICE="${REFERENCE_DEVICE:-0}" -readonly BACKBONE_ROUTER="${BACKBONE_ROUTER:-0}" otbr_uninstall() { @@ -76,7 +75,7 @@ otbr_install() "-DOT_REFERENCE_DEVICE=ON" ) fi - if [[ ${BACKBONE_ROUTER} == "1" ]]; then + if with BACKBONE_ROUTER; then otbr_options+=( "-DOTBR_BACKBONE_ROUTER=ON" ) From 9ef7480b90e135137a38eb9ca2f0d3ad8ff24e8f Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Wed, 25 Nov 2020 00:59:53 +0800 Subject: [PATCH 027/175] [backbone-router] remove MLR multicast routing using smcroute (#604) This commit removes the MLR multicast routing feature using smcroute. --- etc/docker/Dockerfile | 2 +- script/_smcroute | 59 ------- script/bootstrap | 4 +- script/setup | 3 - script/update | 3 - src/agent/ncp.hpp | 19 ++- src/agent/ncp_openthread.cpp | 15 -- src/backbone_router/CMakeLists.txt | 1 - src/backbone_router/backbone_agent.cpp | 36 ----- src/backbone_router/backbone_agent.hpp | 5 - src/backbone_router/constants.hpp | 6 - src/backbone_router/nd_proxy.cpp | 2 + src/backbone_router/smcroute_manager.cpp | 192 ----------------------- src/backbone_router/smcroute_manager.hpp | 127 --------------- src/common/logging.cpp | 4 - third_party/openthread/repo | 2 +- 16 files changed, 15 insertions(+), 465 deletions(-) delete mode 100644 script/_smcroute delete mode 100644 src/backbone_router/smcroute_manager.cpp delete mode 100644 src/backbone_router/smcroute_manager.hpp diff --git a/etc/docker/Dockerfile b/etc/docker/Dockerfile index 0c5d989afa8..5181d685dc8 100644 --- a/etc/docker/Dockerfile +++ b/etc/docker/Dockerfile @@ -62,7 +62,7 @@ ENV OTBR_DOCKER_DEPS git ca-certificates 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 \ libavahi-client-dev libboost-dev libboost-filesystem-dev libboost-system-dev libjsoncpp-dev \ - autoconf automake pkg-config libnetfilter-queue-dev + libnetfilter-queue-dev # Required for OpenThread Backbone CI ENV OTBR_OT_BACKBONE_CI_DEPS curl lcov diff --git a/script/_smcroute b/script/_smcroute deleted file mode 100644 index 714c764bfde..00000000000 --- a/script/_smcroute +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -# -# 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. -# -# Description: -# This script manipulates smcroute configuration. -# - -smcroute_uninstall() -{ - with BACKBONE_ROUTER || return 0 - - sudo smcroutectl kill || true - - test -d "$BUILD_DIR"/smcroute || return 0 - - (cd "$BUILD_DIR"/smcroute \ - && (test ! -f config.status || sudo make uninstall)) -} - -smcroute_install() -{ - with BACKBONE_ROUTER || return 0 - - test -d "$BUILD_DIR"/smcroute || (cd "$BUILD_DIR" \ - && git clone -b ip6_mf --depth 1 https://github.com/librasungirl/smcroute.git) || die 'Failed to download source code of SMCRoute!' - - ( - cd "$BUILD_DIR"/smcroute || return 1 - test -f configure || ./autogen.sh - test -f config.status || ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var - make - sudo make install - ) -} diff --git a/script/bootstrap b/script/bootstrap index e6a6c63041a..e18f0f90b7a 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -43,7 +43,7 @@ install_packages_apt() libreadline-dev \ libncurses-dev - sudo apt-get install --no-install-recommends -y build-essential ninja-build cmake automake autoconf pkg-config + 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 @@ -106,7 +106,7 @@ install_packages_rpm() else PM=yum fi - sudo $PM install -y gcc gcc-c++ automake autoconf pkg-config + sudo $PM install -y gcc gcc-c++ with RELEASE || sudo $PM install -y cmake ninja-build sudo $PM install -y dbus-devel sudo $PM install -y avahi avahi-devel diff --git a/script/setup b/script/setup index 2a77dcbada1..480db78b6e9 100755 --- a/script/setup +++ b/script/setup @@ -38,7 +38,6 @@ . script/_dns64 . script/_dhcpv6_pd . script/_network_manager -. script/_smcroute . script/_swapfile . script/_sudo_extend . script/_disable_services @@ -54,11 +53,9 @@ main() dhcpv6_pd_uninstall nat64_uninstall dns64_uninstall - smcroute_uninstall ipforward_uninstall ipforward_install - smcroute_install nat64_install dns64_install network_manager_install diff --git a/script/update b/script/update index 698e409a915..a920f54929d 100755 --- a/script/update +++ b/script/update @@ -38,7 +38,6 @@ . script/_nat64 . script/_dns64 . script/_dhcpv6_pd -. script/_smcroute main() { @@ -49,11 +48,9 @@ main() dhcpv6_pd_uninstall nat64_uninstall dns64_uninstall - smcroute_uninstall ipforward_uninstall ipforward_install - smcroute_install nat64_install dns64_install dhcpv6_pd_install diff --git a/src/agent/ncp.hpp b/src/agent/ncp.hpp index 5973cdded13..13a41470e57 100644 --- a/src/agent/ncp.hpp +++ b/src/agent/ncp.hpp @@ -62,16 +62,15 @@ namespace Ncp { */ enum { - kEventExtPanId, ///< Extended PAN ID arrived. - kEventNetworkName, ///< Network name arrived. - kEventPSKc, ///< PSKc arrived. - kEventThreadState, ///< Thread State. - kEventThreadVersion, ///< Thread Version. - kEventUdpForwardStream, ///< UDP forward stream arrived. - kEventBackboneRouterState, ///< Backbone Router State. - kEventBackboneRouterDomainPrefixEvent, ///< Backbone Router Domain Prefix event. - kEventBackboneRouterNdProxyEvent, ///< Backbone Router ND Proxy event arrived. - kEventBackboneRouterMulticastListenerEvent, ///< Backbone Router Multicast Listener event arrived. + kEventExtPanId, ///< Extended PAN ID arrived. + kEventNetworkName, ///< Network name arrived. + kEventPSKc, ///< PSKc arrived. + kEventThreadState, ///< Thread State. + kEventThreadVersion, ///< Thread Version. + kEventUdpForwardStream, ///< UDP forward stream arrived. + kEventBackboneRouterState, ///< Backbone Router State. + kEventBackboneRouterDomainPrefixEvent, ///< Backbone Router Domain Prefix event. + kEventBackboneRouterNdProxyEvent, ///< Backbone Router ND Proxy event arrived. }; /** diff --git a/src/agent/ncp_openthread.cpp b/src/agent/ncp_openthread.cpp index e11ca5526fc..07130957bd3 100644 --- a/src/agent/ncp_openthread.cpp +++ b/src/agent/ncp_openthread.cpp @@ -132,8 +132,6 @@ otbrError ControllerOpenThread::Init(void) otBackboneRouterSetDomainPrefixCallback(mInstance, &ControllerOpenThread::HandleBackboneRouterDomainPrefixEvent, this); otBackboneRouterSetNdProxyCallback(mInstance, &ControllerOpenThread::HandleBackboneRouterNdProxyEvent, this); - otBackboneRouterSetMulticastListenerCallback( - mInstance, &ControllerOpenThread::HandleBackboneRouterMulticastListenerEvent, this); #endif mThreadHelper = std::unique_ptr(new otbr::agent::ThreadHelper(mInstance, this)); @@ -384,19 +382,6 @@ void ControllerOpenThread::HandleBackboneRouterNdProxyEvent(otBackboneRouterNdPr { EventEmitter::Emit(kEventBackboneRouterNdProxyEvent, aEvent, aAddress); } - -void ControllerOpenThread::HandleBackboneRouterMulticastListenerEvent(void * aContext, - otBackboneRouterMulticastListenerEvent aEvent, - const otIp6Address * aAddress) -{ - static_cast(aContext)->HandleBackboneRouterMulticastListenerEvent(aEvent, aAddress); -} - -void ControllerOpenThread::HandleBackboneRouterMulticastListenerEvent(otBackboneRouterMulticastListenerEvent aEvent, - const otIp6Address * aAddress) -{ - EventEmitter::Emit(kEventBackboneRouterMulticastListenerEvent, aEvent, aAddress); -} #endif Controller *Controller::Create(const char *aInterfaceName, const char *aRadioUrl, const char *aBackboneInterfaceName) diff --git a/src/backbone_router/CMakeLists.txt b/src/backbone_router/CMakeLists.txt index 84d1b9a62f6..48d0c04e24e 100644 --- a/src/backbone_router/CMakeLists.txt +++ b/src/backbone_router/CMakeLists.txt @@ -29,7 +29,6 @@ add_library(otbr-backbone-router backbone_agent.cpp nd_proxy.cpp - smcroute_manager.cpp ) target_link_libraries(otbr-backbone-router PRIVATE diff --git a/src/backbone_router/backbone_agent.cpp b/src/backbone_router/backbone_agent.cpp index 2a61df5cd7e..889783fe257 100644 --- a/src/backbone_router/backbone_agent.cpp +++ b/src/backbone_router/backbone_agent.cpp @@ -55,10 +55,8 @@ void BackboneAgent::Init(void) mNcp.On(Ncp::kEventBackboneRouterState, HandleBackboneRouterState, this); mNcp.On(Ncp::kEventBackboneRouterDomainPrefixEvent, HandleBackboneRouterDomainPrefixEvent, this); mNcp.On(Ncp::kEventBackboneRouterNdProxyEvent, HandleBackboneRouterNdProxyEvent, this); - mNcp.On(Ncp::kEventBackboneRouterMulticastListenerEvent, HandleBackboneRouterMulticastListenerEvent, this); mNdProxyManager.Init(); - mSMCRouteManager.Init(); HandleBackboneRouterState(); } @@ -97,37 +95,6 @@ void BackboneAgent::HandleBackboneRouterState(void) return; } -void BackboneAgent::HandleBackboneRouterMulticastListenerEvent(void *aContext, int aEvent, va_list aArguments) -{ - OT_UNUSED_VARIABLE(aEvent); - - otBackboneRouterMulticastListenerEvent event; - const otIp6Address * address; - - assert(aEvent == Ncp::kEventBackboneRouterMulticastListenerEvent); - - event = static_cast(va_arg(aArguments, int)); - address = va_arg(aArguments, const otIp6Address *); - static_cast(aContext)->HandleBackboneRouterMulticastListenerEvent(event, *address); -} - -void BackboneAgent::HandleBackboneRouterMulticastListenerEvent(otBackboneRouterMulticastListenerEvent aEvent, - const otIp6Address & aAddress) -{ - otbrLog(OTBR_LOG_INFO, "BackboneAgent: Multicast Listener event: %d, address: %s, state: %s", aEvent, - Ip6Address(aAddress.mFields.m8).ToString().c_str(), StateToString(mBackboneRouterState)); - - switch (aEvent) - { - case OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ADDED: - mSMCRouteManager.Add(Ip6Address(aAddress.mFields.m8)); - break; - case OT_BACKBONE_ROUTER_MULTICAST_LISTENER_REMOVED: - mSMCRouteManager.Remove(Ip6Address(aAddress.mFields.m8)); - break; - } -} - void BackboneAgent::OnBecomePrimary(void) { otbrLog(OTBR_LOG_NOTICE, "BackboneAgent: Backbone Router becomes Primary!"); @@ -136,8 +103,6 @@ void BackboneAgent::OnBecomePrimary(void) { mNdProxyManager.Enable(mDomainPrefix); } - - mSMCRouteManager.Enable(); } void BackboneAgent::OnResignPrimary(void) @@ -146,7 +111,6 @@ void BackboneAgent::OnResignPrimary(void) StateToString(mBackboneRouterState)); mNdProxyManager.Disable(); - mSMCRouteManager.Disable(); } const char *BackboneAgent::StateToString(otBackboneRouterState aState) diff --git a/src/backbone_router/backbone_agent.hpp b/src/backbone_router/backbone_agent.hpp index 1ca1220384c..5fe22870938 100644 --- a/src/backbone_router/backbone_agent.hpp +++ b/src/backbone_router/backbone_agent.hpp @@ -39,7 +39,6 @@ #include "agent/instance_params.hpp" #include "agent/ncp_openthread.hpp" #include "backbone_router/nd_proxy.hpp" -#include "backbone_router/smcroute_manager.hpp" namespace otbr { namespace BackboneRouter { @@ -111,15 +110,11 @@ class BackboneAgent const otIp6Prefix * aDomainPrefix); static void HandleBackboneRouterNdProxyEvent(void *aContext, int aEvent, va_list aArguments); void HandleBackboneRouterNdProxyEvent(otBackboneRouterNdProxyEvent aEvent, const otIp6Address *aAddress); - static void HandleBackboneRouterMulticastListenerEvent(void *aContext, int aEvent, va_list aArguments); - void HandleBackboneRouterMulticastListenerEvent(otBackboneRouterMulticastListenerEvent aEvent, - const otIp6Address & aAddress); static const char *StateToString(otBackboneRouterState aState); otbr::Ncp::ControllerOpenThread &mNcp; otBackboneRouterState mBackboneRouterState; - SMCRouteManager mSMCRouteManager; NdProxyManager mNdProxyManager; Ip6Prefix mDomainPrefix; }; diff --git a/src/backbone_router/constants.hpp b/src/backbone_router/constants.hpp index 836eeb1a820..c853e12f138 100644 --- a/src/backbone_router/constants.hpp +++ b/src/backbone_router/constants.hpp @@ -34,12 +34,6 @@ #ifndef BACKBONE_CONSTANTS_HPP_ #define BACKBONE_CONSTANTS_HPP_ -#include - -#include "agent/ncp_openthread.hpp" -#include "backbone_router/nd_proxy.hpp" -#include "backbone_router/smcroute_manager.hpp" - namespace otbr { namespace BackboneRouter { diff --git a/src/backbone_router/nd_proxy.cpp b/src/backbone_router/nd_proxy.cpp index 897d814aad8..295d4e88a27 100644 --- a/src/backbone_router/nd_proxy.cpp +++ b/src/backbone_router/nd_proxy.cpp @@ -48,10 +48,12 @@ #error "Platform not supported" #endif +#include "agent/instance_params.hpp" #include "backbone_router/constants.hpp" #include "common/code_utils.hpp" #include "common/logging.hpp" #include "common/types.hpp" +#include "utils/system_utils.hpp" namespace otbr { namespace BackboneRouter { diff --git a/src/backbone_router/smcroute_manager.cpp b/src/backbone_router/smcroute_manager.cpp deleted file mode 100644 index f2a774ab3d5..00000000000 --- a/src/backbone_router/smcroute_manager.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2020, The OpenThread Authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * The file implements the SMCRoute manager. - */ - -#include "backbone_router/smcroute_manager.hpp" - -#include -#include - -#include - -#include "common/code_utils.hpp" -#include "utils/system_utils.hpp" - -namespace otbr { - -namespace BackboneRouter { - -void SMCRouteManager::Init(void) -{ - assert(!mEnabled); - - StartSMCRouteService(); -} - -void SMCRouteManager::Enable(void) -{ - otbrError error = OTBR_ERROR_NONE; - - VerifyOrExit(!mEnabled); - - mEnabled = true; - - Flush(); - - // Add mroute rules: 65520 (0xfff0) allow outbound for MA scope >= admin (4) - SuccessOrExit(error = AllowOutboundMulticast()); - - // Add mroute rules for the current Multicast Listeners Table - for (const Ip6Address &address : mListenerSet) - { - SuccessOrExit(error = AddRoute(address)); - } - -exit: - otbrLogResult(error, "SMCRouteManager: %s", __FUNCTION__); -} - -void SMCRouteManager::Disable(void) -{ - otbrError error = OTBR_ERROR_NONE; - - VerifyOrExit(mEnabled); - - mEnabled = false; - - Flush(); - - // Remove mroute rules for the current Multicast Listeners Table - for (const Ip6Address &address : mListenerSet) - { - SuccessOrExit(error = DeleteRoute(address)); - } - - // Remove mroute rules: forbid outbound Multicast traffic - SuccessOrExit(error = ForbidOutboundMulticast()); - -exit: - otbrLogResult(error, "SMCRouteManager: %s", __FUNCTION__); -} - -void SMCRouteManager::StartSMCRouteService(void) -{ - otbrError error = OTBR_ERROR_NONE; - std::chrono::system_clock::time_point deadline; - - VerifyOrExit(SystemUtils::ExecuteCommand("smcroutectl kill || true") == 0, error = OTBR_ERROR_SMCROUTE); - VerifyOrExit(SystemUtils::ExecuteCommand("smcrouted") == 0, error = OTBR_ERROR_SMCROUTE); - - deadline = std::chrono::system_clock::now() + std::chrono::seconds(10); - - while (std::chrono::system_clock::now() < deadline) - { - usleep(10000); - - VerifyOrExit((error = Flush()) != OTBR_ERROR_NONE); - } - -exit: - SuccessOrDie(error, "Failed to start SMCRoute service"); -} - -void SMCRouteManager::Add(const Ip6Address &aAddress) -{ - otbrError error = OTBR_ERROR_NONE; - - assert(mListenerSet.find(aAddress) == mListenerSet.end()); - mListenerSet.insert(aAddress); - - VerifyOrExit(mEnabled); - - Flush(); - error = AddRoute(aAddress); - -exit: - otbrLogResult(error, "SMCRouteManager: AddRoute %s", aAddress.ToString().c_str()); -} - -void SMCRouteManager::Remove(const Ip6Address &aAddress) -{ - otbrError error = OTBR_ERROR_NONE; - - assert(mListenerSet.find(aAddress) != mListenerSet.end()); - mListenerSet.erase(aAddress); - - VerifyOrExit(mEnabled); - - Flush(); - error = DeleteRoute(aAddress); -exit: - otbrLogResult(error, "SMCRouteManager: RemoveRoute %s", aAddress.ToString().c_str()); -} - -otbrError SMCRouteManager::AllowOutboundMulticast(void) -{ - return SystemUtils::ExecuteCommand("smcroutectl add %s :: :: 65520 %s", InstanceParams::Get().GetThreadIfName(), - InstanceParams::Get().GetBackboneIfName()) == 0 - ? OTBR_ERROR_NONE - : OTBR_ERROR_SMCROUTE; -} - -otbrError SMCRouteManager::ForbidOutboundMulticast(void) -{ - return SystemUtils::ExecuteCommand("smcroutectl remove %s :: :: 65520 %s", InstanceParams::Get().GetThreadIfName(), - InstanceParams::Get().GetBackboneIfName()) == 0 - ? OTBR_ERROR_NONE - : OTBR_ERROR_SMCROUTE; -} - -otbrError SMCRouteManager::AddRoute(const Ip6Address &aAddress) -{ - return SystemUtils::ExecuteCommand("smcroutectl add %s :: %s %s", InstanceParams::Get().GetBackboneIfName(), - aAddress.ToString().c_str(), InstanceParams::Get().GetThreadIfName()) == 0 - ? OTBR_ERROR_NONE - : OTBR_ERROR_SMCROUTE; -} - -otbrError SMCRouteManager::DeleteRoute(const Ip6Address &aAddress) -{ - return SystemUtils::ExecuteCommand("smcroutectl del %s :: %s %s", InstanceParams::Get().GetBackboneIfName(), - aAddress.ToString().c_str(), InstanceParams::Get().GetThreadIfName()) == 0 - ? OTBR_ERROR_NONE - : OTBR_ERROR_SMCROUTE; -} - -otbrError SMCRouteManager::Flush(void) -{ - return SystemUtils::ExecuteCommand("smcroutectl flush") == 0 ? OTBR_ERROR_NONE : OTBR_ERROR_SMCROUTE; -} - -} // namespace BackboneRouter - -} // namespace otbr diff --git a/src/backbone_router/smcroute_manager.hpp b/src/backbone_router/smcroute_manager.hpp deleted file mode 100644 index 0d6bb119e7b..00000000000 --- a/src/backbone_router/smcroute_manager.hpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2020, The OpenThread Authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * This file includes definition for SMCRoute manager. - */ - -#ifndef BACKBONE_ROUTER_SMCROUTE_MANAGER_HPP_ -#define BACKBONE_ROUTER_SMCROUTE_MANAGER_HPP_ - -#include -#include - -#include "agent/instance_params.hpp" -#include "agent/ncp_openthread.hpp" -#include "utils/system_utils.hpp" - -namespace otbr { -namespace BackboneRouter { - -/** - * @addtogroup border-router-backbone - * - * @brief - * This module includes definition for SMCRoute manager. - * - * @{ - */ - -/** - * This class implements SMCRoute manager functionality. - * - */ -class SMCRouteManager -{ -public: - /** - * This constructor initializes a SMCRoute manager instance. - * - */ - explicit SMCRouteManager() - : mEnabled(false) - { - } - - /** - * This method initializes a SMCRoute manager instance. - * - */ - void Init(void); - - /** - * This method enables the SMCRoute manager. - * - */ - void Enable(void); - - /** - * This method disables the SMCRoute manager. - * - */ - void Disable(void); - - /** - * This method adds a multicast route. - * - * NOTE: Multicast routes are only effective when the SMCRoute manager is enabled. - * - * @param[in] aAddress The multicast address. - * - */ - void Add(const Ip6Address &aAddress); - - /** - * This method removes a multicast route. - * - * @param[in] aAddress The multicast address. - * - */ - void Remove(const Ip6Address &aAddress); - -private: - void StartSMCRouteService(void); - otbrError Flush(void); - otbrError ForbidOutboundMulticast(void); - otbrError AllowOutboundMulticast(void); - otbrError AddRoute(const Ip6Address &aAddress); - otbrError DeleteRoute(const Ip6Address &aAddress); - - std::set mListenerSet; - bool mEnabled : 1; -}; - -/** - * @} - */ - -} // namespace BackboneRouter -} // namespace otbr - -#endif // BACKBONE_ROUTER_SMCROUTE_MANAGER_HPP_ diff --git a/src/common/logging.cpp b/src/common/logging.cpp index c35ed674f59..8cc795b3d16 100644 --- a/src/common/logging.cpp +++ b/src/common/logging.cpp @@ -156,10 +156,6 @@ const char *otbrErrorString(otbrError aError) error = "OpenThread error"; break; - case OTBR_ERROR_SMCROUTE: - error = "SMCRoute error"; - break; - case OTBR_ERROR_NOT_FOUND: error = "Not found"; break; diff --git a/third_party/openthread/repo b/third_party/openthread/repo index 0b0d6eef1d5..d33c2f12afe 160000 --- a/third_party/openthread/repo +++ b/third_party/openthread/repo @@ -1 +1 @@ -Subproject commit 0b0d6eef1d569c77a6cc08c3d4a39b76ea3e33c0 +Subproject commit d33c2f12afe0941651a7af5efbcc33bd58330833 From 48e53dfb0e7672978b9209361ecbea1a5c904542 Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Wed, 25 Nov 2020 01:00:42 +0800 Subject: [PATCH 028/175] [openthread] always enable SLAAC in ot-br-posix (#626) --- third_party/openthread/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/third_party/openthread/CMakeLists.txt b/third_party/openthread/CMakeLists.txt index fda2cf71364..54d4217146e 100644 --- a/third_party/openthread/CMakeLists.txt +++ b/third_party/openthread/CMakeLists.txt @@ -34,6 +34,7 @@ set(OT_COMMISSIONER ON CACHE BOOL "enable commissioner" FORCE) set(OT_DAEMON ON CACHE BOOL "enable daemon mode" FORCE) set(OT_JOINER ON CACHE BOOL "enable joiner" FORCE) set(OT_LEGACY ON CACHE STRING "enable legacy network support" FORCE) +set(OT_SLAAC ON CACHE BOOL "enable SLAAC" FORCE) if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(OT_LOG_LEVEL "DEBG" CACHE STRING "set OpenThread log level to DEBG" FORCE) From 56c9d92e073d2914f1b311a6b63e46ee6eb80a43 Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Wed, 25 Nov 2020 01:42:35 +0800 Subject: [PATCH 029/175] [dbus] fix typo (#625) --- src/dbus/server/dbus_thread_object.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/dbus/server/dbus_thread_object.cpp b/src/dbus/server/dbus_thread_object.cpp index 936deec4a93..88e7f6b70c5 100644 --- a/src/dbus/server/dbus_thread_object.cpp +++ b/src/dbus/server/dbus_thread_object.cpp @@ -529,8 +529,7 @@ otError DBusThreadObject::GetDeviceRoleHandler(DBusMessageIter &aIter) auto threadHelper = mNcp->GetThreadHelper(); otDeviceRole role = otThreadGetDeviceRole(threadHelper->GetInstance()); std::string roleName = GetDeviceRoleName(role); - ; - otError error = OT_ERROR_NONE; + otError error = OT_ERROR_NONE; VerifyOrExit(DBusMessageEncodeToVariant(&aIter, roleName) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); From 5ce31910705742c634f49a5a5373a15e604c4210 Mon Sep 17 00:00:00 2001 From: Yakun Xu Date: Thu, 26 Nov 2020 02:27:48 +0800 Subject: [PATCH 030/175] [script] disable DNS of dnsmasq when DNS64 is on (#624) This commit disables DNS of dnsmasq when DNS64 is enabled, because bind9 provides DNS service already. --- script/_network_manager | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/script/_network_manager b/script/_network_manager index c105bfa73cc..2d73179f695 100644 --- a/script/_network_manager +++ b/script/_network_manager @@ -330,6 +330,12 @@ network_manager_install() return 0 fi + if with DNS64; then + # bind9 provides DNS service + sudo sed -i 's/^#port=5353/port=0/g' /etc/dnsmasq.conf + sudo systemctl stop dnsmasq + fi + sudo systemctl daemon-reload sudo systemctl stop wpa_supplicant || true @@ -372,6 +378,12 @@ network_manager_uninstall() { with NETWORK_MANAGER || return 0 + if with DNS64; then + # revert changes to dnsmasq + sudo sed -i 's/^port=0/#port=5353/g' /etc/dnsmasq.conf + sudo systemctl restart dnsmasq + fi + if ! have systemctl; then echo "This script requires systemctl!" return 0 From c6c72733661f7a80b02977c1d9b84035c1ca6d96 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Sat, 28 Nov 2020 01:23:15 +0800 Subject: [PATCH 031/175] [plat] set gPlatResetReason for software reset (#628) openthread/openthread#5466 allows ot-ctl to reconnect to otbr-agent or ot-daemon seamlessly. However, otbr-agent didn't set gPlatResetReason correctly thus this feature is not working for otbr-agent. This commit fix this issue. --- src/agent/ncp_openthread.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/agent/ncp_openthread.cpp b/src/agent/ncp_openthread.cpp index 07130957bd3..1db65789f51 100644 --- a/src/agent/ncp_openthread.cpp +++ b/src/agent/ncp_openthread.cpp @@ -248,6 +248,8 @@ void ControllerOpenThread::Process(const otSysMainloopContext &aMainloop) void ControllerOpenThread::Reset(void) { + gPlatResetReason = OT_PLAT_RESET_REASON_SOFTWARE; + otInstanceFinalize(mInstance); otSysDeinit(); Init(); @@ -435,5 +437,6 @@ extern "C" void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const ch void otPlatReset(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); + sReset = true; } From 089271cbf530239072fa426af9896efd21019b73 Mon Sep 17 00:00:00 2001 From: Yakun Xu Date: Mon, 30 Nov 2020 23:38:40 +0800 Subject: [PATCH 032/175] [script] fix starting network manager (#630) --- script/_network_manager | 4 ++-- tests/scripts/check-scripts | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/script/_network_manager b/script/_network_manager index 2d73179f695..6dff89730d5 100644 --- a/script/_network_manager +++ b/script/_network_manager @@ -333,7 +333,7 @@ network_manager_install() if with DNS64; then # bind9 provides DNS service sudo sed -i 's/^#port=5353/port=0/g' /etc/dnsmasq.conf - sudo systemctl stop dnsmasq + sudo systemctl restart dnsmasq fi sudo systemctl daemon-reload @@ -379,9 +379,9 @@ network_manager_uninstall() with NETWORK_MANAGER || return 0 if with DNS64; then + sudo systemctl stop dnsmasq # revert changes to dnsmasq sudo sed -i 's/^port=0/#port=5353/g' /etc/dnsmasq.conf - sudo systemctl restart dnsmasq fi if ! have systemctl; then diff --git a/tests/scripts/check-scripts b/tests/scripts/check-scripts index 6ac1d957b51..83f08413186 100755 --- a/tests/scripts/check-scripts +++ b/tests/scripts/check-scripts @@ -44,6 +44,8 @@ main() RELEASE=1 ./script/bootstrap ./script/bootstrap NAT64=1 ./script/setup + # re-run to ensure the script can run successfully multiple times + NAT64=1 ./script/setup SOCAT_OUTPUT=/tmp/ot-socat socat -d -d pty,raw,echo=0 pty,raw,echo=0 >/dev/null 2>$SOCAT_OUTPUT & From cbf2329cf2569164f28cda98da1ed9bd31e9d78b Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Thu, 3 Dec 2020 00:49:15 +0800 Subject: [PATCH 033/175] [cli] fix reset command (#632) --- src/agent/main.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/agent/main.cpp b/src/agent/main.cpp index c24942382b6..a8e4d7aaa57 100644 --- a/src/agent/main.cpp +++ b/src/agent/main.cpp @@ -107,17 +107,17 @@ static void HandleSignal(int aSignal) static int Mainloop(otbr::AgentInstance &aInstance, const char *aInterfaceName) { - int error = EXIT_FAILURE; + int error = EXIT_FAILURE; + ControllerOpenThread &ncpOpenThread = static_cast(aInstance.GetNcp()); + #if OTBR_ENABLE_DBUS_SERVER - ControllerOpenThread * ncpOpenThread = reinterpret_cast(&aInstance.GetNcp()); - std::unique_ptr dbusAgent = std::unique_ptr(new DBusAgent(aInterfaceName, ncpOpenThread)); + std::unique_ptr dbusAgent = std::unique_ptr(new DBusAgent(aInterfaceName, &ncpOpenThread)); dbusAgent->Init(); #else (void)aInterfaceName; #endif #if OTBR_ENABLE_REST_SERVER - ControllerOpenThread *ncpOpenThreadRest = reinterpret_cast(&aInstance.GetNcp()); - RestWebServer * restServer = RestWebServer::GetRestWebServer(ncpOpenThreadRest); + RestWebServer *restServer = RestWebServer::GetRestWebServer(&ncpOpenThread); restServer->Init(); #endif otbrLog(OTBR_LOG_INFO, "Border router agent started."); @@ -155,13 +155,11 @@ static int Mainloop(otbr::AgentInstance &aInstance, const char *aInterfaceName) rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet, &mainloop.mTimeout); -#if OTBR_ENABLE_DBUS_SERVER - if (ncpOpenThread->IsResetRequested()) + if (ncpOpenThread.IsResetRequested()) { - ncpOpenThread->Reset(); + ncpOpenThread.Reset(); continue; } -#endif if (rval >= 0) { From 1afaf59d8e120b9db7933b3f9e3845e5949644d3 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Thu, 3 Dec 2020 09:42:41 +0800 Subject: [PATCH 034/175] [github-actions] switch to ubuntu 20.04 (#640) --- .github/workflows/build.yml | 14 +++++++------- .github/workflows/docker.yml | 4 ++-- .github/workflows/macOS.yml | 2 +- .github/workflows/raspbian.yml | 4 ++-- tests/scripts/bootstrap.sh | 1 + 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2ae58a45147..45ac5dfe9dc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,7 +33,7 @@ on: [push, pull_request] jobs: cancel-previous-runs: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - uses: rokroskar/workflow-run-cleanup-action@master env: @@ -50,7 +50,7 @@ jobs: run: script/make-pretty check android-check: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 strategy: matrix: mdns: ["mDNSResponder", ""] @@ -67,7 +67,7 @@ jobs: ot-br-posix/tests/scripts/check-android-build" check: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 strategy: matrix: mdns: ["mDNSResponder", "avahi"] @@ -87,7 +87,7 @@ jobs: uses: codecov/codecov-action@v1 rest-check: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 strategy: matrix: rest: ["rest-off", ""] @@ -107,7 +107,7 @@ jobs: uses: codecov/codecov-action@v1 script-check: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 env: BUILD_TARGET: script-check OTBR_COVERAGE: 1 @@ -123,7 +123,7 @@ jobs: uses: codecov/codecov-action@v1 scan-build: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 env: BUILD_TARGET: scan-build CC: clang @@ -154,7 +154,7 @@ jobs: run: script/test package thread-1-2-backbone: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 env: PACKET_VERIFICATION: 1 REFERENCE_DEVICE: 1 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index ac7434b219e..a24d05da20e 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -33,7 +33,7 @@ on: [push, pull_request] jobs: cancel-previous-runs: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - uses: rokroskar/workflow-run-cleanup-action@master env: @@ -41,7 +41,7 @@ jobs: if: "github.ref != 'refs/heads/master'" buildx: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 strategy: matrix: include: diff --git a/.github/workflows/macOS.yml b/.github/workflows/macOS.yml index 6e6d7f55513..518ef9f1162 100644 --- a/.github/workflows/macOS.yml +++ b/.github/workflows/macOS.yml @@ -5,7 +5,7 @@ on: [push, pull_request] jobs: cancel-previous-runs: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - uses: rokroskar/workflow-run-cleanup-action@master env: diff --git a/.github/workflows/raspbian.yml b/.github/workflows/raspbian.yml index ed798b39a17..bf0ea035d35 100644 --- a/.github/workflows/raspbian.yml +++ b/.github/workflows/raspbian.yml @@ -33,7 +33,7 @@ on: [push, pull_request] jobs: cancel-previous-runs: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - uses: rokroskar/workflow-run-cleanup-action@master env: @@ -41,7 +41,7 @@ jobs: if: "github.ref != 'refs/heads/master'" raspbian-check: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 env: IMAGE_URL: http://director.downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2018-04-19/2018-04-18-raspbian-stretch-lite.zip BUILD_TARGET: raspbian-gcc diff --git a/tests/scripts/bootstrap.sh b/tests/scripts/bootstrap.sh index f8d5428b748..fb74d594c2b 100755 --- a/tests/scripts/bootstrap.sh +++ b/tests/scripts/bootstrap.sh @@ -54,6 +54,7 @@ install_common_dependencies() ninja-build \ doxygen \ expect \ + net-tools \ libboost-dev \ libboost-filesystem-dev \ libboost-system-dev \ From b19a7340a6a30359dd33f8feb49790e4e512308d Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Thu, 3 Dec 2020 14:30:40 +0800 Subject: [PATCH 035/175] [ncp] re-attach when soft reset is triggered (#639) --- src/agent/ncp_openthread.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/agent/ncp_openthread.cpp b/src/agent/ncp_openthread.cpp index 1db65789f51..e09dcd8056e 100644 --- a/src/agent/ncp_openthread.cpp +++ b/src/agent/ncp_openthread.cpp @@ -257,7 +257,8 @@ void ControllerOpenThread::Reset(void) { handler(); } - sReset = false; + mTriedAttach = false; + sReset = false; } bool ControllerOpenThread::IsResetRequested(void) From 8c734165a43232c234ec9e9662353d4ce19cbe5e Mon Sep 17 00:00:00 2001 From: IHIDCHAOS Date: Thu, 3 Dec 2020 14:31:11 +0800 Subject: [PATCH 036/175] [otbr-web] fix Status page exception (#633) --- src/web/web-service/wpan_service.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/web-service/wpan_service.cpp b/src/web/web-service/wpan_service.cpp index 0f0b1d561ce..848d401079b 100644 --- a/src/web/web-service/wpan_service.cpp +++ b/src/web/web-service/wpan_service.cpp @@ -292,7 +292,7 @@ std::string WpanService::HandleStatusRequest() networkInfo["IPv6:MeshLocalPrefix"] = rval; meshLocalPrefix = rval; - meshLocalPrefix.resize(meshLocalPrefix.find('/')); + meshLocalPrefix.resize(meshLocalPrefix.find(":/")); VerifyOrExit((rval = client.Execute("ipaddr")) != nullptr, ret = kWpanStatus_GetPropertyFailed); From 5abbbdbd404336e5b57c51939a540aae9c44c22d Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Wed, 9 Dec 2020 15:37:53 +0800 Subject: [PATCH 037/175] [dhcp6] enable DHCP6 server and client for reference device (#646) --- script/_otbr | 2 ++ 1 file changed, 2 insertions(+) diff --git a/script/_otbr b/script/_otbr index 66729465e96..98da06627fc 100644 --- a/script/_otbr +++ b/script/_otbr @@ -73,6 +73,8 @@ otbr_install() if [[ ${REFERENCE_DEVICE} == "1" ]]; then otbr_options+=( "-DOT_REFERENCE_DEVICE=ON" + "-DOT_DHCP6_CLIENT=ON" + "-DOT_DHCP6_SERVER=ON" ) fi if with BACKBONE_ROUTER; then From 4dc187f9d9c7b6625d75086667b8bc19d7de1019 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Sat, 12 Dec 2020 01:26:13 +0800 Subject: [PATCH 038/175] [openwrt] fix leaderpartitionid (#645) --- src/openwrt/controller/thread.lua | 2 - src/openwrt/ubus/otubus.cpp | 44 ++++--------------- src/openwrt/ubus/otubus.hpp | 30 +++---------- .../view/admin_thread/thread_setting.htm | 26 +---------- third_party/openthread/repo | 2 +- 5 files changed, 18 insertions(+), 86 deletions(-) diff --git a/src/openwrt/controller/thread.lua b/src/openwrt/controller/thread.lua index 869ab3455c5..245d1fc5577 100644 --- a/src/openwrt/controller/thread.lua +++ b/src/openwrt/controller/thread.lua @@ -59,7 +59,6 @@ function thread_handler_setting() local panid = luci.http.formvalue("panid") local extpanid = luci.http.formvalue("extpanid") local mode = luci.http.formvalue("mode") - local leaderpartitionid = luci.http.formvalue("leaderpartitionid") + 0 local masterkey = luci.http.formvalue("masterkey") local pskc = luci.http.formvalue("pskc") local macfilter = luci.http.formvalue("macfilterselect") @@ -112,7 +111,6 @@ function thread_handler_setting() conn:call("otbr", "setpanid", { panid = panid }) conn:call("otbr", "setextpanid", { extpanid = extpanid }) conn:call("otbr", "setmode", { mode = mode }) - conn:call("otbr", "setleaderpartitionid", { leaderpartitionid = leaderpartitionid }) conn:call("otbr", "setmasterkey", { masterkey = masterkey }) conn:call("otbr", "setpskc", { pskc = pskc }) conn:call("otbr", "macfiltersetstate", { state = macfilter }) diff --git a/src/openwrt/ubus/otubus.cpp b/src/openwrt/ubus/otubus.cpp index 78b954ce193..b531fe2be9a 100644 --- a/src/openwrt/ubus/otubus.cpp +++ b/src/openwrt/ubus/otubus.cpp @@ -134,10 +134,6 @@ static const struct blobmsg_policy setModePolicy[SET_NETWORK_MAX] = { [SETNETWORK] = {.name = "mode", .type = BLOBMSG_TYPE_STRING}, }; -static const struct blobmsg_policy setLeaderPartitionIdPolicy[SET_NETWORK_MAX] = { - [SETNETWORK] = {.name = "leaderpartitionid", .type = BLOBMSG_TYPE_INT32}, -}; - static const struct blobmsg_policy macfilterAddPolicy[SET_NETWORK_MAX] = { [SETNETWORK] = {.name = "addr", .type = BLOBMSG_TYPE_STRING}, }; @@ -191,9 +187,7 @@ static const struct ubus_method otbrMethods[] = { {"parent", &UbusServer::UbusParentHandler, 0, 0, nullptr, 0}, {"mode", &UbusServer::UbusModeHandler, 0, 0, nullptr, 0}, {"setmode", &UbusServer::UbusSetModeHandler, 0, 0, setModePolicy, ARRAY_SIZE(setModePolicy)}, - {"leaderpartitionid", &UbusServer::UbusLeaderPartitionIdHandler, 0, 0, nullptr, 0}, - {"setleaderpartitionid", &UbusServer::UbusSetLeaderPartitionIdHandler, 0, 0, setLeaderPartitionIdPolicy, - ARRAY_SIZE(setLeaderPartitionIdPolicy)}, + {"partitionid", &UbusServer::UbusPartitionIdHandler, 0, 0, nullptr, 0}, {"leave", &UbusServer::UbusLeaveHandler, 0, 0, nullptr, 0}, {"leaderdata", &UbusServer::UbusLeaderdataHandler, 0, 0, nullptr, 0}, {"networkdata", &UbusServer::UbusNetworkdataHandler, 0, 0, nullptr, 0}, @@ -535,22 +529,13 @@ int UbusServer::UbusSetModeHandler(struct ubus_context * aContext, return GetInstance().UbusSetInformation(aContext, aObj, aRequest, aMethod, aMsg, "mode"); } -int UbusServer::UbusLeaderPartitionIdHandler(struct ubus_context * aContext, - struct ubus_object * aObj, - struct ubus_request_data *aRequest, - const char * aMethod, - struct blob_attr * aMsg) -{ - return GetInstance().UbusGetInformation(aContext, aObj, aRequest, aMethod, aMsg, "leaderpartitionid"); -} - -int UbusServer::UbusSetLeaderPartitionIdHandler(struct ubus_context * aContext, - struct ubus_object * aObj, - struct ubus_request_data *aRequest, - const char * aMethod, - struct blob_attr * aMsg) +int UbusServer::UbusPartitionIdHandler(struct ubus_context * aContext, + struct ubus_object * aObj, + struct ubus_request_data *aRequest, + const char * aMethod, + struct blob_attr * aMsg) { - return GetInstance().UbusSetInformation(aContext, aObj, aRequest, aMethod, aMsg, "leaderpartitionid"); + return GetInstance().UbusGetInformation(aContext, aObj, aRequest, aMethod, aMsg, "partitionid"); } int UbusServer::UbusLeaveHandler(struct ubus_context * aContext, @@ -1161,9 +1146,9 @@ int UbusServer::UbusGetInformation(struct ubus_context * aContext, } blobmsg_add_string(&mBuf, "Mode", mode); } - else if (!strcmp(aAction, "leaderpartitionid")) + else if (!strcmp(aAction, "partitionid")) { - blobmsg_add_u32(&mBuf, "Leaderpartitionid", otThreadGetLocalLeaderPartitionId(mController->GetInstance())); + blobmsg_add_u32(&mBuf, "Partitionid", otThreadGetPartitionId(mController->GetInstance())); } else if (!strcmp(aAction, "leaderdata")) { @@ -1543,17 +1528,6 @@ int UbusServer::UbusSetInformation(struct ubus_context * aContext, SuccessOrExit(error = otThreadSetLinkMode(mController->GetInstance(), linkMode)); } } - else if (!strcmp(aAction, "leaderpartitionid")) - { - struct blob_attr *tb[SET_NETWORK_MAX]; - - blobmsg_parse(setLeaderPartitionIdPolicy, SET_NETWORK_MAX, tb, blob_data(aMsg), blob_len(aMsg)); - if (tb[SETNETWORK] != nullptr) - { - uint32_t input = blobmsg_get_u32(tb[SETNETWORK]); - otThreadSetLocalLeaderPartitionId(mController->GetInstance(), input); - } - } else if (!strcmp(aAction, "macfilteradd")) { struct blob_attr *tb[SET_NETWORK_MAX]; diff --git a/src/openwrt/ubus/otubus.hpp b/src/openwrt/ubus/otubus.hpp index d1c9f47c94d..cb7e7e503ad 100644 --- a/src/openwrt/ubus/otubus.hpp +++ b/src/openwrt/ubus/otubus.hpp @@ -413,7 +413,7 @@ class UbusServer struct blob_attr * aMsg); /** - * This method handle ubus get leaderpartitionid function request. + * This method handle ubus get partitionid function request. * * @param[in] aContext A pointer to the ubus context. * @param[in] aObj A pointer to the ubus object. @@ -424,29 +424,11 @@ class UbusServer * @retval 0 Successfully handler the request. * */ - static int UbusLeaderPartitionIdHandler(struct ubus_context * aContext, - struct ubus_object * aObj, - struct ubus_request_data *aRequest, - const char * aMethod, - struct blob_attr * aMsg); - - /** - * This method handle ubus set learderpartitionid function request. - * - * @param[in] aContext A pointer to the ubus context. - * @param[in] aObj A pointer to the ubus object. - * @param[in] aRequest A pointer to the ubus request. - * @param[in] aMethod A pointer to the ubus method. - * @param[in] aMsg A pointer to the ubus message. - * - * @retval 0 Successfully handler the request. - * - */ - static int UbusSetLeaderPartitionIdHandler(struct ubus_context * aContext, - struct ubus_object * aObj, - struct ubus_request_data *aRequest, - const char * aMethod, - struct blob_attr * aMsg); + static int UbusPartitionIdHandler(struct ubus_context * aContext, + struct ubus_object * aObj, + struct ubus_request_data *aRequest, + const char * aMethod, + struct blob_attr * aMsg); /** * This method handle ubus get leaderdata function request. diff --git a/src/openwrt/view/admin_thread/thread_setting.htm b/src/openwrt/view/admin_thread/thread_setting.htm index aba88ea3c27..f291a0a20be 100644 --- a/src/openwrt/view/admin_thread/thread_setting.htm +++ b/src/openwrt/view/admin_thread/thread_setting.htm @@ -160,23 +160,13 @@

<%:Network Configuration%>

- <% if state == 'disabled' then %> - +
- " style="width:50%;"/> -
-
- "/><%:leaderpartitionid must be a number%> -
- <% else %> - -
- " readonly="readonly" style="width:50%;"/> + <%=threadget("partitionid").Partitionid%>
"/><%:can not change partitionid when thread network is started.%>
- <% end %>
@@ -393,18 +383,6 @@

<%:Interface Configuration%>

return false; } - var leaderpartitionid = document.forms["settingForm"]["leaderpartitionid"].value; - if (isNaN(leaderpartitionid)) { - alert("leaderpartitionid must be a number"); - return false; - } - - var leaderpartitionid = document.forms["settingForm"]["leaderpartitionid"].value; - if (isNaN(leaderpartitionid)) { - alert("leaderpartitionid must be a number"); - return false; - } - var masterkey = document.forms["settingForm"]["masterkey"].value; if (masterkey.length != 32) { alert("Masterkey length must be 32 bytes"); diff --git a/third_party/openthread/repo b/third_party/openthread/repo index d33c2f12afe..02f7dbb42be 160000 --- a/third_party/openthread/repo +++ b/third_party/openthread/repo @@ -1 +1 @@ -Subproject commit d33c2f12afe0941651a7af5efbcc33bd58330833 +Subproject commit 02f7dbb42be7f75355436ec43bc82d0b2b4caad6 From b7735542cf5ef668737c81f34f0c4c276830dd03 Mon Sep 17 00:00:00 2001 From: Yakun Xu Date: Sun, 13 Dec 2020 00:52:00 +0800 Subject: [PATCH 039/175] [test] move all jobs to GitHub Actions (#651) --- .github/workflows/build.yml | 2 +- .github/workflows/docker.yml | 20 +++++++ .github/workflows/meshcop.yml | 70 +++++++++++++++++++++++++ .github/workflows/openwrt.yml | 54 +++++++++++++++++++ .travis.yml | 21 -------- .travis/after_success.sh | 54 ------------------- .travis/script.sh | 59 --------------------- {.travis => tests/scripts}/check-docker | 6 +-- tests/scripts/openwrt | 16 +++--- 9 files changed, 156 insertions(+), 146 deletions(-) create mode 100644 .github/workflows/meshcop.yml create mode 100644 .github/workflows/openwrt.yml delete mode 100644 .travis.yml delete mode 100755 .travis/after_success.sh delete mode 100755 .travis/script.sh rename {.travis => tests/scripts}/check-docker (94%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 45ac5dfe9dc..d312efe899d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,7 +45,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Bootstrap - run: sudo BUILD_TARGET=pretty-check tests/scripts/bootstrap.sh + run: BUILD_TARGET=pretty-check tests/scripts/bootstrap.sh - name: Check run: script/make-pretty check diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index a24d05da20e..76c0018b318 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -40,6 +40,26 @@ jobs: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" if: "github.ref != 'refs/heads/master'" + docker-check: + runs-on: ubuntu-latest + strategy: + matrix: + rcp_bus: ["UART", "SPI"] + env: + OT_POSIX_CONFIG_RCP_BUS: ${{matrix.rcp_bus}} + OTBR_COVERAGE: 1 + VERBOSE: 1 + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Bootstrap + env: + BUILD_TARGET: "docker-check" + run: tests/scripts/bootstrap.sh + - name: Check + run: tests/scripts/check-docker + buildx: runs-on: ubuntu-20.04 strategy: diff --git a/.github/workflows/meshcop.yml b/.github/workflows/meshcop.yml new file mode 100644 index 00000000000..2a5aa9bf2b2 --- /dev/null +++ b/.github/workflows/meshcop.yml @@ -0,0 +1,70 @@ +# +## 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. +## + +name: MeshCoP + +on: [push, pull_request] + +jobs: + + cancel-previous-runs: + runs-on: ubuntu-latest + steps: + - uses: rokroskar/workflow-run-cleanup-action@master + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + if: "github.ref != 'refs/heads/master'" + + meshcop: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Bootstrap + env: + BUILD_TARGET: "meshcop" + run: tests/scripts/bootstrap.sh + - name: Build + run: | + script/bootstrap + script/test build + - name: MTD + env: + OT_CLI: "ot-cli-mtd" + run: script/test meshcop + - name: FTD + env: + OT_CLI: "ot-cli-ftd" + run: script/test meshcop + - name: Web Commissioner + env: + OTBR_USE_WEB_COMMISSIONER: 1 + run: script/test meshcop + - name: Codecov + uses: codecov/codecov-action@v1 diff --git a/.github/workflows/openwrt.yml b/.github/workflows/openwrt.yml new file mode 100644 index 00000000000..ccbdfa5dcb4 --- /dev/null +++ b/.github/workflows/openwrt.yml @@ -0,0 +1,54 @@ +# +## 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. +## + +name: OpenWrt + +on: [push, pull_request] + +jobs: + + cancel-previous-runs: + runs-on: ubuntu-latest + steps: + - uses: rokroskar/workflow-run-cleanup-action@master + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + if: "github.ref != 'refs/heads/master'" + + openwrt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Bootstrap + env: + BUILD_TARGET: "openwrt-check" + run: tests/scripts/bootstrap.sh + - name: Check + run: script/test openwrt diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index e2f3bca8d2a..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -language: python -python: "3.6" - -dist: bionic -os: linux - -cache: - directories: - - $HOME/.cache/tools - -before_install: ./tests/scripts/bootstrap.sh -script: .travis/script.sh -after_success: - - .travis/after_success.sh - -jobs: - include: - - env: BUILD_TARGET="docker-check" OTBR_COVERAGE=1 VERBOSE=1 - - env: BUILD_TARGET="docker-check" OT_POSIX_CONFIG_RCP_BUS=SPI OTBR_COVERAGE=1 VERBOSE=1 - - env: BUILD_TARGET="openwrt-check" VERBOSE=1 - - env: BUILD_TARGET="meshcop" OTBR_COVERAGE=1 VERBOSE=1 diff --git a/.travis/after_success.sh b/.travis/after_success.sh deleted file mode 100755 index 9f64999716c..00000000000 --- a/.travis/after_success.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2019, 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. -# - -[ -n "$BUILD_TARGET" ] || exit 0 - -set -e - -codecov_upload() -{ - curl -s https://codecov.io/bash >codecov - chmod a+x codecov - - # Assume gcov by default, and llvm-cov if CC is clang - if [[ -z $CC ]]; then - ./codecov - elif "$CC" --version | grep -q gcc; then - ./codecov - elif "$CC" --version | grep -q clang; then - ./codecov -x "llvm-cov gcov" - fi -} - -main() -{ - codecov_upload -} - -main "$@" diff --git a/.travis/script.sh b/.travis/script.sh deleted file mode 100755 index 05e6be4e470..00000000000 --- a/.travis/script.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -# -# 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. -# - -set -e -set -x - -export PATH=/usr/local/bin:$PATH - -case $BUILD_TARGET in - meshcop) - ./script/bootstrap - ./script/test build - - OT_CLI="ot-cli-mtd" ./script/test meshcop - OT_CLI="ot-cli-ftd" ./script/test meshcop - OTBR_USE_WEB_COMMISSIONER=1 ./script/test meshcop - ;; - - openwrt-check) - ./script/test openwrt - ;; - - docker-check) - .travis/check-docker - ;; - - otbr-dbus-check) - .travis/check-otbr-dbus - ;; - *) - false - ;; -esac diff --git a/.travis/check-docker b/tests/scripts/check-docker similarity index 94% rename from .travis/check-docker rename to tests/scripts/check-docker index b2140b8faed..fbaa89a7f8c 100755 --- a/.travis/check-docker +++ b/tests/scripts/check-docker @@ -49,12 +49,12 @@ main() # SPI simulation is not available yet, so just verify the binary runs if [[ ${OT_POSIX_CONFIG_RCP_BUS} == SPI ]]; then - docker run --rm -it --entrypoint otbr-agent otbr -h | grep 'spi://' + docker run --rm -t --entrypoint otbr-agent otbr -h | grep 'spi://' return 0 fi local -r SOCAT_OUTPUT=/tmp/ot-socat - socat -d -d pty,raw,echo=0 pty,raw,echo=0 >/dev/null 2>$SOCAT_OUTPUT & + socat -d -d pty,raw,echo=0 pty,raw,echo=0 2>&1 | tee $SOCAT_OUTPUT & while true; do if test "$(head -n2 "$SOCAT_OUTPUT" | wc -l)" = 2; then local -r DEVICE_PTY=$(head -n1 $SOCAT_OUTPUT | grep -o '/dev/.\+') @@ -70,7 +70,7 @@ main() # shellcheck disable=SC2094 ot-rcp 1 >"$DEVICE_PTY" <"$DEVICE_PTY" & - readonly OTBR_DOCKER_PID=$(docker run --rm -dit \ + readonly OTBR_DOCKER_PID=$(docker run --rm -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) sleep 10 diff --git a/tests/scripts/openwrt b/tests/scripts/openwrt index aa3517e748a..902a261ba12 100755 --- a/tests/scripts/openwrt +++ b/tests/scripts/openwrt @@ -45,20 +45,20 @@ do_prepare() echo 'src-link openthread /home/build/ot-br-posix/etc/openwrt' >feeds.conf docker start "${CONTAINER_NAME}" - docker exec -it "${CONTAINER_NAME}" scripts/feeds update base - docker exec -it "${CONTAINER_NAME}" scripts/feeds install libjson-c libubox libubus + docker exec "${CONTAINER_NAME}" scripts/feeds update base + docker exec "${CONTAINER_NAME}" scripts/feeds install libjson-c libubox libubus docker cp feeds.conf "${CONTAINER_NAME}":/home/build/openwrt/feeds.conf - docker exec -it "${CONTAINER_NAME}" sudo chown -R build:build /home/build/ot-br-posix /home/build/openwrt/feeds.conf /home/build/openwrt/bin - docker exec -it "${CONTAINER_NAME}" scripts/feeds update openthread - docker exec -it "${CONTAINER_NAME}" make defconfig - docker exec -it "${CONTAINER_NAME}" scripts/feeds install openthread-br + docker exec "${CONTAINER_NAME}" sudo chown -R build:build /home/build/ot-br-posix /home/build/openwrt/feeds.conf /home/build/openwrt/bin + docker exec "${CONTAINER_NAME}" scripts/feeds update openthread + docker exec "${CONTAINER_NAME}" make defconfig + docker exec "${CONTAINER_NAME}" scripts/feeds install openthread-br } do_build() { - docker exec -it "${CONTAINER_NAME}" make V=sc package/openthread-br/compile - docker exec -it "${CONTAINER_NAME}" find . -name "${PACKAGE_NAME}*.ipk" | grep "${PACKAGE_NAME}" + docker exec "${CONTAINER_NAME}" make V=sc package/openthread-br/compile + docker exec "${CONTAINER_NAME}" find . -name "${PACKAGE_NAME}*.ipk" | grep "${PACKAGE_NAME}" } do_clean() From 07e971761549416aca17bc209ba5ed08806033a2 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Thu, 17 Dec 2020 00:13:25 +0800 Subject: [PATCH 040/175] [backbone-router] add build options for backbone router features (#638) --- CMakeLists.txt | 1 + src/agent/instance_params.hpp | 6 ----- src/agent/main.cpp | 33 +++++++------------------- src/backbone_router/backbone_agent.hpp | 4 ++-- third_party/openthread/repo | 2 +- 5 files changed, 13 insertions(+), 33 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 48ffe9ec2c9..d708f856ea3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,6 +96,7 @@ if (OTBR_BACKBONE_ROUTER) target_compile_definitions(otbr-config INTERFACE OTBR_ENABLE_BACKBONE_ROUTER=1 ) + set(OT_BACKBONE_ROUTER_DUA_NDPROXYING ON CACHE BOOL "Enable Backbone Router DUA ND Proxying in OpenThread" FORCE) set(OT_THREAD_VERSION 1.2 CACHE STRING "Backbone Router requires Thread 1.2 or higher" FORCE) set(OT_BACKBONE_ROUTER ON CACHE BOOL "Enable Backbone Router feature in OpenThread" FORCE) set(OT_SERVICE ON CACHE BOOL "Backbone Router requires Thread network service" FORCE) diff --git a/src/agent/instance_params.hpp b/src/agent/instance_params.hpp index 1cc25afe4b3..107bd61e861 100644 --- a/src/agent/instance_params.hpp +++ b/src/agent/instance_params.hpp @@ -67,7 +67,6 @@ class InstanceParams */ const char *GetThreadIfName(void) const { return mThreadIfName; } -#if OTBR_ENABLE_BACKBONE_ROUTER /** * This method sets the Backbone network interface name. * @@ -83,21 +82,16 @@ class InstanceParams * */ const char *GetBackboneIfName(void) const { return mBackboneIfName; } -#endif private: InstanceParams() : mThreadIfName(nullptr) -#if OTBR_ENABLE_BACKBONE_ROUTER , mBackboneIfName(nullptr) -#endif { } const char *mThreadIfName; -#if OTBR_ENABLE_BACKBONE_ROUTER const char *mBackboneIfName; -#endif }; } // namespace otbr diff --git a/src/agent/main.cpp b/src/agent/main.cpp index a8e4d7aaa57..a6bce8c77df 100644 --- a/src/agent/main.cpp +++ b/src/agent/main.cpp @@ -72,15 +72,13 @@ static const char kDefaultInterfaceName[] = "wpan0"; enum { -#if OTBR_ENABLE_BACKBONE_ROUTER OTBR_OPT_BACKBONE_INTERFACE_NAME = 'B', -#endif - OTBR_OPT_DEBUG_LEVEL = 'd', - OTBR_OPT_HELP = 'h', - OTBR_OPT_INTERFACE_NAME = 'I', - OTBR_OPT_VERBOSE = 'v', - OTBR_OPT_VERSION = 'V', - OTBR_OPT_SHORTMAX = 128, + OTBR_OPT_DEBUG_LEVEL = 'd', + OTBR_OPT_HELP = 'h', + OTBR_OPT_INTERFACE_NAME = 'I', + OTBR_OPT_VERBOSE = 'v', + OTBR_OPT_VERSION = 'V', + OTBR_OPT_SHORTMAX = 128, OTBR_OPT_RADIO_VERSION, OTBR_OPT_REGION, }; @@ -88,9 +86,7 @@ enum // Default poll timeout. static const struct timeval kPollTimeout = {10, 0}; static const struct option kOptions[] = { -#if OTBR_ENABLE_BACKBONE_ROUTER {"backbone-ifname", required_argument, nullptr, OTBR_OPT_BACKBONE_INTERFACE_NAME}, -#endif {"debug-level", required_argument, nullptr, OTBR_OPT_DEBUG_LEVEL}, {"help", no_argument, nullptr, OTBR_OPT_HELP}, {"thread-ifname", required_argument, nullptr, OTBR_OPT_INTERFACE_NAME}, @@ -229,20 +225,14 @@ int main(int argc, char *argv[]) std::set_new_handler(OnAllocateFailed); - while ((opt = getopt_long(argc, argv, -#if OTBR_ENABLE_BACKBONE_ROUTER - "B:" -#endif - "d:hI:Vv", - kOptions, nullptr)) != -1) + while ((opt = getopt_long(argc, argv, "B:d:hI:Vv", kOptions, nullptr)) != -1) { switch (opt) { -#if OTBR_ENABLE_BACKBONE_ROUTER case OTBR_OPT_BACKBONE_INTERFACE_NAME: backboneInterfaceName = optarg; break; -#endif + case OTBR_OPT_DEBUG_LEVEL: logLevel = atoi(optarg); VerifyOrExit(logLevel >= OTBR_LOG_EMERG && logLevel <= OTBR_LOG_DEBUG, ret = EXIT_FAILURE); @@ -290,11 +280,8 @@ int main(int argc, char *argv[]) VerifyOrExit(ncp != nullptr, ret = EXIT_FAILURE); otbrLog(OTBR_LOG_INFO, "Thread interface %s", interfaceName); -#if OTBR_ENABLE_BACKBONE_ROUTER otbrLog(OTBR_LOG_INFO, "Backbone interface %s", backboneInterfaceName); -#endif - otbrLog(OTBR_LOG_INFO, "Backbone interface %s", - backboneInterfaceName == nullptr ? "(null)" : backboneInterfaceName); + if (!regionCode.empty()) { otbrLog(OTBR_LOG_INFO, "Region %s", regionCode.c_str()); @@ -305,9 +292,7 @@ int main(int argc, char *argv[]) otbr::AgentInstance instance(ncp); otbr::InstanceParams::Get().SetThreadIfName(interfaceName); -#if OTBR_ENABLE_BACKBONE_ROUTER otbr::InstanceParams::Get().SetBackboneIfName(backboneInterfaceName); -#endif SuccessOrExit(ret = instance.Init()); diff --git a/src/backbone_router/backbone_agent.hpp b/src/backbone_router/backbone_agent.hpp index 5fe22870938..7e2fb1e0719 100644 --- a/src/backbone_router/backbone_agent.hpp +++ b/src/backbone_router/backbone_agent.hpp @@ -119,11 +119,11 @@ class BackboneAgent Ip6Prefix mDomainPrefix; }; -#endif // OTBR_ENABLE_BACKBONE_ROUTER - /** * @} */ } // namespace BackboneRouter } // namespace otbr + +#endif // BACKBONE_ROUTER_BACKBONE_AGENT_HPP_ diff --git a/third_party/openthread/repo b/third_party/openthread/repo index 02f7dbb42be..d103d827ad5 160000 --- a/third_party/openthread/repo +++ b/third_party/openthread/repo @@ -1 +1 @@ -Subproject commit 02f7dbb42be7f75355436ec43bc82d0b2b4caad6 +Subproject commit d103d827ad5fa5e7142109d7821c386448b99452 From fc0149c576996ba7352e5fe1a88549e38d994680 Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Tue, 22 Dec 2020 00:48:39 +0800 Subject: [PATCH 041/175] [radio] pass full power map in command line args (#656) This allows the powermap to be dynamically reloaded when user sets the region. Also fixes the reset behavior of the region code. --- src/agent/main.cpp | 60 +++++++++++++++++++++---- src/agent/ncp.hpp | 12 +++-- src/agent/ncp_openthread.cpp | 62 +++++++++++++++++++++++--- src/agent/ncp_openthread.hpp | 12 ++++- src/dbus/server/dbus_thread_object.cpp | 2 +- tests/dbus/test-client | 11 ++++- 6 files changed, 135 insertions(+), 24 deletions(-) diff --git a/src/agent/main.cpp b/src/agent/main.cpp index a6bce8c77df..5324534d9d7 100644 --- a/src/agent/main.cpp +++ b/src/agent/main.cpp @@ -28,7 +28,9 @@ #include +#include #include +#include #include #include @@ -81,6 +83,7 @@ enum OTBR_OPT_SHORTMAX = 128, OTBR_OPT_RADIO_VERSION, OTBR_OPT_REGION, + OTBR_OPT_POWER_MAP, }; // Default poll timeout. @@ -94,6 +97,7 @@ static const struct option kOptions[] = { {"version", no_argument, nullptr, OTBR_OPT_VERSION}, {"radio-version", no_argument, nullptr, OTBR_OPT_RADIO_VERSION}, {"reg", required_argument, nullptr, OTBR_OPT_REGION}, + {"power-map", required_argument, nullptr, OTBR_OPT_POWER_MAP}, {0, 0, 0, 0}}; static void HandleSignal(int aSignal) @@ -101,6 +105,38 @@ static void HandleSignal(int aSignal) signal(aSignal, SIG_DFL); } +otbrError LoadPowerMap(const char *aFile, otbr::Ncp::PowerMap *aPowerMap) +{ + otbrError error = OTBR_ERROR_NONE; + std::ifstream fin(aFile); + std::string line; + + VerifyOrExit(fin, error = OTBR_ERROR_ERRNO); + while (std::getline(fin, line)) + { + std::istringstream lineStream(line); + std::string region; + std::vector powerTable; + + lineStream >> region; + if (!region.empty()) + { + int power; + while (lineStream >> power) + { + powerTable.push_back(power); + } + } + VerifyOrExit(powerTable.size() > 0 && + powerTable.size() <= OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX - OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN + 1, + error = OTBR_ERROR_PARSE); + aPowerMap->emplace(region, powerTable); + } + +exit: + return error; +} + static int Mainloop(otbr::AgentInstance &aInstance, const char *aInterfaceName) { int error = EXIT_FAILURE; @@ -219,8 +255,9 @@ int main(int argc, char *argv[]) const char * backboneInterfaceName = ""; otbr::Ncp::Controller * ncp = nullptr; otbr::Ncp::ControllerOpenThread *ncpOpenThread = nullptr; - bool verbose = false; - bool printRadioVersion = false; + otbr::Ncp::PowerMap powerMap; + bool verbose = false; + bool printRadioVersion = false; std::string regionCode; std::set_new_handler(OnAllocateFailed); @@ -264,6 +301,10 @@ int main(int argc, char *argv[]) regionCode = optarg; break; + case OTBR_OPT_POWER_MAP: + SuccessOrExit(LoadPowerMap(optarg, &powerMap)); + break; + default: PrintHelp(argv[0]); ExitNow(ret = EXIT_FAILURE); @@ -275,19 +316,14 @@ int main(int argc, char *argv[]) otbrLog(OTBR_LOG_INFO, "Running %s", OTBR_PACKAGE_VERSION); VerifyOrExit(optind < argc, ret = EXIT_FAILURE); - ncp = otbr::Ncp::Controller::Create(interfaceName, argv[optind], backboneInterfaceName); + ncp = + otbr::Ncp::Controller::Create(interfaceName, argv[optind], regionCode.c_str(), powerMap, backboneInterfaceName); ncpOpenThread = static_cast(ncp); VerifyOrExit(ncp != nullptr, ret = EXIT_FAILURE); otbrLog(OTBR_LOG_INFO, "Thread interface %s", interfaceName); otbrLog(OTBR_LOG_INFO, "Backbone interface %s", backboneInterfaceName); - if (!regionCode.empty()) - { - otbrLog(OTBR_LOG_INFO, "Region %s", regionCode.c_str()); - } - ncpOpenThread->SetRegionCode(regionCode); - { otbr::AgentInstance instance(ncp); @@ -296,6 +332,12 @@ int main(int argc, char *argv[]) SuccessOrExit(ret = instance.Init()); + if (!regionCode.empty()) + { + otbrLog(OTBR_LOG_INFO, "Region %s", regionCode.c_str()); + SuccessOrExit(ncpOpenThread->SetRegionCode(regionCode)); + } + if (printRadioVersion) { PrintRadioVersion(ncpOpenThread->GetInstance()); diff --git a/src/agent/ncp.hpp b/src/agent/ncp.hpp index 13a41470e57..8bf8abc1ada 100644 --- a/src/agent/ncp.hpp +++ b/src/agent/ncp.hpp @@ -73,6 +73,8 @@ enum kEventBackboneRouterNdProxyEvent, ///< Backbone Router ND Proxy event arrived. }; +using PowerMap = std::map>; + /** * This interface defines NCP Controller functionality. * @@ -136,12 +138,16 @@ class Controller : public EventEmitter * * @param[in] aInterfaceName A string of the NCP interface name. * @param[in] aRadioUrl The URL describes the radio chip. + * @param[in] aRegionCode The region code, empty string for not specified. + * @param[in] aPowerMap The power table for each region. * @param[in] aBackboneInterfaceName The Backbone network interface name. * */ - static Controller *Create(const char *aInterfaceName, - const char *aRadioUrl, - const char *aBackboneInterfaceName = nullptr); + static Controller *Create(const char * aInterfaceName, + const char * aRadioUrl, + const char * aRegionCode, + const PowerMap &aPowerMap, + const char * aBackboneInterfaceName = nullptr); /** * This method destroys a NCP Controller. diff --git a/src/agent/ncp_openthread.cpp b/src/agent/ncp_openthread.cpp index e09dcd8056e..22b294f4e3b 100644 --- a/src/agent/ncp_openthread.cpp +++ b/src/agent/ncp_openthread.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include "common/code_utils.hpp" @@ -65,10 +66,15 @@ const otCliCommand ControllerOpenThread::sRegionCommand = { &ControllerOpenThread::HandleRegionCommand, }; -ControllerOpenThread::ControllerOpenThread(const char *aInterfaceName, - const char *aRadioUrl, - const char *aBackboneInterfaceName) +ControllerOpenThread::ControllerOpenThread(const char * aInterfaceName, + const char * aRadioUrl, + const char * aRegionCode, + const PowerMap &aPowerMap, + const char * aBackboneInterfaceName) : mTriedAttach(false) + , mRegionCode(aRegionCode) + , mOriginalRegionCode(aRegionCode) + , mPowerMap(aPowerMap) { memset(&mConfig, 0, sizeof(mConfig)); @@ -134,6 +140,11 @@ otbrError ControllerOpenThread::Init(void) otBackboneRouterSetNdProxyCallback(mInstance, &ControllerOpenThread::HandleBackboneRouterNdProxyEvent, this); #endif + if (!mRegionCode.empty()) + { + VerifyOrExit(SetRegionCode(mRegionCode) == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD); + } + mThreadHelper = std::unique_ptr(new otbr::agent::ThreadHelper(mInstance, this)); otCliSetUserCommands(&sRegionCommand, 1, this); @@ -252,6 +263,7 @@ void ControllerOpenThread::Reset(void) otInstanceFinalize(mInstance); otSysDeinit(); + mRegionCode = mOriginalRegionCode; Init(); for (auto &handler : mResetHandlers) { @@ -329,6 +341,30 @@ void ControllerOpenThread::RegisterResetHandler(std::function aHandl mResetHandlers.emplace_back(std::move(aHandler)); } +otError ControllerOpenThread::SetRegionCode(const std::string &aCode) +{ + constexpr char kRegionWorldWide[] = "WW"; + std::string powerCode = aCode; + otError error = OT_ERROR_NONE; + + if (mPowerMap.find(aCode) == mPowerMap.end()) + { + otbrLog(OTBR_LOG_WARNING, "Cannot find %s in power map, use WW instead", aCode.c_str()); + powerCode = kRegionWorldWide; + } + VerifyOrExit(mPowerMap.find(powerCode) != mPowerMap.end(), error = OT_ERROR_NOT_FOUND); + mRegionCode = aCode; + + for (size_t i = 0, channel = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN; + i < mPowerMap[powerCode].size() && channel <= OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX; i++, channel++) + { + SuccessOrExit(error = otPlatRadioSetChannelMaxTransmitPower(mInstance, channel, mPowerMap[powerCode][i])); + } + +exit: + return error; +} + void ControllerOpenThread::HandleRegionCommand(void *aContext, uint8_t aArgLength, char **aArgs) { ControllerOpenThread *controller = static_cast(aContext); @@ -345,8 +381,16 @@ void ControllerOpenThread::HandleRegionCommand(uint8_t aArgLength, char **aArgs) { if (strnlen(aArgs[0], 3) == 2) { - mRegionCode = aArgs[0]; - otCliOutputFormat("Done\n"); + otError error = SetRegionCode(aArgs[0]); + + if (error != OT_ERROR_NONE) + { + otCliOutputFormat("Error%d: %s\n", error, otThreadErrorToString(error)); + } + else + { + otCliOutputFormat("Done\n"); + } } else { @@ -387,9 +431,13 @@ void ControllerOpenThread::HandleBackboneRouterNdProxyEvent(otBackboneRouterNdPr } #endif -Controller *Controller::Create(const char *aInterfaceName, const char *aRadioUrl, const char *aBackboneInterfaceName) +Controller *Controller::Create(const char * aInterfaceName, + const char * aRadioUrl, + const char * aRegionCode, + const PowerMap &aPowerMap, + const char * aBackboneInterfaceName) { - return new ControllerOpenThread(aInterfaceName, aRadioUrl, aBackboneInterfaceName); + return new ControllerOpenThread(aInterfaceName, aRadioUrl, aRegionCode, aPowerMap, aBackboneInterfaceName); } /* diff --git a/src/agent/ncp_openthread.hpp b/src/agent/ncp_openthread.hpp index 68b7fb2ce32..d178aab7d55 100644 --- a/src/agent/ncp_openthread.hpp +++ b/src/agent/ncp_openthread.hpp @@ -61,10 +61,16 @@ class ControllerOpenThread : public Controller * * @param[in] aInterfaceName A string of the NCP interface name. * @param[in] aRadioUrl The URL describes the radio chip. + * @param[in] aRegionCode The region code, empty string for not specified. + * @param[in] aPowerMap The power table for each region. * @param[in] aBackboneInterfaceName The Backbone network interface name. * */ - ControllerOpenThread(const char *aInterfaceName, const char *aRadioUrl, const char *aBackboneInterfaceName); + ControllerOpenThread(const char * aInterfaceName, + const char * aRadioUrl, + const char * aRegionCode, + const PowerMap &aPowerMap, + const char * aBackboneInterfaceName); /** * This method initalize the NCP controller. @@ -96,7 +102,7 @@ class ControllerOpenThread : public Controller * @param[in] aCode The region code. * */ - void SetRegionCode(const std::string &aCode) { mRegionCode = aCode; } + otError SetRegionCode(const std::string &aCode); /** * This method gets the region code. @@ -202,6 +208,8 @@ class ControllerOpenThread : public Controller bool mTriedAttach; std::vector> mResetHandlers; std::string mRegionCode; + std::string mOriginalRegionCode; + PowerMap mPowerMap; static const otCliCommand sRegionCommand; }; diff --git a/src/dbus/server/dbus_thread_object.cpp b/src/dbus/server/dbus_thread_object.cpp index 88e7f6b70c5..aa93db6286f 100644 --- a/src/dbus/server/dbus_thread_object.cpp +++ b/src/dbus/server/dbus_thread_object.cpp @@ -501,7 +501,7 @@ otError DBusThreadObject::SetRegionHandler(DBusMessageIter &aIter) otError error = OT_ERROR_NONE; VerifyOrExit(DBusMessageExtractFromVariant(&aIter, regionCode) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); - mNcp->SetRegionCode(regionCode); + error = mNcp->SetRegionCode(regionCode); exit: return error; diff --git a/tests/dbus/test-client b/tests/dbus/test-client index afb6a3561d0..19f2cbc5a4c 100755 --- a/tests/dbus/test-client +++ b/tests/dbus/test-client @@ -51,16 +51,23 @@ on_exit() main() { sudo rm -rf tmp + echo "US 20 20 20 20 20 20 20 20 20 20 20 20 20 20 18 127 +CA 20 20 20 20 20 20 20 20 20 20 20 20 20 20 18 127 +WW 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10" >/tmp/power_map sudo install -m 644 "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent.conf /etc/dbus-1/system.d/"${OTBR_DBUS_SERVER_CONF}" sudo service dbus reload sudo "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent -d7 -I wpan0 --radio-version "spinel+hdlc+forkpty://$(command -v ot-rcp)?forkpty-arg=1" | grep "OPENTHREAD" - sudo "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent --reg WW -d7 -I wpan0 "spinel+hdlc+forkpty://$(command -v ot-rcp)?forkpty-arg=1" & + sudo "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent --reg WW --power-map /tmp/power_map -d7 -I wpan0 "spinel+hdlc+forkpty://$(command -v ot-rcp)?forkpty-arg=1" & trap on_exit EXIT sleep 5 + sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl region | grep WW + sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl txpower 50 | grep Done + sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl txpower | grep 10 sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl region US | grep Done sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl region | grep US - sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl region WW | grep Done + sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl txpower | grep 20 sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl factoryreset + sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl region | grep WW sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \ --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \ org.freedesktop.DBus.Introspectable.Introspect | grep JoinerStart From 6f22cc2e80c4fe84a1574032d9ea67e571b3d87f Mon Sep 17 00:00:00 2001 From: kangping Date: Wed, 23 Dec 2020 14:59:44 +0800 Subject: [PATCH 042/175] [mbedtls] enable ECDSA support (#658) --- third_party/openthread/mbedtls-config.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/third_party/openthread/mbedtls-config.h b/third_party/openthread/mbedtls-config.h index 3ff6d3341bb..6b2bc5df3ed 100644 --- a/third_party/openthread/mbedtls-config.h +++ b/third_party/openthread/mbedtls-config.h @@ -70,6 +70,15 @@ #define MBEDTLS_SSL_SRV_C #define MBEDTLS_SSL_TLS_C +// Enable ECDSA support +#define MBEDTLS_BASE64_C +#define MBEDTLS_ECDH_C +#define MBEDTLS_ECDSA_C +#define MBEDTLS_ECDSA_DETERMINISTIC +#define MBEDTLS_OID_C +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_PK_WRITE_C + #define MBEDTLS_NET_C #define MBEDTLS_TIMING_C From 3730e59535df035cbecde033f7c5c485fc4c0fc2 Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Wed, 23 Dec 2020 15:00:52 +0800 Subject: [PATCH 043/175] [agent] remove region support (#657) The region support has been moved to OpenThread core. --- Android.mk | 1 - src/agent/main.cpp | 57 +--------------- src/agent/ncp.hpp | 10 +-- src/agent/ncp_openthread.cpp | 93 ++------------------------ src/agent/ncp_openthread.hpp | 33 +-------- src/agent/thread_helper.cpp | 7 +- src/common/CMakeLists.txt | 1 - src/common/region_code.cpp | 70 ------------------- src/common/region_code.hpp | 58 ---------------- src/dbus/client/thread_api_dbus.cpp | 10 --- src/dbus/client/thread_api_dbus.hpp | 22 ------ src/dbus/common/constants.hpp | 1 - src/dbus/server/dbus_thread_object.cpp | 33 +-------- src/dbus/server/dbus_thread_object.hpp | 2 - src/dbus/server/introspect.xml | 4 -- tests/dbus/test-client | 12 +--- tests/dbus/test_dbus_client.cpp | 14 ---- 17 files changed, 16 insertions(+), 412 deletions(-) delete mode 100644 src/common/region_code.cpp delete mode 100644 src/common/region_code.hpp diff --git a/Android.mk b/Android.mk index c1b3d5cf7b0..3cd4b01310c 100644 --- a/Android.mk +++ b/Android.mk @@ -98,7 +98,6 @@ LOCAL_SRC_FILES := \ src/agent/ncp_openthread.cpp \ src/agent/thread_helper.cpp \ src/common/logging.cpp \ - src/common/region_code.cpp \ src/dbus/common/dbus_message_dump.cpp \ src/dbus/common/dbus_message_helper.cpp \ src/dbus/common/dbus_message_helper_openthread.cpp \ diff --git a/src/agent/main.cpp b/src/agent/main.cpp index 5324534d9d7..de9456ec2e2 100644 --- a/src/agent/main.cpp +++ b/src/agent/main.cpp @@ -49,7 +49,6 @@ #include "agent/ncp_openthread.hpp" #include "common/code_utils.hpp" #include "common/logging.hpp" -#include "common/region_code.hpp" #include "common/types.hpp" #if OTBR_ENABLE_REST_SERVER #include "rest/rest_web_server.hpp" @@ -82,8 +81,6 @@ enum OTBR_OPT_VERSION = 'V', OTBR_OPT_SHORTMAX = 128, OTBR_OPT_RADIO_VERSION, - OTBR_OPT_REGION, - OTBR_OPT_POWER_MAP, }; // Default poll timeout. @@ -96,8 +93,6 @@ static const struct option kOptions[] = { {"verbose", no_argument, nullptr, OTBR_OPT_VERBOSE}, {"version", no_argument, nullptr, OTBR_OPT_VERSION}, {"radio-version", no_argument, nullptr, OTBR_OPT_RADIO_VERSION}, - {"reg", required_argument, nullptr, OTBR_OPT_REGION}, - {"power-map", required_argument, nullptr, OTBR_OPT_POWER_MAP}, {0, 0, 0, 0}}; static void HandleSignal(int aSignal) @@ -105,38 +100,6 @@ static void HandleSignal(int aSignal) signal(aSignal, SIG_DFL); } -otbrError LoadPowerMap(const char *aFile, otbr::Ncp::PowerMap *aPowerMap) -{ - otbrError error = OTBR_ERROR_NONE; - std::ifstream fin(aFile); - std::string line; - - VerifyOrExit(fin, error = OTBR_ERROR_ERRNO); - while (std::getline(fin, line)) - { - std::istringstream lineStream(line); - std::string region; - std::vector powerTable; - - lineStream >> region; - if (!region.empty()) - { - int power; - while (lineStream >> power) - { - powerTable.push_back(power); - } - } - VerifyOrExit(powerTable.size() > 0 && - powerTable.size() <= OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX - OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN + 1, - error = OTBR_ERROR_PARSE); - aPowerMap->emplace(region, powerTable); - } - -exit: - return error; -} - static int Mainloop(otbr::AgentInstance &aInstance, const char *aInterfaceName) { int error = EXIT_FAILURE; @@ -226,7 +189,7 @@ static int Mainloop(otbr::AgentInstance &aInstance, const char *aInterfaceName) static void PrintHelp(const char *aProgramName) { - fprintf(stderr, "Usage: %s [--reg region] [-I interfaceName] [-d DEBUG_LEVEL] [-v] RADIO_URL\n", aProgramName); + fprintf(stderr, "Usage: %s [-I interfaceName] [-d DEBUG_LEVEL] [-v] RADIO_URL\n", aProgramName); fprintf(stderr, "%s", otSysGetRadioUrlHelpString()); } @@ -258,7 +221,6 @@ int main(int argc, char *argv[]) otbr::Ncp::PowerMap powerMap; bool verbose = false; bool printRadioVersion = false; - std::string regionCode; std::set_new_handler(OnAllocateFailed); @@ -297,14 +259,6 @@ int main(int argc, char *argv[]) printRadioVersion = true; break; - case OTBR_OPT_REGION: - regionCode = optarg; - break; - - case OTBR_OPT_POWER_MAP: - SuccessOrExit(LoadPowerMap(optarg, &powerMap)); - break; - default: PrintHelp(argv[0]); ExitNow(ret = EXIT_FAILURE); @@ -316,8 +270,7 @@ int main(int argc, char *argv[]) otbrLog(OTBR_LOG_INFO, "Running %s", OTBR_PACKAGE_VERSION); VerifyOrExit(optind < argc, ret = EXIT_FAILURE); - ncp = - otbr::Ncp::Controller::Create(interfaceName, argv[optind], regionCode.c_str(), powerMap, backboneInterfaceName); + ncp = otbr::Ncp::Controller::Create(interfaceName, argv[optind], backboneInterfaceName); ncpOpenThread = static_cast(ncp); VerifyOrExit(ncp != nullptr, ret = EXIT_FAILURE); @@ -332,12 +285,6 @@ int main(int argc, char *argv[]) SuccessOrExit(ret = instance.Init()); - if (!regionCode.empty()) - { - otbrLog(OTBR_LOG_INFO, "Region %s", regionCode.c_str()); - SuccessOrExit(ncpOpenThread->SetRegionCode(regionCode)); - } - if (printRadioVersion) { PrintRadioVersion(ncpOpenThread->GetInstance()); diff --git a/src/agent/ncp.hpp b/src/agent/ncp.hpp index 8bf8abc1ada..aa62e5d1675 100644 --- a/src/agent/ncp.hpp +++ b/src/agent/ncp.hpp @@ -138,16 +138,12 @@ class Controller : public EventEmitter * * @param[in] aInterfaceName A string of the NCP interface name. * @param[in] aRadioUrl The URL describes the radio chip. - * @param[in] aRegionCode The region code, empty string for not specified. - * @param[in] aPowerMap The power table for each region. * @param[in] aBackboneInterfaceName The Backbone network interface name. * */ - static Controller *Create(const char * aInterfaceName, - const char * aRadioUrl, - const char * aRegionCode, - const PowerMap &aPowerMap, - const char * aBackboneInterfaceName = nullptr); + static Controller *Create(const char *aInterfaceName, + const char *aRadioUrl, + const char *aBackboneInterfaceName = nullptr); /** * This method destroys a NCP Controller. diff --git a/src/agent/ncp_openthread.cpp b/src/agent/ncp_openthread.cpp index 22b294f4e3b..4c2bec4d0cd 100644 --- a/src/agent/ncp_openthread.cpp +++ b/src/agent/ncp_openthread.cpp @@ -61,20 +61,10 @@ using std::chrono::steady_clock; namespace otbr { namespace Ncp { -const otCliCommand ControllerOpenThread::sRegionCommand = { - "region", - &ControllerOpenThread::HandleRegionCommand, -}; - -ControllerOpenThread::ControllerOpenThread(const char * aInterfaceName, - const char * aRadioUrl, - const char * aRegionCode, - const PowerMap &aPowerMap, - const char * aBackboneInterfaceName) +ControllerOpenThread::ControllerOpenThread(const char *aInterfaceName, + const char *aRadioUrl, + const char *aBackboneInterfaceName) : mTriedAttach(false) - , mRegionCode(aRegionCode) - , mOriginalRegionCode(aRegionCode) - , mPowerMap(aPowerMap) { memset(&mConfig, 0, sizeof(mConfig)); @@ -140,13 +130,7 @@ otbrError ControllerOpenThread::Init(void) otBackboneRouterSetNdProxyCallback(mInstance, &ControllerOpenThread::HandleBackboneRouterNdProxyEvent, this); #endif - if (!mRegionCode.empty()) - { - VerifyOrExit(SetRegionCode(mRegionCode) == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD); - } - mThreadHelper = std::unique_ptr(new otbr::agent::ThreadHelper(mInstance, this)); - otCliSetUserCommands(&sRegionCommand, 1, this); exit: return error; @@ -263,7 +247,6 @@ void ControllerOpenThread::Reset(void) otInstanceFinalize(mInstance); otSysDeinit(); - mRegionCode = mOriginalRegionCode; Init(); for (auto &handler : mResetHandlers) { @@ -341,68 +324,6 @@ void ControllerOpenThread::RegisterResetHandler(std::function aHandl mResetHandlers.emplace_back(std::move(aHandler)); } -otError ControllerOpenThread::SetRegionCode(const std::string &aCode) -{ - constexpr char kRegionWorldWide[] = "WW"; - std::string powerCode = aCode; - otError error = OT_ERROR_NONE; - - if (mPowerMap.find(aCode) == mPowerMap.end()) - { - otbrLog(OTBR_LOG_WARNING, "Cannot find %s in power map, use WW instead", aCode.c_str()); - powerCode = kRegionWorldWide; - } - VerifyOrExit(mPowerMap.find(powerCode) != mPowerMap.end(), error = OT_ERROR_NOT_FOUND); - mRegionCode = aCode; - - for (size_t i = 0, channel = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN; - i < mPowerMap[powerCode].size() && channel <= OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX; i++, channel++) - { - SuccessOrExit(error = otPlatRadioSetChannelMaxTransmitPower(mInstance, channel, mPowerMap[powerCode][i])); - } - -exit: - return error; -} - -void ControllerOpenThread::HandleRegionCommand(void *aContext, uint8_t aArgLength, char **aArgs) -{ - ControllerOpenThread *controller = static_cast(aContext); - controller->HandleRegionCommand(aArgLength, aArgs); -} - -void ControllerOpenThread::HandleRegionCommand(uint8_t aArgLength, char **aArgs) -{ - if (aArgLength == 0) - { - otCliOutputFormat("%s\nDone\n", mRegionCode.c_str()); - } - else if (aArgLength == 1) - { - if (strnlen(aArgs[0], 3) == 2) - { - otError error = SetRegionCode(aArgs[0]); - - if (error != OT_ERROR_NONE) - { - otCliOutputFormat("Error%d: %s\n", error, otThreadErrorToString(error)); - } - else - { - otCliOutputFormat("Done\n"); - } - } - else - { - otCliOutputFormat("Error: InvalidArgs\n"); - } - } - else - { - otCliOutputFormat("Error: InvalidArgs\n"); - } -} - #if OTBR_ENABLE_BACKBONE_ROUTER void ControllerOpenThread::HandleBackboneRouterDomainPrefixEvent(void * aContext, otBackboneRouterDomainPrefixEvent aEvent, @@ -431,13 +352,9 @@ void ControllerOpenThread::HandleBackboneRouterNdProxyEvent(otBackboneRouterNdPr } #endif -Controller *Controller::Create(const char * aInterfaceName, - const char * aRadioUrl, - const char * aRegionCode, - const PowerMap &aPowerMap, - const char * aBackboneInterfaceName) +Controller *Controller::Create(const char *aInterfaceName, const char *aRadioUrl, const char *aBackboneInterfaceName) { - return new ControllerOpenThread(aInterfaceName, aRadioUrl, aRegionCode, aPowerMap, aBackboneInterfaceName); + return new ControllerOpenThread(aInterfaceName, aRadioUrl, aBackboneInterfaceName); } /* diff --git a/src/agent/ncp_openthread.hpp b/src/agent/ncp_openthread.hpp index d178aab7d55..59f8a5e94dc 100644 --- a/src/agent/ncp_openthread.hpp +++ b/src/agent/ncp_openthread.hpp @@ -44,7 +44,6 @@ #include "ncp.hpp" #include "agent/thread_helper.hpp" -#include "common/region_code.hpp" namespace otbr { namespace Ncp { @@ -61,16 +60,10 @@ class ControllerOpenThread : public Controller * * @param[in] aInterfaceName A string of the NCP interface name. * @param[in] aRadioUrl The URL describes the radio chip. - * @param[in] aRegionCode The region code, empty string for not specified. - * @param[in] aPowerMap The power table for each region. * @param[in] aBackboneInterfaceName The Backbone network interface name. * */ - ControllerOpenThread(const char * aInterfaceName, - const char * aRadioUrl, - const char * aRegionCode, - const PowerMap &aPowerMap, - const char * aBackboneInterfaceName); + ControllerOpenThread(const char *aInterfaceName, const char *aRadioUrl, const char *aBackboneInterfaceName); /** * This method initalize the NCP controller. @@ -96,22 +89,6 @@ class ControllerOpenThread : public Controller */ otbr::agent::ThreadHelper *GetThreadHelper(void) { return mThreadHelper.get(); } - /** - * This method sets the region code. - * - * @param[in] aCode The region code. - * - */ - otError SetRegionCode(const std::string &aCode); - - /** - * This method gets the region code. - * - * @retval The region code. - * - */ - std::string GetRegionCode(void) { return mRegionCode; } - /** * This method updates the fd_set to poll. * @@ -197,9 +174,6 @@ class ControllerOpenThread : public Controller void HandleBackboneRouterMulticastListenerEvent(otBackboneRouterMulticastListenerEvent aEvent, const otIp6Address * aAddress); - static void HandleRegionCommand(void *aContext, uint8_t aArgLength, char **aArgs); - void HandleRegionCommand(uint8_t aArgLength, char **aArgs); - otInstance *mInstance; otPlatformConfig mConfig; @@ -207,11 +181,6 @@ class ControllerOpenThread : public Controller std::multimap> mTimers; bool mTriedAttach; std::vector> mResetHandlers; - std::string mRegionCode; - std::string mOriginalRegionCode; - PowerMap mPowerMap; - - static const otCliCommand sRegionCommand; }; } // namespace Ncp diff --git a/src/agent/thread_helper.cpp b/src/agent/thread_helper.cpp index a87414af4a2..c7c2cb293ee 100644 --- a/src/agent/thread_helper.cpp +++ b/src/agent/thread_helper.cpp @@ -45,7 +45,6 @@ #include "common/byteswap.hpp" #include "common/code_utils.hpp" #include "common/logging.hpp" -#include "common/region_code.hpp" namespace otbr { namespace agent { @@ -187,8 +186,6 @@ void ThreadHelper::Attach(const std::string & aNetworkName, otExtendedPanId extPanId; otMasterKey masterKey; otPskc pskc; - uint32_t preferredChannelMask = GetPreferredChannelMaskForRegion(mNcp->GetRegionCode()); - uint32_t supportedChannelMask = GetSupportedChannelMaskForRegion(mNcp->GetRegionCode()); uint32_t channelMask; uint8_t channel; @@ -246,11 +243,11 @@ void ThreadHelper::Attach(const std::string & aNetworkName, SuccessOrExit(error = otThreadSetExtendedPanId(mInstance, &extPanId)); SuccessOrExit(error = otThreadSetMasterKey(mInstance, &masterKey)); - channelMask = otLinkGetSupportedChannelMask(mInstance) & preferredChannelMask & aChannelMask; + channelMask = otPlatRadioGetPreferredChannelMask(mInstance) & aChannelMask; if (channelMask == 0) { - channelMask = otLinkGetSupportedChannelMask(mInstance) & supportedChannelMask & aChannelMask; + channelMask = otLinkGetSupportedChannelMask(mInstance) & aChannelMask; } VerifyOrExit(channelMask != 0, otbrLog(OTBR_LOG_WARNING, "Invalid channel mask"), error = OT_ERROR_INVALID_ARGS); diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 21c0e2e1c30..9b9072d411d 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -29,7 +29,6 @@ add_library(otbr-common logging.cpp types.cpp - region_code.cpp ) target_link_libraries(otbr-common diff --git a/src/common/region_code.cpp b/src/common/region_code.cpp deleted file mode 100644 index 28a2c4cc942..00000000000 --- a/src/common/region_code.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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. - */ - -#include "region_code.hpp" - -namespace { - -constexpr uint32_t kChannelMask11To24 = 0x1fff800; -constexpr uint32_t kChannelMask11To25 = 0x3fff800; -constexpr uint32_t kChannelMask11To26 = 0x7fff800; - -constexpr char kRegionCodeUS[] = "US"; -constexpr char kRegionCodeCA[] = "CA"; - -} // namespace - -namespace otbr { - -uint32_t GetSupportedChannelMaskForRegion(const std::string &aRegionCode) -{ - uint32_t mask = kChannelMask11To26; - - // US or CA - if (aRegionCode == kRegionCodeUS || aRegionCode == kRegionCodeCA) - { - mask = kChannelMask11To25; - } - - return mask; -} - -uint32_t GetPreferredChannelMaskForRegion(const std::string &aRegionCode) -{ - uint32_t mask = kChannelMask11To26; - - // US or CA - if (aRegionCode == kRegionCodeUS || aRegionCode == kRegionCodeCA) - { - mask = kChannelMask11To24; - } - - return mask; -} - -} // namespace otbr diff --git a/src/common/region_code.hpp b/src/common/region_code.hpp deleted file mode 100644 index 3073e92a0bc..00000000000 --- a/src/common/region_code.hpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ - -#ifndef OTBR_COMMON_REGION_CODE_HPP_ -#define OTBR_COMMON_REGION_CODE_HPP_ - -#include - -namespace otbr { - -/** - * This method returns the supported channel mask for a region code. - * - * - * @param[in] aRegionCode The region code. - * @returns The supported channel mask. - * - */ -uint32_t GetSupportedChannelMaskForRegion(const std::string &aRegionCode); - -/** - * This method returns the preferred channel mask for a region code. - * - * @param[in] aRegionCode The region code. - * - * @returns The preferred channel mask. - * - */ -uint32_t GetPreferredChannelMaskForRegion(const std::string &aRegionCode); - -} // namespace otbr - -#endif // OTBR_COMMON_REGION_CODE_HPP_ diff --git a/src/dbus/client/thread_api_dbus.cpp b/src/dbus/client/thread_api_dbus.cpp index 3ca3ec0c20c..80f8c3df7b6 100644 --- a/src/dbus/client/thread_api_dbus.cpp +++ b/src/dbus/client/thread_api_dbus.cpp @@ -374,11 +374,6 @@ ClientError ThreadApiDBus::SetLinkMode(const LinkModeConfig &aConfig) return SetProperty(OTBR_DBUS_PROPERTY_LINK_MODE, aConfig); } -ClientError ThreadApiDBus::SetRegion(const std::string &aRegion) -{ - return SetProperty(OTBR_DBUS_PROPERTY_REGION, aRegion); -} - ClientError ThreadApiDBus::GetLinkMode(LinkModeConfig &aConfig) { return GetProperty(OTBR_DBUS_PROPERTY_LINK_MODE, aConfig); @@ -515,11 +510,6 @@ ClientError ThreadApiDBus::GetExternalRoutes(std::vector &aExtern return GetProperty(OTBR_DBUS_PROPERTY_EXTERNAL_ROUTES, aExternalRoutes); } -ClientError ThreadApiDBus::GetRegion(std::string &aRegion) -{ - return GetProperty(OTBR_DBUS_PROPERTY_REGION, aRegion); -} - std::string ThreadApiDBus::GetInterfaceName(void) { return mInterfaceName; diff --git a/src/dbus/client/thread_api_dbus.hpp b/src/dbus/client/thread_api_dbus.hpp index fa9c2e53595..665d3b07cb7 100644 --- a/src/dbus/client/thread_api_dbus.hpp +++ b/src/dbus/client/thread_api_dbus.hpp @@ -267,17 +267,6 @@ class ThreadApiDBus */ ClientError SetLinkMode(const LinkModeConfig &aConfig); - /** - * This method sets the region. - * - * @param[in] aRegion The region, can be CA, US or WW. - * - * @retval ERROR_NONE successfully performed the dbus function call - * @retval ERROR_DBUS dbus encode/decode error - * - */ - ClientError SetRegion(const std::string &aRegion); - /** * This method gets the link operating mode. * @@ -591,17 +580,6 @@ class ThreadApiDBus */ ClientError GetExternalRoutes(std::vector &aExternalRoutes); - /** - * This method gets the region. - * - * @param[out] aRegion The region, can be CA, US or WW. - * - * @retval ERROR_NONE successfully performed the dbus function call - * @retval ERROR_DBUS dbus encode/decode error - * - */ - ClientError GetRegion(std::string &aRegion); - /** * This method returns the network interface name the client is bound to. * diff --git a/src/dbus/common/constants.hpp b/src/dbus/common/constants.hpp index ec0d1d0f58a..8a254a94aba 100644 --- a/src/dbus/common/constants.hpp +++ b/src/dbus/common/constants.hpp @@ -79,7 +79,6 @@ #define OTBR_DBUS_PROPERTY_INSTANT_RSSI "InstantRssi" #define OTBR_DBUS_PROPERTY_RADIO_TX_POWER "RadioTxPower" #define OTBR_DBUS_PROPERTY_EXTERNAL_ROUTES "ExternalRoutes" -#define OTBR_DBUS_PROPERTY_REGION "Region" #define OTBR_ROLE_NAME_DISABLED "disabled" #define OTBR_ROLE_NAME_DETACHED "detached" diff --git a/src/dbus/server/dbus_thread_object.cpp b/src/dbus/server/dbus_thread_object.cpp index aa93db6286f..f5d51dc6e7f 100644 --- a/src/dbus/server/dbus_thread_object.cpp +++ b/src/dbus/server/dbus_thread_object.cpp @@ -40,7 +40,6 @@ #include #include "common/byteswap.hpp" -#include "common/region_code.hpp" #include "dbus/common/constants.hpp" #include "dbus/server/dbus_agent.hpp" #include "dbus/server/dbus_thread_object.hpp" @@ -140,8 +139,6 @@ otbrError DBusThreadObject::Init(void) std::bind(&DBusThreadObject::SetLegacyUlaPrefixHandler, this, _1)); RegisterSetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_LINK_MODE, std::bind(&DBusThreadObject::SetLinkModeHandler, this, _1)); - RegisterSetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_REGION, - std::bind(&DBusThreadObject::SetRegionHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_LINK_MODE, std::bind(&DBusThreadObject::GetLinkModeHandler, this, _1)); @@ -196,8 +193,6 @@ otbrError DBusThreadObject::Init(void) std::bind(&DBusThreadObject::GetRadioTxPowerHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_EXTERNAL_ROUTES, std::bind(&DBusThreadObject::GetExternalRoutesHandler, this, _1)); - RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_REGION, - std::bind(&DBusThreadObject::GetRegionHandler, this, _1)); return error; } @@ -495,18 +490,6 @@ otError DBusThreadObject::SetLinkModeHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::SetRegionHandler(DBusMessageIter &aIter) -{ - std::string regionCode; - otError error = OT_ERROR_NONE; - - VerifyOrExit(DBusMessageExtractFromVariant(&aIter, regionCode) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); - error = mNcp->SetRegionCode(regionCode); - -exit: - return error; -} - otError DBusThreadObject::GetLinkModeHandler(DBusMessageIter &aIter) { auto threadHelper = mNcp->GetThreadHelper(); @@ -680,9 +663,8 @@ otError DBusThreadObject::GetIp6CountersHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetSupportedChannelMaskHandler(DBusMessageIter &aIter) { auto threadHelper = mNcp->GetThreadHelper(); - uint32_t channelMask = otLinkGetSupportedChannelMask(threadHelper->GetInstance()) & - GetSupportedChannelMaskForRegion(mNcp->GetRegionCode()); - otError error = OT_ERROR_NONE; + uint32_t channelMask = otLinkGetSupportedChannelMask(threadHelper->GetInstance()); + otError error = OT_ERROR_NONE; VerifyOrExit(DBusMessageEncodeToVariant(&aIter, channelMask) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); @@ -979,16 +961,5 @@ otError DBusThreadObject::GetExternalRoutesHandler(DBusMessageIter &aIter) return error; } -otError DBusThreadObject::GetRegionHandler(DBusMessageIter &aIter) -{ - otError error = OT_ERROR_NONE; - std::string regionName(mNcp->GetRegionCode()); - - VerifyOrExit(DBusMessageEncodeToVariant(&aIter, regionName) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); - -exit: - return error; -} - } // namespace DBus } // namespace otbr diff --git a/src/dbus/server/dbus_thread_object.hpp b/src/dbus/server/dbus_thread_object.hpp index 4d7364f98db..4893935b4da 100644 --- a/src/dbus/server/dbus_thread_object.hpp +++ b/src/dbus/server/dbus_thread_object.hpp @@ -86,7 +86,6 @@ class DBusThreadObject : public DBusObject otError SetMeshLocalPrefixHandler(DBusMessageIter &aIter); otError SetLegacyUlaPrefixHandler(DBusMessageIter &aIter); otError SetLinkModeHandler(DBusMessageIter &aIter); - otError SetRegionHandler(DBusMessageIter &aIter); otError GetLinkModeHandler(DBusMessageIter &aIter); otError GetDeviceRoleHandler(DBusMessageIter &aIter); @@ -114,7 +113,6 @@ class DBusThreadObject : public DBusObject otError GetInstantRssiHandler(DBusMessageIter &aIter); otError GetRadioTxPowerHandler(DBusMessageIter &aIter); otError GetExternalRoutesHandler(DBusMessageIter &aIter); - otError GetRegionHandler(DBusMessageIter &aIter); void ReplyScanResult(DBusRequest &aRequest, otError aError, const std::vector &aResult); diff --git a/src/dbus/server/introspect.xml b/src/dbus/server/introspect.xml index 0fc7b7dd902..0850c5f9270 100644 --- a/src/dbus/server/introspect.xml +++ b/src/dbus/server/introspect.xml @@ -334,10 +334,6 @@ - - - - diff --git a/tests/dbus/test-client b/tests/dbus/test-client index 19f2cbc5a4c..2026c049572 100755 --- a/tests/dbus/test-client +++ b/tests/dbus/test-client @@ -51,23 +51,13 @@ on_exit() main() { sudo rm -rf tmp - echo "US 20 20 20 20 20 20 20 20 20 20 20 20 20 20 18 127 -CA 20 20 20 20 20 20 20 20 20 20 20 20 20 20 18 127 -WW 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10" >/tmp/power_map sudo install -m 644 "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent.conf /etc/dbus-1/system.d/"${OTBR_DBUS_SERVER_CONF}" sudo service dbus reload sudo "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent -d7 -I wpan0 --radio-version "spinel+hdlc+forkpty://$(command -v ot-rcp)?forkpty-arg=1" | grep "OPENTHREAD" - sudo "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent --reg WW --power-map /tmp/power_map -d7 -I wpan0 "spinel+hdlc+forkpty://$(command -v ot-rcp)?forkpty-arg=1" & + sudo "${CMAKE_BINARY_DIR}"/src/agent/otbr-agent -d7 -I wpan0 "spinel+hdlc+forkpty://$(command -v ot-rcp)?forkpty-arg=1" & trap on_exit EXIT sleep 5 - sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl region | grep WW - sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl txpower 50 | grep Done - sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl txpower | grep 10 - sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl region US | grep Done - sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl region | grep US - sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl txpower | grep 20 sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl factoryreset - sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl region | grep WW sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \ --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \ org.freedesktop.DBus.Introspectable.Introspect | grep JoinerStart diff --git a/tests/dbus/test_dbus_client.cpp b/tests/dbus/test_dbus_client.cpp index 06f04a52a34..deb324a7922 100644 --- a/tests/dbus/test_dbus_client.cpp +++ b/tests/dbus/test_dbus_client.cpp @@ -117,8 +117,6 @@ int main() std::vector masterKey = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; uint16_t channel = 11; - std::string region; - uint32_t channelMask; for (auto &&result : aResult) { @@ -132,18 +130,6 @@ int main() cfg.mDeviceType = true; api->SetLinkMode(cfg); - api->SetRegion("US"); - api->GetRegion(region); - TEST_ASSERT(region == "US"); - api->GetSupportedChannelMask(channelMask); - TEST_ASSERT((channelMask & (1 << 26)) == 0); - - api->SetRegion("WW"); - api->GetRegion(region); - TEST_ASSERT(region == "WW"); - api->GetSupportedChannelMask(channelMask); - TEST_ASSERT((channelMask & (1 << 26)) != 0); - api->Attach("Test", 0x3456, extpanid, masterKey, {}, 1 << channel, [&api, channel, extpanid](ClientError aError) { printf("Attach result %d\n", static_cast(aError)); From 9c3824a841be5260043357fb111a54e593d0d711 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Thu, 24 Dec 2020 00:38:46 +0800 Subject: [PATCH 044/175] [openthread] update to include #5911 (#659) --- third_party/openthread/repo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/openthread/repo b/third_party/openthread/repo index d103d827ad5..01d169ad876 160000 --- a/third_party/openthread/repo +++ b/third_party/openthread/repo @@ -1 +1 @@ -Subproject commit d103d827ad5fa5e7142109d7821c386448b99452 +Subproject commit 01d169ad876583e7ff45307156dd01d1689748bb From 5d4b3dcf456f91822b4842b669db352c4832b9fa Mon Sep 17 00:00:00 2001 From: kangping Date: Tue, 29 Dec 2020 02:39:02 +0800 Subject: [PATCH 045/175] [utils] use keyword "override" for virtual methods (#665) --- src/mdns/mdns_avahi.hpp | 18 +++++++++++------- src/mdns/mdns_mdnssd.hpp | 18 +++++++++++------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/mdns/mdns_avahi.hpp b/src/mdns/mdns_avahi.hpp index 19b53c35bb9..09b13602982 100644 --- a/src/mdns/mdns_avahi.hpp +++ b/src/mdns/mdns_avahi.hpp @@ -203,7 +203,7 @@ class PublisherAvahi : public Publisher */ PublisherAvahi(int aProtocol, const char *aHost, const char *aDomain, StateHandler aHandler, void *aContext); - ~PublisherAvahi(void); + ~PublisherAvahi(void) override; /** * This method publishes or updates a service. @@ -220,7 +220,7 @@ class PublisherAvahi : public Publisher * @retval OTBR_ERROR_ERRNO Failed to publish or update the service. * */ - otbrError PublishService(uint16_t aPort, const char *aName, const char *aType, ...); + otbrError PublishService(uint16_t aPort, const char *aName, const char *aType, ...) override; /** * This method starts the MDNS service. @@ -229,7 +229,7 @@ class PublisherAvahi : public Publisher * @retval OTBR_ERROR_MDNS Failed to start MDNS service. * */ - otbrError Start(void); + otbrError Start(void) override; /** * This method checks if publisher has been started. @@ -238,13 +238,13 @@ class PublisherAvahi : public Publisher * @retval false Not started. * */ - bool IsStarted(void) const; + bool IsStarted(void) const override; /** * This method stops the MDNS service. * */ - void Stop(void); + void Stop(void) override; /** * This method performs avahi poll processing. @@ -254,7 +254,7 @@ class PublisherAvahi : public Publisher * @param[in] aErrorFdSet A reference to error file descriptors. * */ - void Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet, const fd_set &aErrorFdSet); + void Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet, const fd_set &aErrorFdSet) override; /** * This method updates the fd_set and timeout for mainloop. @@ -266,7 +266,11 @@ class PublisherAvahi : public Publisher * @param[inout] aTimeout A reference to the timeout. * */ - void UpdateFdSet(fd_set &aReadFdSet, fd_set &aWriteFdSet, fd_set &aErrorFdSet, int &aMaxFd, timeval &aTimeout); + void UpdateFdSet(fd_set & aReadFdSet, + fd_set & aWriteFdSet, + fd_set & aErrorFdSet, + int & aMaxFd, + timeval &aTimeout) override; private: enum diff --git a/src/mdns/mdns_mdnssd.hpp b/src/mdns/mdns_mdnssd.hpp index aba49073999..ad0f9da88d3 100644 --- a/src/mdns/mdns_mdnssd.hpp +++ b/src/mdns/mdns_mdnssd.hpp @@ -65,7 +65,7 @@ class PublisherMDnsSd : public Publisher */ PublisherMDnsSd(int aProtocol, const char *aHost, const char *aDomain, StateHandler aHandler, void *aContext); - ~PublisherMDnsSd(void); + ~PublisherMDnsSd(void) override; /** * This method publishes or updates a service. @@ -82,7 +82,7 @@ class PublisherMDnsSd : public Publisher * @retval OTBR_ERROR_ERRNO Failed to publish or update the service. * */ - otbrError PublishService(uint16_t aPort, const char *aName, const char *aType, ...); + otbrError PublishService(uint16_t aPort, const char *aName, const char *aType, ...) override; /** * This method starts the MDNS service. @@ -91,7 +91,7 @@ class PublisherMDnsSd : public Publisher * @retval OTBR_ERROR_MDNS Failed to start MDNS service. * */ - otbrError Start(void); + otbrError Start(void) override; /** * This method checks if publisher has been started. @@ -100,13 +100,13 @@ class PublisherMDnsSd : public Publisher * @retval false Not started. * */ - bool IsStarted(void) const; + bool IsStarted(void) const override; /** * This method stops the MDNS service. * */ - void Stop(void); + void Stop(void) override; /** * This method performs avahi poll processing. @@ -116,7 +116,7 @@ class PublisherMDnsSd : public Publisher * @param[in] aErrorFdSet A reference to error file descriptors. * */ - void Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet, const fd_set &aErrorFdSet); + void Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet, const fd_set &aErrorFdSet) override; /** * This method updates the fd_set and timeout for mainloop. @@ -128,7 +128,11 @@ class PublisherMDnsSd : public Publisher * @param[inout] aTimeout A reference to the timeout. * */ - void UpdateFdSet(fd_set &aReadFdSet, fd_set &aWriteFdSet, fd_set &aErrorFdSet, int &aMaxFd, timeval &aTimeout); + void UpdateFdSet(fd_set & aReadFdSet, + fd_set & aWriteFdSet, + fd_set & aErrorFdSet, + int & aMaxFd, + timeval &aTimeout) override; private: void DiscardService(const char *aName, const char *aType, DNSServiceRef aServiceRef); From b43370e67ff9312e6ff22a55a9b5785dc463f764 Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Tue, 29 Dec 2020 03:16:41 +0800 Subject: [PATCH 046/175] [dbus] add active dataset api (#662) This change allows users to get and set the active dataset via the dbus api. It also adds an `Attach` interface to allow users to start the Thread network without specifying network parameters. --- src/agent/thread_helper.cpp | 24 ++++++++++++++ src/agent/thread_helper.hpp | 11 +++++++ src/dbus/client/thread_api_dbus.cpp | 34 +++++++++++++++++++ src/dbus/client/thread_api_dbus.hpp | 39 ++++++++++++++++++++++ src/dbus/common/constants.hpp | 1 + src/dbus/common/dbus_message_helper.cpp | 11 +++++++ src/dbus/common/dbus_message_helper.hpp | 2 ++ src/dbus/server/dbus_thread_object.cpp | 43 ++++++++++++++++++++++++- src/dbus/server/dbus_thread_object.hpp | 2 ++ src/dbus/server/introspect.xml | 7 ++++ tests/dbus/test_dbus_client.cpp | 15 +++++++-- 11 files changed, 186 insertions(+), 3 deletions(-) diff --git a/src/agent/thread_helper.cpp b/src/agent/thread_helper.cpp index c7c2cb293ee..090e9cf6bdd 100644 --- a/src/agent/thread_helper.cpp +++ b/src/agent/thread_helper.cpp @@ -268,6 +268,30 @@ void ThreadHelper::Attach(const std::string & aNetworkName, } } +void ThreadHelper::Attach(ResultHandler aHandler) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(mAttachHandler == nullptr && mJoinerHandler == nullptr, error = OT_ERROR_INVALID_STATE); + mAttachHandler = aHandler; + + if (!otIp6IsEnabled(mInstance)) + { + SuccessOrExit(error = otIp6SetEnabled(mInstance, true)); + } + SuccessOrExit(error = otThreadSetEnabled(mInstance, true)); + +exit: + if (error != OT_ERROR_NONE) + { + if (aHandler) + { + aHandler(error); + } + mAttachHandler = nullptr; + } +} + otError ThreadHelper::Reset(void) { mDeviceRoleHandlers.clear(); diff --git a/src/agent/thread_helper.hpp b/src/agent/thread_helper.hpp index e3bf9565bdb..f503a99d496 100644 --- a/src/agent/thread_helper.hpp +++ b/src/agent/thread_helper.hpp @@ -119,6 +119,17 @@ class ThreadHelper uint32_t aChannelMask, ResultHandler aHandler); + /** + * This method attaches the device to the Thread network. + * + * @note The joiner start and the attach proccesses are exclusive, and the + * network parameter will be set through the active dataset. + * + * @param[in] aHandler The attach result handler. + * + */ + void Attach(ResultHandler aHandler); + /** * This method resets the OpenThread stack. * diff --git a/src/dbus/client/thread_api_dbus.cpp b/src/dbus/client/thread_api_dbus.cpp index 80f8c3df7b6..c8bf8806825 100644 --- a/src/dbus/client/thread_api_dbus.cpp +++ b/src/dbus/client/thread_api_dbus.cpp @@ -228,6 +228,30 @@ ClientError ThreadApiDBus::Attach(const std::string & aNetworkName, return error; } +ClientError ThreadApiDBus::Attach(const OtResultHandler &aHandler) +{ + ClientError error = ClientError::ERROR_NONE; + + VerifyOrExit(mAttachHandler == nullptr && mJoinerHandler == nullptr, error = ClientError::OT_ERROR_INVALID_STATE); + mAttachHandler = aHandler; + + if (aHandler) + { + error = CallDBusMethodAsync(OTBR_DBUS_ATTACH_METHOD, + &ThreadApiDBus::sHandleDBusPendingCall<&ThreadApiDBus::AttachPendingCallHandler>); + } + else + { + error = CallDBusMethodSync(OTBR_DBUS_ATTACH_METHOD); + } + if (error != ClientError::ERROR_NONE) + { + mAttachHandler = nullptr; + } +exit: + return error; +} + void ThreadApiDBus::AttachPendingCallHandler(DBusPendingCall *aPending) { ClientError ret = ClientError::OT_ERROR_FAILED; @@ -369,6 +393,11 @@ ClientError ThreadApiDBus::SetLegacyUlaPrefix(const std::array &aDataset) +{ + return SetProperty(OTBR_DBUS_PROPERTY_ACTIVE_DATASET_TLVS, aDataset); +} + ClientError ThreadApiDBus::SetLinkMode(const LinkModeConfig &aConfig) { return SetProperty(OTBR_DBUS_PROPERTY_LINK_MODE, aConfig); @@ -510,6 +539,11 @@ ClientError ThreadApiDBus::GetExternalRoutes(std::vector &aExtern return GetProperty(OTBR_DBUS_PROPERTY_EXTERNAL_ROUTES, aExternalRoutes); } +ClientError ThreadApiDBus::GetActiveDatasetTlvs(std::vector &aDataset) +{ + return GetProperty(OTBR_DBUS_PROPERTY_ACTIVE_DATASET_TLVS, aDataset); +} + std::string ThreadApiDBus::GetInterfaceName(void) { return mInterfaceName; diff --git a/src/dbus/client/thread_api_dbus.hpp b/src/dbus/client/thread_api_dbus.hpp index 665d3b07cb7..4dfc65e636e 100644 --- a/src/dbus/client/thread_api_dbus.hpp +++ b/src/dbus/client/thread_api_dbus.hpp @@ -125,6 +125,21 @@ class ThreadApiDBus uint32_t aChannelMask, const OtResultHandler & aHandler); + /** + * This method attaches the device to the Thread network. + * + * The network parameters will be set with the active dataset under this + * circumstance. + * + * @param[in] aHandler The attach result handler. + * + * @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); + /** * This method performs a factory reset. * @@ -255,6 +270,18 @@ class ThreadApiDBus */ ClientError SetLegacyUlaPrefix(const std::array &aPrefix); + /** + * This method sets the active operational dataset. + * + * @param[out] aDataset The active operational dataset + * + * @retval ERROR_NONE successfully performed the dbus function call + * @retval ERROR_DBUS dbus encode/decode error + * @retval ... OpenThread defined error value otherwise + * + */ + ClientError SetActiveDatasetTlvs(const std::vector &aDataset); + /** * This method sets the link operating mode. * @@ -580,6 +607,18 @@ class ThreadApiDBus */ ClientError GetExternalRoutes(std::vector &aExternalRoutes); + /** + * This method gets the active operational dataset + * + * @param[out] aDataset The active operational dataset + * + * @retval ERROR_NONE successfully performed the dbus function call + * @retval ERROR_DBUS dbus encode/decode error + * @retval ... OpenThread defined error value otherwise + * + */ + ClientError GetActiveDatasetTlvs(std::vector &aDataset); + /** * This method returns the network interface name the client is bound to. * diff --git a/src/dbus/common/constants.hpp b/src/dbus/common/constants.hpp index 8a254a94aba..2de929338e0 100644 --- a/src/dbus/common/constants.hpp +++ b/src/dbus/common/constants.hpp @@ -79,6 +79,7 @@ #define OTBR_DBUS_PROPERTY_INSTANT_RSSI "InstantRssi" #define OTBR_DBUS_PROPERTY_RADIO_TX_POWER "RadioTxPower" #define OTBR_DBUS_PROPERTY_EXTERNAL_ROUTES "ExternalRoutes" +#define OTBR_DBUS_PROPERTY_ACTIVE_DATASET_TLVS "ActiveDatasetTlvs" #define OTBR_ROLE_NAME_DISABLED "disabled" #define OTBR_ROLE_NAME_DETACHED "detached" diff --git a/src/dbus/common/dbus_message_helper.cpp b/src/dbus/common/dbus_message_helper.cpp index 7474f23ed40..dbf7a0cd54e 100644 --- a/src/dbus/common/dbus_message_helper.cpp +++ b/src/dbus/common/dbus_message_helper.cpp @@ -177,5 +177,16 @@ otbrError DBusMessageEncode(DBusMessageIter *aIter, const std::vector & return DBusMessageEncodePrimitive(aIter, aValue); } +bool IsDBusMessageEmpty(DBusMessage &aMessage) +{ + DBusMessageIter iter; + + if (!dbus_message_iter_init(&aMessage, &iter)) + { + return true; + } + return dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_INVALID; +} + } // namespace DBus } // namespace otbr diff --git a/src/dbus/common/dbus_message_helper.hpp b/src/dbus/common/dbus_message_helper.hpp index c19f660ed4f..6b1528b261d 100644 --- a/src/dbus/common/dbus_message_helper.hpp +++ b/src/dbus/common/dbus_message_helper.hpp @@ -583,6 +583,8 @@ otbrError DBusMessageToTuple(UniqueDBusMessage const &aMessage, std::tupleAttach([aRequest](otError aError) mutable { aRequest.ReplyOtResult(aError); }); + } + else if (DBusMessageToTuple(*aRequest.GetMessage(), args) != OTBR_ERROR_NONE) { aRequest.ReplyOtResult(OT_ERROR_INVALID_ARGS); } @@ -961,5 +969,38 @@ otError DBusThreadObject::GetExternalRoutesHandler(DBusMessageIter &aIter) return error; } +otError DBusThreadObject::SetActiveDatasetTlvsHandler(DBusMessageIter &aIter) +{ + auto threadHelper = mNcp->GetThreadHelper(); + std::vector data; + otOperationalDatasetTlvs datasetTlvs; + otError error = OT_ERROR_NONE; + + VerifyOrExit(DBusMessageExtractFromVariant(&aIter, data) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); + VerifyOrExit(data.size() <= sizeof(datasetTlvs.mTlvs)); + std::copy(std::begin(data), std::end(data), std::begin(datasetTlvs.mTlvs)); + datasetTlvs.mLength = data.size(); + error = otDatasetSetActiveTlvs(threadHelper->GetInstance(), &datasetTlvs); + +exit: + return error; +} + +otError DBusThreadObject::GetActiveDatasetTlvsHandler(DBusMessageIter &aIter) +{ + auto threadHelper = mNcp->GetThreadHelper(); + otError error = OT_ERROR_NONE; + std::vector data; + otOperationalDatasetTlvs datasetTlvs; + + SuccessOrExit(error = otDatasetGetActiveTlvs(threadHelper->GetInstance(), &datasetTlvs)); + data = std::vector{std::begin(datasetTlvs.mTlvs), std::begin(datasetTlvs.mTlvs) + datasetTlvs.mLength}; + + VerifyOrExit(DBusMessageEncodeToVariant(&aIter, data) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); + +exit: + return error; +} + } // namespace DBus } // namespace otbr diff --git a/src/dbus/server/dbus_thread_object.hpp b/src/dbus/server/dbus_thread_object.hpp index 4893935b4da..e59997e466a 100644 --- a/src/dbus/server/dbus_thread_object.hpp +++ b/src/dbus/server/dbus_thread_object.hpp @@ -86,6 +86,7 @@ class DBusThreadObject : public DBusObject otError SetMeshLocalPrefixHandler(DBusMessageIter &aIter); otError SetLegacyUlaPrefixHandler(DBusMessageIter &aIter); otError SetLinkModeHandler(DBusMessageIter &aIter); + otError SetActiveDatasetTlvsHandler(DBusMessageIter &aIter); otError GetLinkModeHandler(DBusMessageIter &aIter); otError GetDeviceRoleHandler(DBusMessageIter &aIter); @@ -113,6 +114,7 @@ class DBusThreadObject : public DBusObject otError GetInstantRssiHandler(DBusMessageIter &aIter); otError GetRadioTxPowerHandler(DBusMessageIter &aIter); otError GetExternalRoutesHandler(DBusMessageIter &aIter); + otError GetActiveDatasetTlvsHandler(DBusMessageIter &aIter); void ReplyScanResult(DBusRequest &aRequest, otError aError, const std::vector &aResult); diff --git a/src/dbus/server/introspect.xml b/src/dbus/server/introspect.xml index 0850c5f9270..da4193487f3 100644 --- a/src/dbus/server/introspect.xml +++ b/src/dbus/server/introspect.xml @@ -31,6 +31,9 @@ + + + @@ -334,6 +337,10 @@ + + + + diff --git a/tests/dbus/test_dbus_client.cpp b/tests/dbus/test_dbus_client.cpp index deb324a7922..1d34810bbb4 100644 --- a/tests/dbus/test_dbus_client.cpp +++ b/tests/dbus/test_dbus_client.cpp @@ -134,7 +134,9 @@ int main() [&api, channel, extpanid](ClientError aError) { printf("Attach result %d\n", static_cast(aError)); sleep(10); - uint64_t extpanidCheck; + uint64_t extpanidCheck; + std::vector activeDataset; + if (aError == OTBR_ERROR_NONE) { std::string name; @@ -166,6 +168,7 @@ int main() TEST_ASSERT(api->GetPartitionId(partitionId) == OTBR_ERROR_NONE); TEST_ASSERT(api->GetInstantRssi(rssi) == OTBR_ERROR_NONE); TEST_ASSERT(api->GetRadioTxPower(txPower) == OTBR_ERROR_NONE); + TEST_ASSERT(api->GetActiveDatasetTlvs(activeDataset) == OTBR_ERROR_NONE); api->FactoryReset(nullptr); TEST_ASSERT(api->GetNetworkName(name) == OTBR_ERROR_NONE); TEST_ASSERT(rloc16 != 0xffff); @@ -178,10 +181,13 @@ int main() { exit(-1); } - api->Attach("Test", 0x5678, extpanid, {}, {}, UINT32_MAX, [&api](ClientError aErr) { + TEST_ASSERT(api->SetActiveDatasetTlvs(activeDataset) == OTBR_ERROR_NONE); + api->Attach([&api, channel, extpanid](ClientError aErr) { uint8_t routerId; otbr::DBus::LeaderData leaderData; uint8_t leaderWeight; + uint16_t channelResult; + uint64_t extpanidCheck; Ip6Prefix prefix; OnMeshPrefix onMeshPrefix = {}; @@ -192,6 +198,11 @@ int main() onMeshPrefix.mPreference = 0; onMeshPrefix.mStable = true; + TEST_ASSERT(api->GetChannel(channelResult) == OTBR_ERROR_NONE); + TEST_ASSERT(channelResult == channel); + TEST_ASSERT(api->GetExtPanId(extpanidCheck) == OTBR_ERROR_NONE); + TEST_ASSERT(extpanidCheck == extpanid); + TEST_ASSERT(api->GetLocalLeaderWeight(leaderWeight) == OTBR_ERROR_NONE); TEST_ASSERT(api->GetLeaderData(leaderData) == OTBR_ERROR_NONE); TEST_ASSERT(api->GetRouterId(routerId) == OTBR_ERROR_NONE); From c537189ce80d970d08f9ee51fa5f910298ed750e Mon Sep 17 00:00:00 2001 From: kangping Date: Thu, 31 Dec 2020 03:30:06 +0800 Subject: [PATCH 047/175] [ncp] initialize OT instance to nullptr in the constructor (#667) --- src/agent/ncp_openthread.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/agent/ncp_openthread.cpp b/src/agent/ncp_openthread.cpp index 4c2bec4d0cd..5ae5f2f994f 100644 --- a/src/agent/ncp_openthread.cpp +++ b/src/agent/ncp_openthread.cpp @@ -64,7 +64,8 @@ namespace Ncp { ControllerOpenThread::ControllerOpenThread(const char *aInterfaceName, const char *aRadioUrl, const char *aBackboneInterfaceName) - : mTriedAttach(false) + : mInstance(nullptr) + , mTriedAttach(false) { memset(&mConfig, 0, sizeof(mConfig)); From eff3372505a3ad32222c6b6bacc32e4f044c956c Mon Sep 17 00:00:00 2001 From: kangping Date: Thu, 31 Dec 2020 03:44:41 +0800 Subject: [PATCH 048/175] [utils] add gitignores for CLion (#663) --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 96311abbd3b..15c86358b23 100644 --- a/.gitignore +++ b/.gitignore @@ -105,6 +105,10 @@ tests/unit/unittest # Vim auto complete helper .ycm_extra_conf.py +# CLion +.idea/** +cmake-build-*/** + # Thread local storage ./tmp/ *.data From 3f7af7408fe78ba789fd86efa2a2b6c4e37258de Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Fri, 1 Jan 2021 01:24:45 +0800 Subject: [PATCH 049/175] [codecov] fix codecov drop (#654) Seems codecov does not work on ubuntu-20.04 here. The actual cause is not found yet. Revert one job to use ubuntu-18.04 to fix codecov issue. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d312efe899d..b7b4f58c7a4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -87,7 +87,7 @@ jobs: uses: codecov/codecov-action@v1 rest-check: - runs-on: ubuntu-20.04 + runs-on: ubuntu-18.04 strategy: matrix: rest: ["rest-off", ""] From dd80cd847520c39555a1ebd44ca5fc031fdba338 Mon Sep 17 00:00:00 2001 From: kangping Date: Fri, 1 Jan 2021 01:28:16 +0800 Subject: [PATCH 050/175] [mdns] add mDNS API to publish & un-publish custom host (#664) This commit adds the ability to publish a service with custom host name & address. For a BR, we need to help advertise a service registered by a Thread device. the Service resides on the end device and has specific host name & address. To support it, this commit adds below changes: - add an additional aHostName param to the PublishService API to allow specifying a custom host name; - add API UnpublishService to un-publish a service when the Thread device de-registers it from the BR. We cannot simply stop the Publisher because there may be many services from different Thread end devices. - add API PublishHost to publish a host name & address pair. The service cannot be resolved if the host it points to doesn't have a valid address RR. - add API UnpublishHost to un-publish the a host name & address pair. We cannot simply stop the Publisher because there can be many hosts registered by different Thread end devices. - add mdnssd implementation of those new APIs. --- src/agent/border_agent.cpp | 4 +- src/mdns/mdns.hpp | 61 ++++++-- src/mdns/mdns_avahi.cpp | 50 +++++-- src/mdns/mdns_avahi.hpp | 54 ++++++- src/mdns/mdns_mdnssd.cpp | 200 ++++++++++++++++++++++++-- src/mdns/mdns_mdnssd.hpp | 88 ++++++++++-- tests/mdns/CMakeLists.txt | 16 ++- tests/mdns/main.cpp | 132 ++++++++++++++--- tests/mdns/test-multiple-custom-hosts | 55 +++++++ tests/mdns/test-single-custom-host | 50 +++++++ tests/mdns/test_init | 23 +++ 11 files changed, 659 insertions(+), 74 deletions(-) create mode 100755 tests/mdns/test-multiple-custom-hosts create mode 100755 tests/mdns/test-single-custom-host diff --git a/src/agent/border_agent.cpp b/src/agent/border_agent.cpp index cb927854a86..60ba46b6388 100644 --- a/src/agent/border_agent.cpp +++ b/src/agent/border_agent.cpp @@ -83,7 +83,7 @@ enum BorderAgent::BorderAgent(Ncp::Controller *aNcp) #if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO - : mPublisher(Mdns::Publisher::Create(AF_UNSPEC, nullptr, nullptr, HandleMdnsState, this)) + : mPublisher(Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, HandleMdnsState, this)) #else : mPublisher(nullptr) #endif @@ -224,7 +224,7 @@ void BorderAgent::PublishService(void) assert(mThreadVersion != 0); // clang-format off - mPublisher->PublishService(kBorderAgentUdpPort, mNetworkName, kBorderAgentServiceType, + mPublisher->PublishService(/* aHostName */ nullptr, kBorderAgentUdpPort, mNetworkName, kBorderAgentServiceType, "nn", mNetworkName, strlen(mNetworkName), "xp", &mExtPanId, sizeof(mExtPanId), "tv", versionString, strlen(versionString), diff --git a/src/mdns/mdns.hpp b/src/mdns/mdns.hpp index ef54dcc4091..a12bc3d513d 100644 --- a/src/mdns/mdns.hpp +++ b/src/mdns/mdns.hpp @@ -104,6 +104,10 @@ class Publisher /** * This method publishes or updates a service. * + * @param[in] aHostName The name of the host which this service resides on. If NULL is provided, + * this service resides on local host and it is the implementation to provide + * specific host name. Otherwise, the caller MUST publish the host with method + * PublishHost. * @param[in] aName The name of this service. * @param[in] aType The type of this service. * @param[in] aPort The port number of this service. @@ -114,7 +118,51 @@ class Publisher * @retval OTBR_ERROR_ERRNO Failed to publish or update the service. * */ - virtual otbrError PublishService(uint16_t aPort, const char *aName, const char *aType, ...) = 0; + virtual otbrError PublishService(const char *aHostName, + uint16_t aPort, + const char *aName, + const char *aType, + ...) = 0; + + /** + * This method un-publishes a service. + * + * @param[in] aName The name of this service. + * @param[in] aType The type of this service. + * + * @retval OTBR_ERROR_NONE Successfully un-published the service. + * @retval OTBR_ERROR_ERRNO Failed to un-publish the service. + * + */ + virtual otbrError UnpublishService(const char *aName, const char *aType) = 0; + + /** + * This method publishes or updates a host. + * + * Publishing a host is advertising an A/AAAA RR for the host name. This method should be called + * before a service with non-null host name is published. + * + * @param[in] aName The name of the host. + * @param[in] aAddress The address of the host. + * @param[in] aAddressLength The length of @p aAddress. + * + * @retval OTBR_ERROR_NONE Successfully published or updated the host. + * @retval OTBR_ERROR_INVALID_ARGS The arguments are not valid. + * @retval OTBR_ERROR_ERRNO Failed to publish or update the host. + * + */ + virtual otbrError PublishHost(const char *aName, const uint8_t *aAddress, uint8_t aAddressLength) = 0; + + /** + * This method un-publishes a host. + * + * @param[in] aName A host name. + * + * @retval OTBR_ERROR_NONE Successfully un-published the host. + * @retval OTBR_ERROR_ERRNO Failed to un-publish the host. + * + */ + virtual otbrError UnpublishHost(const char *aName) = 0; /** * This method performs the MDNS processing. @@ -149,22 +197,17 @@ class Publisher * This function creates a MDNS publisher. * * @param[in] aProtocol Protocol to use for publishing. AF_INET6, AF_INET or AF_UNSPEC. - * @param[in] aHost The host where these services is residing on. - * @param[in] aDomain The domain to register in. + * @param[in] aDomain The domain to register in. Set nullptr to use default mDNS domain ("local."). * @param[in] aHandler The function to be called when this service state changed. * @param[in] aContext A pointer to application-specific context. * * @returns A pointer to the newly created MDNS publisher. * */ - static Publisher *Create(int aProtocol, - const char * aHost, - const char * aDomain, - StateHandler aHandler, - void * aContext); + static Publisher *Create(int aProtocol, const char *aDomain, StateHandler aHandler, void *aContext); /** - * This function destroies the MDNS publisher. + * This function destroys the MDNS publisher. * * @param[in] aPublisher A pointer to the publisher. * diff --git a/src/mdns/mdns_avahi.cpp b/src/mdns/mdns_avahi.cpp index 0db1b24170d..191003ce5ed 100644 --- a/src/mdns/mdns_avahi.cpp +++ b/src/mdns/mdns_avahi.cpp @@ -305,16 +305,11 @@ void Poller::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet, const } } -PublisherAvahi::PublisherAvahi(int aProtocol, - const char * aHost, - const char * aDomain, - StateHandler aHandler, - void * aContext) +PublisherAvahi::PublisherAvahi(int aProtocol, const char *aDomain, StateHandler aHandler, void *aContext) : mClient(nullptr) , mGroup(nullptr) , mProtocol(aProtocol == AF_INET6 ? AVAHI_PROTO_INET6 : aProtocol == AF_INET ? AVAHI_PROTO_INET : AVAHI_PROTO_UNSPEC) - , mHost(aHost) , mDomain(aDomain) , mState(kStateIdle) , mStateHandler(aHandler) @@ -497,7 +492,11 @@ void PublisherAvahi::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet mPoller.Process(aReadFdSet, aWriteFdSet, aErrorFdSet); } -otbrError PublisherAvahi::PublishService(uint16_t aPort, const char *aName, const char *aType, ...) +otbrError PublisherAvahi::PublishService(const char *aHostName, + uint16_t aPort, + const char *aName, + const char *aType, + ...) { otbrError ret = OTBR_ERROR_ERRNO; int error = 0; @@ -510,6 +509,7 @@ otbrError PublisherAvahi::PublishService(uint16_t aPort, const char *aName, cons va_start(args, aType); + VerifyOrExit(aHostName == nullptr, ret = OTBR_ERROR_NOT_IMPLEMENTED); VerifyOrExit(mState == kStateReady, errno = EAGAIN); VerifyOrExit(mGroup != nullptr, ret = OTBR_ERROR_MDNS); @@ -551,7 +551,7 @@ otbrError PublisherAvahi::PublishService(uint16_t aPort, const char *aName, cons otbrLog(OTBR_LOG_INFO, "MDNS create service %s", aName); error = avahi_entry_group_add_service_strlst(mGroup, AVAHI_IF_UNSPEC, mProtocol, static_cast(0), - aName, aType, mDomain, mHost, aPort, last); + aName, aType, mDomain, aHostName, aPort, last); SuccessOrExit(error); { @@ -581,9 +581,39 @@ otbrError PublisherAvahi::PublishService(uint16_t aPort, const char *aName, cons return ret; } -Publisher *Publisher::Create(int aFamily, const char *aHost, const char *aDomain, StateHandler aHandler, void *aContext) +otbrError PublisherAvahi::UnpublishService(const char *aName, const char *aType) { - return new PublisherAvahi(aFamily, aHost, aDomain, aHandler, aContext); + OTBR_UNUSED_VARIABLE(aName); + OTBR_UNUSED_VARIABLE(aType); + + VerifyOrDie(false, "UnpublishService is not implemented with avahi"); + + return OTBR_ERROR_NONE; +} + +otbrError PublisherAvahi::PublishHost(const char *aName, const uint8_t *aAddress, uint8_t aAddressLength) +{ + OTBR_UNUSED_VARIABLE(aName); + OTBR_UNUSED_VARIABLE(aAddress); + OTBR_UNUSED_VARIABLE(aAddressLength); + + VerifyOrDie(false, "PublishHost is not implemented with avahi"); + + return OTBR_ERROR_NONE; +} + +otbrError PublisherAvahi::UnpublishHost(const char *aName) +{ + OTBR_UNUSED_VARIABLE(aName); + + VerifyOrDie(false, "UnpublishHost is not implemented with avahi"); + + return OTBR_ERROR_NONE; +} + +Publisher *Publisher::Create(int aFamily, const char *aDomain, StateHandler aHandler, void *aContext) +{ + return new PublisherAvahi(aFamily, aDomain, aHandler, aContext); } void Publisher::Destroy(Publisher *aPublisher) diff --git a/src/mdns/mdns_avahi.hpp b/src/mdns/mdns_avahi.hpp index 09b13602982..e47750f2ac1 100644 --- a/src/mdns/mdns_avahi.hpp +++ b/src/mdns/mdns_avahi.hpp @@ -194,22 +194,22 @@ class PublisherAvahi : public Publisher * The constructor to initialize a Publisher. * * @param[in] aProtocol The protocol used for publishing. IPv4, IPv6 or both. - * @param[in] aHost The name of host residing the services to be published. - nullptr to use default. * @param[in] aDomain The domain of the host. nullptr to use default. * @param[in] aHandler The function to be called when state changes. * @param[in] aContext A pointer to application-specific context. * */ - PublisherAvahi(int aProtocol, const char *aHost, const char *aDomain, StateHandler aHandler, void *aContext); + PublisherAvahi(int aProtocol, const char *aDomain, StateHandler aHandler, void *aContext); ~PublisherAvahi(void) override; /** * This method publishes or updates a service. * - * @note only text record can be updated. - * + * @param[in] aHostName The name of the host which this service resides on. If NULL is provided, + * this service resides on local host and it is the implementation to provide + * specific host name. Otherwise, the caller MUST publish the host with method + * PublishHost. * @param[in] aName The name of this service. * @param[in] aType The type of this service. * @param[in] aPort The port number of this service. @@ -220,7 +220,48 @@ class PublisherAvahi : public Publisher * @retval OTBR_ERROR_ERRNO Failed to publish or update the service. * */ - otbrError PublishService(uint16_t aPort, const char *aName, const char *aType, ...) override; + otbrError PublishService(const char *aHostName, uint16_t aPort, const char *aName, const char *aType, ...) override; + + /** + * This method un-publishes a service. + * + * @param[in] aName The name of this service. + * @param[in] aType The type of this service. + * + * @retval OTBR_ERROR_NONE Successfully un-published the service. + * @retval OTBR_ERROR_ERRNO Failed to un-publish the service. + * + */ + otbrError UnpublishService(const char *aName, const char *aType) override; + + /** + * This method publishes or updates a host. + * + * Publishing a host is advertising an AAAA RR for the host name. This method should be called + * before a service with non-null host name is published. + * + * @param[in] aName The name of the host. + * @param[in] aAddress The address of the host. + * @param[in] aAddressLength The length of @p aAddress. + * + * @retval OTBR_ERROR_NONE Successfully published or updated the host. + * @retval OTBR_ERROR_ERRNO Failed to publish or update the host. + * + */ + otbrError PublishHost(const char *aName, const uint8_t *aAddress, uint8_t aAddressLength) override; + + /** + * This method un-publishes a host. + * + * @param[in] aName A host name. + * + * @retval OTBR_ERROR_NONE Successfully un-published the host. + * @retval OTBR_ERROR_ERRNO Failed to un-publish the host. + * + * @note All services reside on this host should be un-published by UnpublishService. + * + */ + otbrError UnpublishHost(const char *aName) override; /** * This method starts the MDNS service. @@ -303,7 +344,6 @@ class PublisherAvahi : public Publisher AvahiEntryGroup *mGroup; Poller mPoller; int mProtocol; - const char * mHost; const char * mDomain; State mState; StateHandler mStateHandler; diff --git a/src/mdns/mdns_mdnssd.cpp b/src/mdns/mdns_mdnssd.cpp index f2d1af6136e..480e47e6a1e 100644 --- a/src/mdns/mdns_mdnssd.cpp +++ b/src/mdns/mdns_mdnssd.cpp @@ -33,6 +33,8 @@ #include "mdns/mdns_mdnssd.hpp" +#include + #include #include #include @@ -162,12 +164,8 @@ static const char *DNSErrorToString(DNSServiceErrorType aError) } } -PublisherMDnsSd::PublisherMDnsSd(int aProtocol, - const char * aHost, - const char * aDomain, - StateHandler aHandler, - void * aContext) - : mHost(aHost) +PublisherMDnsSd::PublisherMDnsSd(int aProtocol, const char *aDomain, StateHandler aHandler, void *aContext) + : mHostsConnection(nullptr) , mDomain(aDomain) , mState(kStateIdle) , mStateHandler(aHandler) @@ -205,6 +203,16 @@ void PublisherMDnsSd::Stop(void) mServices.clear(); + if (mHostsConnection != nullptr) + { + otbrLog(OTBR_LOG_INFO, "MDNS remove all hosts"); + + // This effectively removes all hosts registered on this connection. + DNSServiceRefDeallocate(mHostsConnection); + mHostsConnection = nullptr; + mHosts.clear(); + } + exit: return; } @@ -232,6 +240,20 @@ void PublisherMDnsSd::UpdateFdSet(fd_set & aReadFdSet, aMaxFd = fd; } } + + if (mHostsConnection != nullptr) + { + int fd = DNSServiceRefSockFD(mHostsConnection); + + assert(fd != -1); + + FD_SET(fd, &aReadFdSet); + + if (fd > aMaxFd) + { + aMaxFd = fd; + } + } } void PublisherMDnsSd::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet, const fd_set &aErrorFdSet) @@ -251,6 +273,16 @@ void PublisherMDnsSd::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSe } } + if (mHostsConnection != nullptr) + { + int fd = DNSServiceRefSockFD(mHostsConnection); + + if (FD_ISSET(fd, &aReadFdSet)) + { + readyServices.push_back(mHostsConnection); + } + } + for (std::vector::iterator it = readyServices.begin(); it != readyServices.end(); ++it) { DNSServiceErrorType error = DNSServiceProcessResult(*it); @@ -309,7 +341,7 @@ void PublisherMDnsSd::DiscardService(const char *aName, const char *aType, DNSSe { if (!strncmp(it->mName, aName, sizeof(it->mName)) && !strncmp(it->mType, aType, sizeof(it->mType))) { - assert(aServiceRef == it->mService); + assert(aServiceRef == nullptr || aServiceRef == it->mService); mServices.erase(it); DNSServiceRefDeallocate(aServiceRef); aServiceRef = nullptr; @@ -344,7 +376,11 @@ void PublisherMDnsSd::RecordService(const char *aName, const char *aType, DNSSer return; } -otbrError PublisherMDnsSd::PublishService(uint16_t aPort, const char *aName, const char *aType, ...) +otbrError PublisherMDnsSd::PublishService(const char *aHostName, + uint16_t aPort, + const char *aName, + const char *aType, + ...) { otbrError ret = OTBR_ERROR_NONE; int error = 0; @@ -352,6 +388,17 @@ otbrError PublisherMDnsSd::PublishService(uint16_t aPort, const char *aName, con uint8_t txt[kMaxSizeOfTxtRecord]; uint8_t * cur = txt; DNSServiceRef serviceRef = nullptr; + char fullHostName[kMaxSizeOfDomain]; + + if (aHostName != nullptr) + { + auto host = std::find_if(mHosts.begin(), mHosts.end(), + [&](const Host &aHost) { return strcmp(aHost.mName, aHostName) == 0; }); + + // Make sure that the host has been published. + VerifyOrExit(host != mHosts.end(), ret = OTBR_ERROR_INVALID_ARGS); + SuccessOrExit(error = MakeFullName(fullHostName, sizeof(fullHostName), aHostName)); + } va_start(args, aType); @@ -396,9 +443,9 @@ otbrError PublisherMDnsSd::PublishService(uint16_t aPort, const char *aName, con } } - SuccessOrExit(error = DNSServiceRegister(&serviceRef, 0, kDNSServiceInterfaceIndexAny, aName, aType, mDomain, mHost, - htons(aPort), static_cast(cur - txt), txt, - HandleServiceRegisterResult, this)); + SuccessOrExit(error = DNSServiceRegister(&serviceRef, 0, kDNSServiceInterfaceIndexAny, aName, aType, mDomain, + (aHostName != nullptr) ? fullHostName : nullptr, htons(aPort), + static_cast(cur - txt), txt, HandleServiceRegisterResult, this)); if (serviceRef != nullptr) { RecordService(aName, aType, serviceRef); @@ -415,9 +462,136 @@ otbrError PublisherMDnsSd::PublishService(uint16_t aPort, const char *aName, con return ret; } -Publisher *Publisher::Create(int aFamily, const char *aHost, const char *aDomain, StateHandler aHandler, void *aContext) +otbrError PublisherMDnsSd::UnpublishService(const char *aName, const char *aType) +{ + DiscardService(aName, aType); + return OTBR_ERROR_NONE; +} + +otbrError PublisherMDnsSd::PublishHost(const char *aName, const uint8_t *aAddress, uint8_t aAddressLength) +{ + otbrError ret = OTBR_ERROR_NONE; + int error = 0; + char fullName[kMaxSizeOfDomain]; + DNSRecordRef hostRecord; + Host newHost; + + // Supports only IPv6 for now, may support IPv4 in the future. + VerifyOrExit(aAddressLength == OTBR_IP6_ADDRESS_SIZE, error = OTBR_ERROR_INVALID_ARGS); + + SuccessOrExit(ret = MakeFullName(fullName, sizeof(fullName), aName)); + + if (mHostsConnection == nullptr) + { + SuccessOrExit(error = DNSServiceCreateConnection(&mHostsConnection)); + } + + for (const auto &host : mHosts) + { + if (strcmp(aName, host.mName) == 0) + { + otbrLog(OTBR_LOG_INFO, "mDNS update host %s", aName); + SuccessOrExit(error = DNSServiceUpdateRecord(mHostsConnection, host.mRecord, /* flags */ 0, aAddressLength, + aAddress, /* ttl */ 0)); + ExitNow(); + } + } + + SuccessOrExit(error = DNSServiceRegisterRecord(mHostsConnection, &hostRecord, kDNSServiceFlagsUnique, + kDNSServiceInterfaceIndexAny, fullName, kDNSServiceType_AAAA, + kDNSServiceClass_IN, aAddressLength, aAddress, /* ttl */ 0, + HandleRegisterHostResult, this)); + strcpy(newHost.mName, aName); + newHost.mRecord = hostRecord; + mHosts.push_back(newHost); + +exit: + if (error != kDNSServiceErr_NoError) + { + ret = OTBR_ERROR_MDNS; + otbrLog(OTBR_LOG_ERR, "Failed to publish/update host %s for mdnssd error: %s!", aName, DNSErrorToString(error)); + } + return ret; +} + +otbrError PublisherMDnsSd::UnpublishHost(const char *aName) +{ + otbrError ret = OTBR_ERROR_NONE; + int error = 0; + + auto host = + std::find_if(mHosts.begin(), mHosts.end(), [&](const Host &aHost) { return strcmp(aHost.mName, aName) == 0; }); + if (host == mHosts.end()) + { + ExitNow(); + } + + SuccessOrExit(error = DNSServiceRemoveRecord(mHostsConnection, host->mRecord, /* flags */ 0)); + mHosts.erase(host); + +exit: + if (error != kDNSServiceErr_NoError) + { + ret = OTBR_ERROR_MDNS; + otbrLog(OTBR_LOG_ERR, "Failed to un-publish host %s for mdnssd error: %s!", aName, DNSErrorToString(error)); + } + return ret; +} + +void PublisherMDnsSd::HandleRegisterHostResult(DNSServiceRef aHostsConnection, + DNSRecordRef aHostRecord, + DNSServiceFlags aFlags, + DNSServiceErrorType aErrorCode, + void * aContext) +{ + static_cast(aContext)->HandleRegisterHostResult(aHostsConnection, aHostRecord, aFlags, + aErrorCode); +} + +void PublisherMDnsSd::HandleRegisterHostResult(DNSServiceRef aHostsConnection, + DNSRecordRef aHostRecord, + DNSServiceFlags aFlags, + DNSServiceErrorType aErrorCode) +{ + OTBR_UNUSED_VARIABLE(aHostsConnection); + OTBR_UNUSED_VARIABLE(aFlags); + + auto host = + std::find_if(mHosts.begin(), mHosts.end(), [&](const Host &aHost) { return aHost.mRecord == aHostRecord; }); + assert(host != mHosts.end()); + + if (aErrorCode == kDNSServiceErr_NoError) + { + otbrLog(OTBR_LOG_INFO, "Successfully registered host %s", host->mName); + } + else + { + otbrLog(OTBR_LOG_WARNING, "Failed to register host %s for mdnssd error: %s", host->mName, + DNSErrorToString(aErrorCode)); + } +} + +otbrError PublisherMDnsSd::MakeFullName(char *aFullName, size_t aFullNameLength, const char *aName) +{ + otbrError error = OTBR_ERROR_NONE; + size_t nameLength = strlen(aName); + const char *domain = (mDomain == nullptr) ? "local." : mDomain; + + VerifyOrExit(nameLength <= kMaxSizeOfHost, error = OTBR_ERROR_INVALID_ARGS); + + assert(aFullNameLength >= nameLength + sizeof(".") + strlen(domain)); + + strcpy(aFullName, aName); + strcpy(aFullName + nameLength, "."); + strcpy(aFullName + nameLength + 1, domain); + +exit: + return error; +} + +Publisher *Publisher::Create(int aFamily, const char *aDomain, StateHandler aHandler, void *aContext) { - return new PublisherMDnsSd(aFamily, aHost, aDomain, aHandler, aContext); + return new PublisherMDnsSd(aFamily, aDomain, aHandler, aContext); } void Publisher::Destroy(Publisher *aPublisher) diff --git a/src/mdns/mdns_mdnssd.hpp b/src/mdns/mdns_mdnssd.hpp index ad0f9da88d3..601622a95d2 100644 --- a/src/mdns/mdns_mdnssd.hpp +++ b/src/mdns/mdns_mdnssd.hpp @@ -56,22 +56,22 @@ class PublisherMDnsSd : public Publisher * The constructor to initialize a Publisher. * * @param[in] aProtocol The protocol used for publishing. IPv4, IPv6 or both. - * @param[in] aHost The name of host residing the services to be published. - nullptr to use default. * @param[in] aDomain The domain of the host. nullptr to use default. * @param[in] aHandler The function to be called when state changes. * @param[in] aContext A pointer to application-specific context. * */ - PublisherMDnsSd(int aProtocol, const char *aHost, const char *aDomain, StateHandler aHandler, void *aContext); + PublisherMDnsSd(int aProtocol, const char *aDomain, StateHandler aHandler, void *aContext); ~PublisherMDnsSd(void) override; /** * This method publishes or updates a service. * - * @note only text record can be updated. - * + * @param[in] aHostName The name of the host which this service resides on. If NULL is provided, + * this service resides on local host and it is the implementation to provide + * specific host name. Otherwise, the caller MUST publish the host with method + * PublishHost. * @param[in] aName The name of this service. * @param[in] aType The type of this service. * @param[in] aPort The port number of this service. @@ -82,7 +82,48 @@ class PublisherMDnsSd : public Publisher * @retval OTBR_ERROR_ERRNO Failed to publish or update the service. * */ - otbrError PublishService(uint16_t aPort, const char *aName, const char *aType, ...) override; + otbrError PublishService(const char *aHostName, uint16_t aPort, const char *aName, const char *aType, ...) override; + + /** + * This method un-publishes a service. + * + * @param[in] aName The name of this service. + * @param[in] aType The type of this service. + * + * @retval OTBR_ERROR_NONE Successfully un-published the service. + * @retval OTBR_ERROR_ERRNO Failed to un-publish the service. + * + */ + otbrError UnpublishService(const char *aName, const char *aType) override; + + /** + * This method publishes or updates a host. + * + * Publishing a host is advertising an AAAA RR for the host name. This method should be called + * before a service with non-null host name is published. + * + * @param[in] aName The name of the host. + * @param[in] aAddress The address of the host. + * @param[in] aAddressLength The length of @p aAddress. + * + * @retval OTBR_ERROR_NONE Successfully published or updated the host. + * @retval OTBR_ERROR_ERRNO Failed to publish or update the host. + * + */ + otbrError PublishHost(const char *aName, const uint8_t *aAddress, uint8_t aAddressLength) override; + + /** + * This method un-publishes a host. + * + * @param[in] aName A host name. + * + * @retval OTBR_ERROR_NONE Successfully un-published the host. + * @retval OTBR_ERROR_ERRNO Failed to un-publish the host. + * + * @note All services reside on this host should be un-published by UnpublishService. + * + */ + otbrError UnpublishHost(const char *aName) override; /** * This method starts the MDNS service. @@ -135,7 +176,7 @@ class PublisherMDnsSd : public Publisher timeval &aTimeout) override; private: - void DiscardService(const char *aName, const char *aType, DNSServiceRef aServiceRef); + void DiscardService(const char *aName, const char *aType, DNSServiceRef aServiceRef = nullptr); void RecordService(const char *aName, const char *aType, DNSServiceRef aServiceRef); static void HandleServiceRegisterResult(DNSServiceRef aService, @@ -151,6 +192,17 @@ class PublisherMDnsSd : public Publisher const char * aName, const char * aType, const char * aDomain); + static void HandleRegisterHostResult(DNSServiceRef aHostsConnection, + DNSRecordRef aHostRecord, + DNSServiceFlags aFlags, + DNSServiceErrorType aErrorCode, + void * aContext); + void HandleRegisterHostResult(DNSServiceRef aHostsConnection, + DNSRecordRef aHostRecord, + DNSServiceFlags aFlags, + DNSServiceErrorType aErrorCode); + + otbrError MakeFullName(char *aFullName, size_t aFullNameLength, const char *aName); enum { @@ -169,14 +221,22 @@ class PublisherMDnsSd : public Publisher DNSServiceRef mService; }; - typedef std::vector Services; + struct Host + { + char mName[kMaxSizeOfServiceName]; + DNSRecordRef mRecord; + }; - Services mServices; - const char * mHost; - const char * mDomain; - State mState; - StateHandler mStateHandler; - void * mContext; + typedef std::vector Services; + typedef std::vector Hosts; + + Services mServices; + Hosts mHosts; + DNSServiceRef mHostsConnection; + const char * mDomain; + State mState; + StateHandler mStateHandler; + void * mContext; }; /** diff --git a/tests/mdns/CMakeLists.txt b/tests/mdns/CMakeLists.txt index a602a7545dd..48c753741a2 100644 --- a/tests/mdns/CMakeLists.txt +++ b/tests/mdns/CMakeLists.txt @@ -33,7 +33,6 @@ add_executable(otbr-test-mdns target_link_libraries(otbr-test-mdns PRIVATE otbr-config otbr-mdns - openthread-ftd ) add_test( @@ -56,6 +55,17 @@ add_test( COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test-stop ) -set_tests_properties(mdns-single mdns-multiple mdns-update mdns-stop PROPERTIES - ENVIRONMENT "OTBR_MDNS=${OTBR_MDNS};OTBR_TEST_MDNS=$" +add_test( + NAME mdns-single-custom-host + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test-single-custom-host +) + +add_test( + NAME mdns-multiple-custom-hosts + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test-multiple-custom-hosts +) + +set_tests_properties(mdns-single mdns-multiple mdns-update mdns-stop mdns-single-custom-host mdns-multiple-custom-hosts + PROPERTIES + ENVIRONMENT "OTBR_MDNS=${OTBR_MDNS};OTBR_TEST_MDNS=$" ) diff --git a/tests/mdns/main.cpp b/tests/mdns/main.cpp index 4239c73e121..d169e09eaed 100644 --- a/tests/mdns/main.cpp +++ b/tests/mdns/main.cpp @@ -80,6 +80,75 @@ int Mainloop(Mdns::Publisher &aPublisher) return rval; } +void PublishSingleServiceWithCustomHost(void *aContext, Mdns::State aState) +{ + uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; + uint8_t hostAddr[16] = {0}; + const char hostName[] = "custom-host"; + + hostAddr[0] = 0x20; + hostAddr[1] = 0x02; + hostAddr[15] = 0x01; + + VerifyOrDie(aContext == &sContext, "unexpected context"); + if (aState == Mdns::kStateReady) + { + otbrError error; + + error = sContext.mPublisher->PublishHost(hostName, hostAddr, sizeof(hostAddr)); + SuccessOrDie(error, "cannot publish the host"); + + error = sContext.mPublisher->PublishService(hostName, 12345, "SingleService", "_meshcop._udp.", "nn", "cool", + sizeof("cool") - 1, "xp", reinterpret_cast(&xpanid), + sizeof(xpanid), nullptr); + SuccessOrDie(error, "cannot publish the service"); + } +} + +void PublishMultipleServicesWithCustomHost(void *aContext, Mdns::State aState) +{ + uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; + uint8_t hostAddr[16] = {0}; + const char hostName1[] = "custom-host-1"; + const char hostName2[] = "custom-host-2"; + + hostAddr[0] = 0x20; + hostAddr[1] = 0x02; + hostAddr[15] = 0x01; + + VerifyOrDie(aContext == &sContext, "unexpected context"); + if (aState == Mdns::kStateReady) + { + otbrError error; + + error = sContext.mPublisher->PublishHost(hostName1, hostAddr, sizeof(hostAddr)); + SuccessOrDie(error, "cannot publish the first host"); + + error = sContext.mPublisher->PublishService(hostName1, 12345, "MultipleService11", "_meshcop._udp.", "nn", + "cool", sizeof("cool") - 1, "xp", reinterpret_cast(&xpanid), + sizeof(xpanid), nullptr); + SuccessOrDie(error, "cannot publish the first service"); + + error = sContext.mPublisher->PublishService(hostName1, 12345, "MultipleService12", "_meshcop._udp.", "nn", + "cool", sizeof("cool") - 1, "xp", reinterpret_cast(&xpanid), + sizeof(xpanid), nullptr); + SuccessOrDie(error, "cannot publish the second service"); + + error = sContext.mPublisher->PublishHost(hostName2, hostAddr, sizeof(hostAddr)); + SuccessOrDie(error, "cannot publish the second host"); + + error = sContext.mPublisher->PublishService(hostName2, 12345, "MultipleService21", "_meshcop._udp.", "nn", + "cool", sizeof("cool") - 1, "xp", reinterpret_cast(&xpanid), + sizeof(xpanid), nullptr); + SuccessOrDie(error, "cannot publish the first service"); + + error = sContext.mPublisher->PublishService(hostName2, 12345, "MultipleService22", "_meshcop._udp.", "nn", + "cool", sizeof("cool") - 1, "xp", reinterpret_cast(&xpanid), + sizeof(xpanid), nullptr); + SuccessOrDie(error, "cannot publish the second service"); + } +} + void PublishSingleService(void *aContext, Mdns::State aState) { uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; @@ -87,9 +156,9 @@ void PublishSingleService(void *aContext, Mdns::State aState) assert(aContext == &sContext); if (aState == Mdns::kStateReady) { - otbrError err = sContext.mPublisher->PublishService(12345, "SingleService", "_meshcop._udp.", "nn", "cool", - sizeof("cool") - 1, "xp", reinterpret_cast(&xpanid), - sizeof(xpanid), nullptr); + otbrError err = sContext.mPublisher->PublishService(nullptr, 12345, "SingleService", "_meshcop._udp.", "nn", + "cool", sizeof("cool") - 1, "xp", + reinterpret_cast(&xpanid), sizeof(xpanid), nullptr); assert(err == OTBR_ERROR_NONE); } @@ -102,12 +171,12 @@ void PublishMultipleServices(void *aContext, Mdns::State aState) assert(aContext == &sContext); if (aState == Mdns::kStateReady) { - otbrError err = sContext.mPublisher->PublishService(12345, "MultipleService1", "_meshcop._udp.", "nn", "cool1", - sizeof("cool1") - 1, "xp", + otbrError err = sContext.mPublisher->PublishService(nullptr, 12345, "MultipleService1", "_meshcop._udp.", "nn", + "cool1", sizeof("cool1") - 1, "xp", reinterpret_cast(&xpanid), sizeof(xpanid), nullptr); assert(err == OTBR_ERROR_NONE); - err = sContext.mPublisher->PublishService(12345, "MultipleService2", "_meshcop._udp.", "nn", "cool2", + err = sContext.mPublisher->PublishService(nullptr, 12345, "MultipleService2", "_meshcop._udp.", "nn", "cool2", sizeof("cool1") - 1, "xp", reinterpret_cast(&xpanid), sizeof(xpanid), nullptr); assert(err == OTBR_ERROR_NONE); @@ -126,25 +195,55 @@ void PublishUpdateServices(void *aContext, Mdns::State aState) if (!sContext.mUpdate) { - err = sContext.mPublisher->PublishService(12345, "UpdateService", "_meshcop._udp.", "nn", "cool", + err = sContext.mPublisher->PublishService(nullptr, 12345, "UpdateService", "_meshcop._udp.", "nn", "cool", sizeof("cool") - 1, "xp", reinterpret_cast(&xpanidOld), sizeof(xpanidOld), nullptr); } else { - err = sContext.mPublisher->PublishService(12345, "UpdateService", "_meshcop._udp.", "nn", "coolcool", - sizeof("coolcool") - 1, "xp", + err = sContext.mPublisher->PublishService(nullptr, 12345, "UpdateService", "_meshcop._udp.", "nn", + "coolcool", sizeof("coolcool") - 1, "xp", reinterpret_cast(&xpanidNew), sizeof(xpanidNew), nullptr); } assert(err == OTBR_ERROR_NONE); } } +otbrError TestSingleServiceWithCustomHost(void) +{ + otbrError error = OTBR_ERROR_NONE; + + Mdns::Publisher *pub = + Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishSingleServiceWithCustomHost, &sContext); + sContext.mPublisher = pub; + SuccessOrExit(error = pub->Start()); + Mainloop(*pub); + +exit: + Mdns::Publisher::Destroy(pub); + return error; +} + +otbrError TestMultipleServicesWithCustomHost(void) +{ + otbrError error = OTBR_ERROR_NONE; + + Mdns::Publisher *pub = + Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishMultipleServicesWithCustomHost, &sContext); + sContext.mPublisher = pub; + SuccessOrExit(error = pub->Start()); + Mainloop(*pub); + +exit: + Mdns::Publisher::Destroy(pub); + return error; +} + otbrError TestSingleService(void) { otbrError ret = OTBR_ERROR_NONE; - Mdns::Publisher *pub = Mdns::Publisher::Create(AF_UNSPEC, nullptr, nullptr, PublishSingleService, &sContext); + Mdns::Publisher *pub = Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishSingleService, &sContext); sContext.mPublisher = pub; SuccessOrExit(ret = pub->Start()); Mainloop(*pub); @@ -158,8 +257,9 @@ otbrError TestMultipleServices(void) { otbrError ret = OTBR_ERROR_NONE; - Mdns::Publisher *pub = Mdns::Publisher::Create(AF_UNSPEC, nullptr, nullptr, PublishMultipleServices, &sContext); - sContext.mPublisher = pub; + Mdns::Publisher *pub = + Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishMultipleServices, &sContext); + sContext.mPublisher = pub; SuccessOrExit(ret = pub->Start()); Mainloop(*pub); @@ -172,7 +272,7 @@ otbrError TestUpdateService(void) { otbrError ret = OTBR_ERROR_NONE; - Mdns::Publisher *pub = Mdns::Publisher::Create(AF_UNSPEC, nullptr, nullptr, PublishUpdateServices, &sContext); + Mdns::Publisher *pub = Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishUpdateServices, &sContext); sContext.mPublisher = pub; sContext.mUpdate = false; SuccessOrExit(ret = pub->Start()); @@ -201,7 +301,7 @@ otbrError TestStopService(void) { otbrError ret = OTBR_ERROR_NONE; - Mdns::Publisher *pub = Mdns::Publisher::Create(AF_UNSPEC, nullptr, nullptr, PublishSingleService, &sContext); + Mdns::Publisher *pub = Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, PublishSingleService, &sContext); sContext.mPublisher = pub; SuccessOrExit(ret = pub->Start()); signal(SIGUSR1, RecoverSignal); @@ -232,11 +332,11 @@ int main(int argc, char *argv[]) switch (argv[1][0]) { case 's': - ret = TestSingleService(); + ret = argv[1][1] == 'c' ? TestSingleServiceWithCustomHost() : TestSingleService(); break; case 'm': - ret = TestMultipleServices(); + ret = argv[1][1] == 'c' ? TestMultipleServicesWithCustomHost() : TestMultipleServices(); break; case 'u': diff --git a/tests/mdns/test-multiple-custom-hosts b/tests/mdns/test-multiple-custom-hosts new file mode 100755 index 00000000000..49db9cc0d79 --- /dev/null +++ b/tests/mdns/test-multiple-custom-hosts @@ -0,0 +1,55 @@ +#!/bin/bash +# +# 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. +# + +# +# This script tests publishing single service with custom host name & address. +# + +# shellcheck source=tests/mdns/test_init +. "$(dirname "$0")/test_init" + +main() +{ + if [[ ${OTBR_MDNS} == 'mDNSResponder' ]]; then + start_publisher mc + + dns_sd_check MultipleService11 _meshcop._udp 'custom-host-1.local.' + dns_sd_check MultipleService12 _meshcop._udp 'custom-host-1.local.' + dns_sd_check_host 'custom-host-1.local.' '2002:0000:0000:0000:0000:0000:0000:0001' + + dns_sd_check MultipleService21 _meshcop._udp 'custom-host-2.local.' + dns_sd_check MultipleService22 _meshcop._udp 'custom-host-2.local.' + dns_sd_check_host 'custom-host-2.local.' '2002:0000:0000:0000:0000:0000:0000:0001' + else + #TODO: + echo "not implemented yet" + fi +} + +main "$@" diff --git a/tests/mdns/test-single-custom-host b/tests/mdns/test-single-custom-host new file mode 100755 index 00000000000..777a26857c7 --- /dev/null +++ b/tests/mdns/test-single-custom-host @@ -0,0 +1,50 @@ +#!/bin/bash +# +# 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. +# + +# +# This script tests publishing single service with custom host name & address. +# + +# shellcheck source=tests/mdns/test_init +. "$(dirname "$0")/test_init" + +main() +{ + if [[ ${OTBR_MDNS} == 'mDNSResponder' ]]; then + start_publisher sc + + dns_sd_check SingleService _meshcop._udp 'custom-host.local.' + dns_sd_check_host 'custom-host.local.' '2002:0000:0000:0000:0000:0000:0000:0001' + else + #TODO: + echo "not implemented yet" + fi +} + +main "$@" diff --git a/tests/mdns/test_init b/tests/mdns/test_init index eb050e24324..47edff24f72 100644 --- a/tests/mdns/test_init +++ b/tests/mdns/test_init @@ -97,6 +97,29 @@ dns_sd_check() grep "$3" "${DNS_SD_RESULT}" } +####################################### +# Check if a host is regisered +# +# Arguments: +# $1 hostname +# $2 address +# +# Returns: +# 0 Registered +# otherwise Not registered +####################################### +dns_sd_check_host() +{ + # dns-sd will not exit + dns-sd -G v6 "$1" >"${DNS_SD_RESULT}" 2>&1 & + DNS_SD_PID=$! + sleep 1 + kill "${DNS_SD_PID}" + + cat "${DNS_SD_RESULT}" + grep "$2" "${DNS_SD_RESULT}" +} + ####################################### # Check if a service is regisered # From dfa561eb72bef34f19221c56ef07a5d67c9eceab Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Tue, 5 Jan 2021 01:02:17 +0800 Subject: [PATCH 051/175] [dbus] add dbus api to get/set radio region (#668) --- src/dbus/client/thread_api_dbus.cpp | 10 +++++++ src/dbus/client/thread_api_dbus.hpp | 24 ++++++++++++++++ src/dbus/common/constants.hpp | 1 + src/dbus/server/dbus_thread_object.cpp | 39 ++++++++++++++++++++++++++ src/dbus/server/dbus_thread_object.hpp | 2 ++ src/dbus/server/introspect.xml | 4 +++ tests/dbus/test_dbus_client.cpp | 5 ++++ 7 files changed, 85 insertions(+) diff --git a/src/dbus/client/thread_api_dbus.cpp b/src/dbus/client/thread_api_dbus.cpp index c8bf8806825..5de5955b29a 100644 --- a/src/dbus/client/thread_api_dbus.cpp +++ b/src/dbus/client/thread_api_dbus.cpp @@ -403,6 +403,11 @@ ClientError ThreadApiDBus::SetLinkMode(const LinkModeConfig &aConfig) return SetProperty(OTBR_DBUS_PROPERTY_LINK_MODE, aConfig); } +ClientError ThreadApiDBus::SetRadioRegion(const std::string &aRadioRegion) +{ + return SetProperty(OTBR_DBUS_PROPERTY_RADIO_REGION, aRadioRegion); +} + ClientError ThreadApiDBus::GetLinkMode(LinkModeConfig &aConfig) { return GetProperty(OTBR_DBUS_PROPERTY_LINK_MODE, aConfig); @@ -544,6 +549,11 @@ ClientError ThreadApiDBus::GetActiveDatasetTlvs(std::vector &aDataset) return GetProperty(OTBR_DBUS_PROPERTY_ACTIVE_DATASET_TLVS, aDataset); } +ClientError ThreadApiDBus::GetRadioRegion(std::string &aRadioRegion) +{ + return GetProperty(OTBR_DBUS_PROPERTY_RADIO_REGION, aRadioRegion); +} + std::string ThreadApiDBus::GetInterfaceName(void) { return mInterfaceName; diff --git a/src/dbus/client/thread_api_dbus.hpp b/src/dbus/client/thread_api_dbus.hpp index 4dfc65e636e..a90816bf8d0 100644 --- a/src/dbus/client/thread_api_dbus.hpp +++ b/src/dbus/client/thread_api_dbus.hpp @@ -294,6 +294,18 @@ class ThreadApiDBus */ ClientError SetLinkMode(const LinkModeConfig &aConfig); + /** + * This method sets the radio region. + * + * @param[in] aRadioRegion The radio region. + * + * @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 gets the link operating mode. * @@ -619,6 +631,18 @@ class ThreadApiDBus */ ClientError GetActiveDatasetTlvs(std::vector &aDataset); + /** + * This method gets the radio region. + * + * @param[out] aRadioRegion The radio region. + * + * @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); + /** * This method returns the network interface name the client is bound to. * diff --git a/src/dbus/common/constants.hpp b/src/dbus/common/constants.hpp index 2de929338e0..5df9b3e3cfc 100644 --- a/src/dbus/common/constants.hpp +++ b/src/dbus/common/constants.hpp @@ -80,6 +80,7 @@ #define OTBR_DBUS_PROPERTY_RADIO_TX_POWER "RadioTxPower" #define OTBR_DBUS_PROPERTY_EXTERNAL_ROUTES "ExternalRoutes" #define OTBR_DBUS_PROPERTY_ACTIVE_DATASET_TLVS "ActiveDatasetTlvs" +#define OTBR_DBUS_PROPERTY_RADIO_REGION "RadioRegion" #define OTBR_ROLE_NAME_DISABLED "disabled" #define OTBR_ROLE_NAME_DETACHED "detached" diff --git a/src/dbus/server/dbus_thread_object.cpp b/src/dbus/server/dbus_thread_object.cpp index d88c8adeb66..a28580f5439 100644 --- a/src/dbus/server/dbus_thread_object.cpp +++ b/src/dbus/server/dbus_thread_object.cpp @@ -141,6 +141,8 @@ otbrError DBusThreadObject::Init(void) std::bind(&DBusThreadObject::SetLinkModeHandler, this, _1)); RegisterSetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_ACTIVE_DATASET_TLVS, std::bind(&DBusThreadObject::SetActiveDatasetTlvsHandler, this, _1)); + RegisterSetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_RADIO_REGION, + std::bind(&DBusThreadObject::SetRadioRegionHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_LINK_MODE, std::bind(&DBusThreadObject::GetLinkModeHandler, this, _1)); @@ -197,6 +199,8 @@ otbrError DBusThreadObject::Init(void) std::bind(&DBusThreadObject::GetExternalRoutesHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_ACTIVE_DATASET_TLVS, std::bind(&DBusThreadObject::GetActiveDatasetTlvsHandler, this, _1)); + RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_RADIO_REGION, + std::bind(&DBusThreadObject::GetRadioRegionHandler, this, _1)); return error; } @@ -1002,5 +1006,40 @@ otError DBusThreadObject::GetActiveDatasetTlvsHandler(DBusMessageIter &aIter) return error; } +otError DBusThreadObject::SetRadioRegionHandler(DBusMessageIter &aIter) +{ + auto threadHelper = mNcp->GetThreadHelper(); + std::string radioRegion; + uint16_t regionCode; + otError error = OT_ERROR_NONE; + + VerifyOrExit(DBusMessageExtractFromVariant(&aIter, radioRegion) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); + VerifyOrExit(radioRegion.size() == sizeof(uint16_t), error = OT_ERROR_INVALID_ARGS); + regionCode = radioRegion[0] << 8 | radioRegion[1]; + + error = otPlatRadioSetRegion(threadHelper->GetInstance(), regionCode); + +exit: + return error; +} + +otError DBusThreadObject::GetRadioRegionHandler(DBusMessageIter &aIter) +{ + auto threadHelper = mNcp->GetThreadHelper(); + otError error = OT_ERROR_NONE; + std::string radioRegion; + uint16_t regionCode; + + SuccessOrExit(error = otPlatRadioGetRegion(threadHelper->GetInstance(), ®ionCode)); + radioRegion.resize(sizeof(uint16_t), '\0'); + radioRegion[0] = static_cast((regionCode >> 8) & 0xff); + radioRegion[1] = static_cast(regionCode & 0xff); + + VerifyOrExit(DBusMessageEncodeToVariant(&aIter, radioRegion) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); + +exit: + return error; +} + } // namespace DBus } // namespace otbr diff --git a/src/dbus/server/dbus_thread_object.hpp b/src/dbus/server/dbus_thread_object.hpp index e59997e466a..f860688a9ae 100644 --- a/src/dbus/server/dbus_thread_object.hpp +++ b/src/dbus/server/dbus_thread_object.hpp @@ -87,6 +87,7 @@ class DBusThreadObject : public DBusObject otError SetLegacyUlaPrefixHandler(DBusMessageIter &aIter); otError SetLinkModeHandler(DBusMessageIter &aIter); otError SetActiveDatasetTlvsHandler(DBusMessageIter &aIter); + otError SetRadioRegionHandler(DBusMessageIter &aIter); otError GetLinkModeHandler(DBusMessageIter &aIter); otError GetDeviceRoleHandler(DBusMessageIter &aIter); @@ -115,6 +116,7 @@ class DBusThreadObject : public DBusObject otError GetRadioTxPowerHandler(DBusMessageIter &aIter); otError GetExternalRoutesHandler(DBusMessageIter &aIter); otError GetActiveDatasetTlvsHandler(DBusMessageIter &aIter); + otError GetRadioRegionHandler(DBusMessageIter &aIter); void ReplyScanResult(DBusRequest &aRequest, otError aError, const std::vector &aResult); diff --git a/src/dbus/server/introspect.xml b/src/dbus/server/introspect.xml index da4193487f3..03d1db12c64 100644 --- a/src/dbus/server/introspect.xml +++ b/src/dbus/server/introspect.xml @@ -341,6 +341,10 @@ + + + + diff --git a/tests/dbus/test_dbus_client.cpp b/tests/dbus/test_dbus_client.cpp index 1d34810bbb4..cc2c448738f 100644 --- a/tests/dbus/test_dbus_client.cpp +++ b/tests/dbus/test_dbus_client.cpp @@ -99,6 +99,7 @@ int main() UniqueDBusConnection connection; std::unique_ptr api; uint64_t extpanid = 0xdead00beaf00cafe; + std::string region; dbus_error_init(&error); connection = UniqueDBusConnection(dbus_bus_get(DBUS_BUS_SYSTEM, &error)); @@ -112,6 +113,10 @@ int main() api->AddDeviceRoleHandler( [](DeviceRole aRole) { printf("Device role changed to %d\n", static_cast(aRole)); }); + TEST_ASSERT(api->SetRadioRegion("US") == ClientError::ERROR_NONE); + TEST_ASSERT(api->GetRadioRegion(region) == ClientError::ERROR_NONE); + TEST_ASSERT(region == "US"); + api->Scan([&api, extpanid](const std::vector &aResult) { LinkModeConfig cfg = {true, false, true}; std::vector masterKey = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, From 07145f02b6ddafb5efb0b26442710fc491059259 Mon Sep 17 00:00:00 2001 From: kangping Date: Wed, 6 Jan 2021 04:10:28 +0800 Subject: [PATCH 052/175] [mdns] accept a list of TXT entries (#669) In cases the TXT record can not be determined at compile time (for services from Thread end devices, arbitrary TXT records may be provided at runtime), we need to support specifying a list of TXT name/value entries. --- src/agent/border_agent.cpp | 18 +++---- src/agent/border_agent.hpp | 4 +- src/mdns/mdns.hpp | 78 ++++++++++++++++++++---------- src/mdns/mdns_avahi.cpp | 33 ++++++------- src/mdns/mdns_avahi.hpp | 9 ++-- src/mdns/mdns_mdnssd.cpp | 38 +++++++-------- src/mdns/mdns_mdnssd.hpp | 9 ++-- tests/mdns/main.cpp | 98 ++++++++++++++++++-------------------- 8 files changed, 152 insertions(+), 135 deletions(-) diff --git a/src/agent/border_agent.cpp b/src/agent/border_agent.cpp index 60ba46b6388..ff8be291773 100644 --- a/src/agent/border_agent.cpp +++ b/src/agent/border_agent.cpp @@ -161,11 +161,11 @@ BorderAgent::~BorderAgent(void) } } -void BorderAgent::HandleMdnsState(Mdns::State aState) +void BorderAgent::HandleMdnsState(Mdns::Publisher::State aState) { switch (aState) { - case Mdns::kStateReady: + case Mdns::Publisher::State::kReady: PublishService(); break; default: @@ -217,19 +217,15 @@ static const char *ThreadVersionToString(uint16_t aThreadVersion) void BorderAgent::PublishService(void) { - const char *versionString = ThreadVersionToString(mThreadVersion); - assert(mNetworkName[0] != '\0'); assert(mExtPanIdInitialized); - assert(mThreadVersion != 0); - // clang-format off + + const char * versionString = ThreadVersionToString(mThreadVersion); + Mdns::Publisher::TxtList txtList{{"nn", mNetworkName}, {"xp", mExtPanId, sizeof(mExtPanId)}, {"tv", versionString}}; + mPublisher->PublishService(/* aHostName */ nullptr, kBorderAgentUdpPort, mNetworkName, kBorderAgentServiceType, - "nn", mNetworkName, strlen(mNetworkName), - "xp", &mExtPanId, sizeof(mExtPanId), - "tv", versionString, strlen(versionString), - nullptr); - // clang-format on + txtList); } void BorderAgent::StartPublishService(void) diff --git a/src/agent/border_agent.hpp b/src/agent/border_agent.hpp index e7ca30ef67f..db49f5b133d 100644 --- a/src/agent/border_agent.hpp +++ b/src/agent/border_agent.hpp @@ -116,11 +116,11 @@ class BorderAgent */ void Stop(void); - static void HandleMdnsState(void *aContext, Mdns::State aState) + static void HandleMdnsState(void *aContext, Mdns::Publisher::State aState) { static_cast(aContext)->HandleMdnsState(aState); } - void HandleMdnsState(Mdns::State aState); + void HandleMdnsState(Mdns::Publisher::State aState); void PublishService(void); void StartPublishService(void); void StopPublishService(void); diff --git a/src/mdns/mdns.hpp b/src/mdns/mdns.hpp index a12bc3d513d..591d69c0905 100644 --- a/src/mdns/mdns.hpp +++ b/src/mdns/mdns.hpp @@ -34,6 +34,8 @@ #ifndef OTBR_AGENT_MDNS_HPP_ #define OTBR_AGENT_MDNS_HPP_ +#include + #include #include "common/types.hpp" @@ -42,25 +44,6 @@ namespace otbr { namespace Mdns { -/** - * MDNS state values. - * - */ -enum State -{ - kStateIdle, ///< Unable to publishing service. - kStateReady, ///< Ready for publishing service. -}; - -/** - * This function pointer is called when MDNS service state changed. - * - * @param[in] aContext A pointer to application-specific context. - * @param[in] aState The new state. - * - */ -typedef void (*StateHandler)(void *aContext, State aState); - /** * @addtogroup border-router-mdns * @@ -77,6 +60,50 @@ typedef void (*StateHandler)(void *aContext, State aState); class Publisher { public: + /** + * This structure represents a name/value pair of the TXT record. + * + */ + struct TxtEntry + { + const char * mName; ///< The name of the TXT entry. + const uint8_t *mValue; ///< The value of the TXT entry. + size_t mValueLength; ///< The length of the value of the TXT entry. + + TxtEntry(const char *aName, const char *aValue) + : TxtEntry(aName, reinterpret_cast(aValue), strlen(aValue)) + { + } + + TxtEntry(const char *aName, const uint8_t *aValue, size_t aValueLength) + : mName(aName) + , mValue(aValue) + , mValueLength(aValueLength) + { + } + }; + + typedef std::vector TxtList; + + /** + * MDNS state values. + * + */ + enum class State + { + kIdle, ///< Unable to publishing service. + kReady, ///< Ready for publishing service. + }; + + /** + * This function pointer is called when MDNS service state changed. + * + * @param[in] aContext A pointer to application-specific context. + * @param[in] aState The new state. + * + */ + typedef void (*StateHandler)(void *aContext, State aState); + /** * This method starts the MDNS service. * @@ -111,18 +138,17 @@ class Publisher * @param[in] aName The name of this service. * @param[in] aType The type of this service. * @param[in] aPort The port number of this service. - * @param[in] ... Pointers to null-terminated string of key and value for text record. - * The last argument must be nullptr. + * @param[in] aTxtList A list of TXT name/value pairs. * * @retval OTBR_ERROR_NONE Successfully published or updated the service. * @retval OTBR_ERROR_ERRNO Failed to publish or update the service. * */ - virtual otbrError PublishService(const char *aHostName, - uint16_t aPort, - const char *aName, - const char *aType, - ...) = 0; + virtual otbrError PublishService(const char * aHostName, + uint16_t aPort, + const char * aName, + const char * aType, + const TxtList &aTxtList) = 0; /** * This method un-publishes a service. diff --git a/src/mdns/mdns_avahi.cpp b/src/mdns/mdns_avahi.cpp index 191003ce5ed..c3e43a4710a 100644 --- a/src/mdns/mdns_avahi.cpp +++ b/src/mdns/mdns_avahi.cpp @@ -311,7 +311,7 @@ PublisherAvahi::PublisherAvahi(int aProtocol, const char *aDomain, StateHandler , mProtocol(aProtocol == AF_INET6 ? AVAHI_PROTO_INET6 : aProtocol == AF_INET ? AVAHI_PROTO_INET : AVAHI_PROTO_UNSPEC) , mDomain(aDomain) - , mState(kStateIdle) + , mState(State::kIdle) , mStateHandler(aHandler) , mContext(aContext) { @@ -361,7 +361,7 @@ void PublisherAvahi::Stop(void) avahi_client_free(mClient); mClient = nullptr; mGroup = nullptr; - mState = kStateIdle; + mState = State::kIdle; mStateHandler(mContext, mState); } } @@ -434,7 +434,7 @@ void PublisherAvahi::HandleClientState(AvahiClient *aClient, AvahiClientState aS /* The server has startup successfully and registered its host * name on the network, so it's time to create our services */ otbrLog(OTBR_LOG_INFO, "Avahi client ready."); - mState = kStateReady; + mState = State::kReady; CreateGroup(aClient); mStateHandler(mContext, mState); if (mGroup) @@ -445,7 +445,7 @@ void PublisherAvahi::HandleClientState(AvahiClient *aClient, AvahiClientState aS case AVAHI_CLIENT_FAILURE: otbrLog(OTBR_LOG_ERR, "Client failure: %s", avahi_strerror(avahi_client_errno(aClient))); - mState = kStateIdle; + mState = State::kIdle; mStateHandler(mContext, mState); break; @@ -492,11 +492,11 @@ void PublisherAvahi::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet mPoller.Process(aReadFdSet, aWriteFdSet, aErrorFdSet); } -otbrError PublisherAvahi::PublishService(const char *aHostName, - uint16_t aPort, - const char *aName, - const char *aType, - ...) +otbrError PublisherAvahi::PublishService(const char * aHostName, + uint16_t aPort, + const char * aName, + const char * aType, + const TxtList &aTxtList) { otbrError ret = OTBR_ERROR_ERRNO; int error = 0; @@ -504,20 +504,18 @@ otbrError PublisherAvahi::PublishService(const char *aHostName, AvahiStringList buffer[kMaxSizeOfTxtRecord / sizeof(AvahiStringList)]; AvahiStringList *last = nullptr; AvahiStringList *curr = buffer; - va_list args; size_t used = 0; - va_start(args, aType); - VerifyOrExit(aHostName == nullptr, ret = OTBR_ERROR_NOT_IMPLEMENTED); - VerifyOrExit(mState == kStateReady, errno = EAGAIN); + VerifyOrExit(mState == State::kReady, errno = EAGAIN); VerifyOrExit(mGroup != nullptr, ret = OTBR_ERROR_MDNS); - for (const char *name = va_arg(args, const char *); name; name = va_arg(args, const char *)) + for (const auto &txtEntry : aTxtList) { - int rval; - const char *value = va_arg(args, const char *); - size_t valueLength = va_arg(args, size_t); + int rval; + const char * name = txtEntry.mName; + const uint8_t *value = txtEntry.mValue; + size_t valueLength = txtEntry.mValueLength; // +1 for the size of "=", avahi doesn't need '\0' at the end of the entry size_t needed = sizeof(AvahiStringList) - sizeof(AvahiStringList::text) + strlen(name) + valueLength + 1; @@ -565,7 +563,6 @@ otbrError PublisherAvahi::PublishService(const char *aHostName, ret = OTBR_ERROR_NONE; exit: - va_end(args); if (error) { diff --git a/src/mdns/mdns_avahi.hpp b/src/mdns/mdns_avahi.hpp index e47750f2ac1..89daa269237 100644 --- a/src/mdns/mdns_avahi.hpp +++ b/src/mdns/mdns_avahi.hpp @@ -213,14 +213,17 @@ class PublisherAvahi : public Publisher * @param[in] aName The name of this service. * @param[in] aType The type of this service. * @param[in] aPort The port number of this service. - * @param[in] ... Pointers to null-terminated string of key and value for text record. - * The last argument must be nullptr. + * @param[in] aTxtList A list of TXT name/value pairs. * * @retval OTBR_ERROR_NONE Successfully published or updated the service. * @retval OTBR_ERROR_ERRNO Failed to publish or update the service. * */ - otbrError PublishService(const char *aHostName, uint16_t aPort, const char *aName, const char *aType, ...) override; + otbrError PublishService(const char * aHostName, + uint16_t aPort, + const char * aName, + const char * aType, + const TxtList &aTxtList) override; /** * This method un-publishes a service. diff --git a/src/mdns/mdns_mdnssd.cpp b/src/mdns/mdns_mdnssd.cpp index 480e47e6a1e..1494f7fc0d4 100644 --- a/src/mdns/mdns_mdnssd.cpp +++ b/src/mdns/mdns_mdnssd.cpp @@ -167,7 +167,7 @@ static const char *DNSErrorToString(DNSServiceErrorType aError) PublisherMDnsSd::PublisherMDnsSd(int aProtocol, const char *aDomain, StateHandler aHandler, void *aContext) : mHostsConnection(nullptr) , mDomain(aDomain) - , mState(kStateIdle) + , mState(State::kIdle) , mStateHandler(aHandler) , mContext(aContext) { @@ -181,19 +181,19 @@ PublisherMDnsSd::~PublisherMDnsSd(void) otbrError PublisherMDnsSd::Start(void) { - mState = kStateReady; - mStateHandler(mContext, kStateReady); + mState = State::kReady; + mStateHandler(mContext, State::kReady); return OTBR_ERROR_NONE; } bool PublisherMDnsSd::IsStarted(void) const { - return mState == kStateReady; + return mState == State::kReady; } void PublisherMDnsSd::Stop(void) { - VerifyOrExit(mState == kStateReady); + VerifyOrExit(mState == State::kReady); for (Services::iterator it = mServices.begin(); it != mServices.end(); ++it) { @@ -376,15 +376,14 @@ void PublisherMDnsSd::RecordService(const char *aName, const char *aType, DNSSer return; } -otbrError PublisherMDnsSd::PublishService(const char *aHostName, - uint16_t aPort, - const char *aName, - const char *aType, - ...) +otbrError PublisherMDnsSd::PublishService(const char * aHostName, + uint16_t aPort, + const char * aName, + const char * aType, + const TxtList &aTxtList) { otbrError ret = OTBR_ERROR_NONE; int error = 0; - va_list args; uint8_t txt[kMaxSizeOfTxtRecord]; uint8_t * cur = txt; DNSServiceRef serviceRef = nullptr; @@ -400,20 +399,19 @@ otbrError PublisherMDnsSd::PublishService(const char *aHostName, SuccessOrExit(error = MakeFullName(fullHostName, sizeof(fullHostName), aHostName)); } - va_start(args, aType); - - for (const char *name = va_arg(args, const char *); name; name = va_arg(args, const char *)) + for (const auto &txtEntry : aTxtList) { - const char * value = va_arg(args, const char *); - const size_t nameLength = strlen(name); - const size_t valueLength = va_arg(args, size_t); - size_t recordLength = nameLength + 1 + valueLength; + const char * name = txtEntry.mName; + const size_t nameLength = strlen(txtEntry.mName); + const uint8_t *value = txtEntry.mValue; + const size_t valueLength = txtEntry.mValueLength; + size_t recordLength = nameLength + 1 + valueLength; assert(nameLength > 0 && valueLength > 0 && recordLength < kMaxTextRecordSize); if (cur + recordLength >= txt + sizeof(txt)) { - otbrLog(OTBR_LOG_WARNING, "Skip text record too much long: %s=%s", name, value); + otbrLog(OTBR_LOG_WARNING, "Skip text record too much long: name=%s, entry-length=%zu", name, recordLength); continue; } @@ -431,8 +429,6 @@ otbrError PublisherMDnsSd::PublishService(const char *aHostName, cur += valueLength; } - va_end(args); - for (Services::iterator it = mServices.begin(); it != mServices.end(); ++it) { if (!strncmp(it->mName, aName, sizeof(it->mName)) && !strncmp(it->mType, aType, sizeof(it->mType))) diff --git a/src/mdns/mdns_mdnssd.hpp b/src/mdns/mdns_mdnssd.hpp index 601622a95d2..72d0b58a4d9 100644 --- a/src/mdns/mdns_mdnssd.hpp +++ b/src/mdns/mdns_mdnssd.hpp @@ -75,14 +75,17 @@ class PublisherMDnsSd : public Publisher * @param[in] aName The name of this service. * @param[in] aType The type of this service. * @param[in] aPort The port number of this service. - * @param[in] ... Pointers to null-terminated string of key and value for text record. - * The last argument must be nullptr. + * @param[in] aTxtList A list of TXT name/value pairs. * * @retval OTBR_ERROR_NONE Successfully published or updated the service. * @retval OTBR_ERROR_ERRNO Failed to publish or update the service. * */ - otbrError PublishService(const char *aHostName, uint16_t aPort, const char *aName, const char *aType, ...) override; + otbrError PublishService(const char * aHostName, + uint16_t aPort, + const char * aName, + const char * aType, + const TxtList &aTxtList) override; /** * This method un-publishes a service. diff --git a/tests/mdns/main.cpp b/tests/mdns/main.cpp index d169e09eaed..3b5368d5226 100644 --- a/tests/mdns/main.cpp +++ b/tests/mdns/main.cpp @@ -80,7 +80,7 @@ int Mainloop(Mdns::Publisher &aPublisher) return rval; } -void PublishSingleServiceWithCustomHost(void *aContext, Mdns::State aState) +void PublishSingleServiceWithCustomHost(void *aContext, Mdns::Publisher::State aState) { uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; uint8_t hostAddr[16] = {0}; @@ -91,21 +91,20 @@ void PublishSingleServiceWithCustomHost(void *aContext, Mdns::State aState) hostAddr[15] = 0x01; VerifyOrDie(aContext == &sContext, "unexpected context"); - if (aState == Mdns::kStateReady) + if (aState == Mdns::Publisher::State::kReady) { - otbrError error; + otbrError error; + Mdns::Publisher::TxtList txtList{{"nn", "cool"}, {"xp", xpanid, sizeof(xpanid)}}; error = sContext.mPublisher->PublishHost(hostName, hostAddr, sizeof(hostAddr)); SuccessOrDie(error, "cannot publish the host"); - error = sContext.mPublisher->PublishService(hostName, 12345, "SingleService", "_meshcop._udp.", "nn", "cool", - sizeof("cool") - 1, "xp", reinterpret_cast(&xpanid), - sizeof(xpanid), nullptr); + error = sContext.mPublisher->PublishService(hostName, 12345, "SingleService", "_meshcop._udp.", txtList); SuccessOrDie(error, "cannot publish the service"); } } -void PublishMultipleServicesWithCustomHost(void *aContext, Mdns::State aState) +void PublishMultipleServicesWithCustomHost(void *aContext, Mdns::Publisher::State aState) { uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; uint8_t hostAddr[16] = {0}; @@ -117,95 +116,92 @@ void PublishMultipleServicesWithCustomHost(void *aContext, Mdns::State aState) hostAddr[15] = 0x01; VerifyOrDie(aContext == &sContext, "unexpected context"); - if (aState == Mdns::kStateReady) + if (aState == Mdns::Publisher::State::kReady) { - otbrError error; + otbrError error; + Mdns::Publisher::TxtList txtList{{"nn", "cool"}, {"xp", xpanid, sizeof(xpanid)}}; error = sContext.mPublisher->PublishHost(hostName1, hostAddr, sizeof(hostAddr)); SuccessOrDie(error, "cannot publish the first host"); - error = sContext.mPublisher->PublishService(hostName1, 12345, "MultipleService11", "_meshcop._udp.", "nn", - "cool", sizeof("cool") - 1, "xp", reinterpret_cast(&xpanid), - sizeof(xpanid), nullptr); + error = sContext.mPublisher->PublishService(hostName1, 12345, "MultipleService11", "_meshcop._udp.", txtList); SuccessOrDie(error, "cannot publish the first service"); - error = sContext.mPublisher->PublishService(hostName1, 12345, "MultipleService12", "_meshcop._udp.", "nn", - "cool", sizeof("cool") - 1, "xp", reinterpret_cast(&xpanid), - sizeof(xpanid), nullptr); + error = sContext.mPublisher->PublishService(hostName1, 12345, "MultipleService12", "_meshcop._udp.", txtList); SuccessOrDie(error, "cannot publish the second service"); error = sContext.mPublisher->PublishHost(hostName2, hostAddr, sizeof(hostAddr)); SuccessOrDie(error, "cannot publish the second host"); - error = sContext.mPublisher->PublishService(hostName2, 12345, "MultipleService21", "_meshcop._udp.", "nn", - "cool", sizeof("cool") - 1, "xp", reinterpret_cast(&xpanid), - sizeof(xpanid), nullptr); + error = sContext.mPublisher->PublishService(hostName2, 12345, "MultipleService21", "_meshcop._udp.", txtList); SuccessOrDie(error, "cannot publish the first service"); - error = sContext.mPublisher->PublishService(hostName2, 12345, "MultipleService22", "_meshcop._udp.", "nn", - "cool", sizeof("cool") - 1, "xp", reinterpret_cast(&xpanid), - sizeof(xpanid), nullptr); + error = sContext.mPublisher->PublishService(hostName2, 12345, "MultipleService22", "_meshcop._udp.", txtList); SuccessOrDie(error, "cannot publish the second service"); } } -void PublishSingleService(void *aContext, Mdns::State aState) +void PublishSingleService(void *aContext, Mdns::Publisher::State aState) { - uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; + uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; + Mdns::Publisher::TxtList txtList{{"nn", "cool"}, {"xp", xpanid, sizeof(xpanid)}}; assert(aContext == &sContext); - if (aState == Mdns::kStateReady) + if (aState == Mdns::Publisher::State::kReady) { - otbrError err = sContext.mPublisher->PublishService(nullptr, 12345, "SingleService", "_meshcop._udp.", "nn", - "cool", sizeof("cool") - 1, "xp", - reinterpret_cast(&xpanid), sizeof(xpanid), nullptr); - - assert(err == OTBR_ERROR_NONE); + otbrError error = + sContext.mPublisher->PublishService(nullptr, 12345, "SingleService", "_meshcop._udp.", txtList); + assert(error == OTBR_ERROR_NONE); } } -void PublishMultipleServices(void *aContext, Mdns::State aState) +void PublishMultipleServices(void *aContext, Mdns::Publisher::State aState) { uint8_t xpanid[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; assert(aContext == &sContext); - if (aState == Mdns::kStateReady) + if (aState == Mdns::Publisher::State::kReady) + { + otbrError error; + Mdns::Publisher::TxtList txtList{{"nn", "cool1"}, {"xp", xpanid, sizeof(xpanid)}}; + + error = sContext.mPublisher->PublishService(nullptr, 12345, "MultipleService1", "_meshcop._udp.", txtList); + assert(error == OTBR_ERROR_NONE); + } + + if (aState == Mdns::Publisher::State::kReady) { - otbrError err = sContext.mPublisher->PublishService(nullptr, 12345, "MultipleService1", "_meshcop._udp.", "nn", - "cool1", sizeof("cool1") - 1, "xp", - reinterpret_cast(&xpanid), sizeof(xpanid), nullptr); - - assert(err == OTBR_ERROR_NONE); - err = sContext.mPublisher->PublishService(nullptr, 12345, "MultipleService2", "_meshcop._udp.", "nn", "cool2", - sizeof("cool1") - 1, "xp", reinterpret_cast(&xpanid), - sizeof(xpanid), nullptr); - assert(err == OTBR_ERROR_NONE); + otbrError error; + Mdns::Publisher::TxtList txtList{{"nn", "cool2"}, {"xp", xpanid, sizeof(xpanid)}}; + + error = sContext.mPublisher->PublishService(nullptr, 12345, "MultipleService2", "_meshcop._udp.", txtList); + assert(error == OTBR_ERROR_NONE); } } -void PublishUpdateServices(void *aContext, Mdns::State aState) +void PublishUpdateServices(void *aContext, Mdns::Publisher::State aState) { uint8_t xpanidOld[kSizeExtPanId] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48}; uint8_t xpanidNew[kSizeExtPanId] = {0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41}; assert(aContext == &sContext); - if (aState == Mdns::kStateReady) + if (aState == Mdns::Publisher::State::kReady) { - otbrError err; + otbrError error; if (!sContext.mUpdate) { - err = sContext.mPublisher->PublishService(nullptr, 12345, "UpdateService", "_meshcop._udp.", "nn", "cool", - sizeof("cool") - 1, "xp", reinterpret_cast(&xpanidOld), - sizeof(xpanidOld), nullptr); + Mdns::Publisher::TxtList txtList{{"nn", "cool"}, {"xp", xpanidOld, sizeof(xpanidOld)}}; + + error = sContext.mPublisher->PublishService(nullptr, 12345, "UpdateService", "_meshcop._udp.", txtList); } else { - err = sContext.mPublisher->PublishService(nullptr, 12345, "UpdateService", "_meshcop._udp.", "nn", - "coolcool", sizeof("coolcool") - 1, "xp", - reinterpret_cast(&xpanidNew), sizeof(xpanidNew), nullptr); + Mdns::Publisher::TxtList txtList{{"nn", "coolcool"}, {"xp", xpanidNew, sizeof(xpanidNew)}}; + + error = sContext.mPublisher->PublishService(nullptr, 12345, "UpdateService", "_meshcop._udp.", txtList); } - assert(err == OTBR_ERROR_NONE); + assert(error == OTBR_ERROR_NONE); } } @@ -277,7 +273,7 @@ otbrError TestUpdateService(void) sContext.mUpdate = false; SuccessOrExit(ret = pub->Start()); sContext.mUpdate = true; - PublishUpdateServices(&sContext, Mdns::kStateReady); + PublishUpdateServices(&sContext, Mdns::Publisher::State::kReady); Mainloop(*pub); exit: From 134497d8db082f09295bbeef45dbde9acbb4b89c Mon Sep 17 00:00:00 2001 From: Yakun Xu Date: Thu, 14 Jan 2021 01:41:00 +0800 Subject: [PATCH 053/175] [doc] generate documentation (#670) This commit automatically publishes the generated documentation to gh-pages branch. --- .github/workflows/documentation.yml | 63 ++ CMakeLists.txt | 5 + doc/CMakeLists.txt | 45 ++ doc/Doxyfile.in | 761 ++++++++++++++++-------- include/openthread-br/config.h | 4 + script/test | 15 + src/agent/thread_helper.hpp | 8 + src/common/byteswap.hpp | 5 + src/common/code_utils.hpp | 4 + src/common/logging.hpp | 4 + src/common/time.hpp | 5 + src/dbus/client/client_error.hpp | 5 + src/dbus/client/thread_api_dbus.hpp | 5 + src/dbus/common/constants.hpp | 5 + src/dbus/common/dbus_message_dump.hpp | 5 + src/dbus/common/dbus_message_helper.hpp | 5 + src/dbus/common/dbus_resources.hpp | 5 + src/dbus/common/error.hpp | 12 + src/dbus/common/types.hpp | 5 + src/dbus/server/dbus_agent.hpp | 5 + src/dbus/server/dbus_object.hpp | 5 + src/dbus/server/dbus_request.hpp | 5 + src/dbus/server/dbus_thread_object.hpp | 5 + src/dbus/server/error_helper.hpp | 5 + src/openwrt/ubus/otubus.hpp | 5 + src/utils/event_emitter.hpp | 5 + src/utils/strcpy_utils.hpp | 5 + src/web/web-service/ot_client.hpp | 6 + 28 files changed, 768 insertions(+), 244 deletions(-) create mode 100644 .github/workflows/documentation.yml create mode 100644 doc/CMakeLists.txt diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml new file mode 100644 index 00000000000..7e5f08245ca --- /dev/null +++ b/.github/workflows/documentation.yml @@ -0,0 +1,63 @@ +# +## Copyright (c) 2021, 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: Documentation + +on: + push: + branches: + - master + +jobs: + cancel-previous-runs: + runs-on: ubuntu-latest + steps: + - uses: rokroskar/workflow-run-cleanup-action@master + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + if: "github.ref != 'refs/heads/master'" + + doxygen: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Bootstrap + run: sudo apt-get install -y doxygen + - name: Generate + run: | + mkdir build-doc + cd build-doc + cmake -DBUILD_TESTING=OFF -DOTBR_DOC=ON .. + make doxygen + - name: Deploy + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./build-doc/doc/html diff --git a/CMakeLists.txt b/CMakeLists.txt index d708f856ea3..8bbde8c0fcc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,7 @@ option(OTBR_OPENWRT "Build OpenWrt support" OFF) option(OTBR_UNSECURE_JOIN "Enable unsecure joining" OFF) option(OTBR_WEB "Build Web GUI" OFF) option(OTBR_REST "Build Rest Server" OFF) +option(OTBR_DOC "Build documentation" OFF) if(NOT CMAKE_C_STANDARD) @@ -166,3 +167,7 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set(CPACK_PACKAGE_CONTACT "OpenThread Authors