diff --git a/.github/workflows/thread_control_api.yml b/.github/workflows/thread_control_api.yml new file mode 100644 index 00000000000..9cc65005af1 --- /dev/null +++ b/.github/workflows/thread_control_api.yml @@ -0,0 +1,64 @@ +# +# Copyright (c) 2024, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +name: ThreadControlApi + +on: + push: + branches-ignore: + - 'dependabot/**' + pull_request: + branches: + - 'main' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || (github.repository == 'openthread/ot-br-posix' && github.run_id) || github.ref }} + cancel-in-progress: true + +jobs: + + thread_control_api: + runs-on: ubuntu-latest + strategy: + fail-fast: false + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - name: Bootstrap + env: + BUILD_TARGET: "check" + OTBR_MDNS: "avahi" + run: tests/scripts/bootstrap.sh + - name: Build + env: + OTBR_MDNS: "avahi" + - name: Test Thread Control Apis + run: OTBR_VERBOSE=${RUNNER_DEBUG:-0} script/test thread_control_api + - name: Codecov + uses: codecov/codecov-action@v4 diff --git a/script/test b/script/test index 93f642cb530..beb38cb3e3d 100755 --- a/script/test +++ b/script/test @@ -242,6 +242,9 @@ main() simulation) do_simulation ;; + thread_control_api) + top_builddir="${OTBR_TOP_BUILDDIR}" print_result ./tests/scripts/thread_control_api + ;; package) do_package ;; diff --git a/src/agent/application.cpp b/src/agent/application.cpp index 16f4082d6ac..cc74189585d 100644 --- a/src/agent/application.cpp +++ b/src/agent/application.cpp @@ -40,6 +40,8 @@ #include "agent/application.hpp" #include "common/code_utils.hpp" #include "common/mainloop_manager.hpp" +#include "ncp/controller_openthread_ncp.hpp" +#include "ncp/controller_openthread_rcp.hpp" #include "utils/infra_link_selector.hpp" namespace otbr { @@ -49,8 +51,6 @@ const struct timeval Application::kPollTimeout = {10, 0}; Application::Application(const std::string &aInterfaceName, const std::vector &aBackboneInterfaceNames, - const std::vector &aRadioUrls, - bool aEnableAutoAttach, const std::string &aRestListenAddress, int aRestListenPort) : mInterfaceName(aInterfaceName) @@ -60,33 +60,33 @@ Application::Application(const std::string &aInterfaceName, #else , mBackboneInterfaceName(aBackboneInterfaceNames.empty() ? "" : aBackboneInterfaceNames.front()) #endif - , mNcp(mInterfaceName.c_str(), aRadioUrls, mBackboneInterfaceName, /* aDryRun */ false, aEnableAutoAttach) + , mCtrlr(nullptr) #if OTBR_ENABLE_MDNS , mPublisher(Mdns::Publisher::Create([this](Mdns::Publisher::State aState) { this->HandleMdnsState(aState); })) #endif #if OTBR_ENABLE_BORDER_AGENT - , mBorderAgent(mNcp, *mPublisher) + , mBorderAgent(*mPublisher) #endif #if OTBR_ENABLE_BACKBONE_ROUTER - , mBackboneAgent(mNcp, aInterfaceName, mBackboneInterfaceName) + , mBackboneAgent(aInterfaceName, mBackboneInterfaceName) #endif #if OTBR_ENABLE_SRP_ADVERTISING_PROXY - , mAdvertisingProxy(mNcp, *mPublisher) + , mAdvertisingProxy(*mPublisher) #endif #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY - , mDiscoveryProxy(mNcp, *mPublisher) + , mDiscoveryProxy(*mPublisher) #endif #if OTBR_ENABLE_TREL - , mTrelDnssd(mNcp, *mPublisher) + , mTrelDnssd(*mPublisher) #endif #if OTBR_ENABLE_OPENWRT - , mUbusAgent(mNcp) + , mUbusAgent() #endif #if OTBR_ENABLE_REST_SERVER - , mRestWebServer(mNcp, aRestListenAddress, aRestListenPort) + , mRestWebServer(aRestListenAddress, aRestListenPort) #endif #if OTBR_ENABLE_DBUS_SERVER && OTBR_ENABLE_BORDER_AGENT - , mDBusAgent(mNcp, *mPublisher) + , mDBusAgent(*mPublisher) #endif #if OTBR_ENABLE_VENDOR_SERVER , mVendorServer(vendor::VendorServer::newInstance(*this)) @@ -96,9 +96,31 @@ Application::Application(const std::string &aInterfaceName, OTBR_UNUSED_VARIABLE(aRestListenPort); } -void Application::Init(void) +void Application::Init(const std::vector &aRadioUrls, bool aEnableAutoAttach) + +{ + mCtrlr = Ncp::IControllerOpenThread::CreateInstance(mInterfaceName.c_str(), aRadioUrls, mBackboneInterfaceName, + false, aEnableAutoAttach); + mCtrlr->Init(); + + if (mCtrlr->GetCoprocessorType() == OT_COPROCESSOR_RCP) + { + InitRcpMode(); + } + else if (mCtrlr->GetCoprocessorType() == OT_COPROCESSOR_NCP) + { + InitNcpMode(); + } +} + +void Application::InitRcpMode(void) { - mNcp.Init(); + Ncp::ControllerOpenThreadRcp *ctrlrRcp = static_cast(mCtrlr); + + mBorderAgent.Init(ctrlrRcp); +#if OTBR_ENABLE_DBUS_SERVER + mDBusAgent.Init(ctrlrRcp); +#endif #if OTBR_ENABLE_MDNS mPublisher->Start(); @@ -113,44 +135,56 @@ void Application::Init(void) #endif #endif #if OTBR_ENABLE_BACKBONE_ROUTER - mBackboneAgent.Init(); + mBackboneAgent.Init(ctrlrRcp); #endif #if OTBR_ENABLE_SRP_ADVERTISING_PROXY + mAdvertisingProxy.Init(ctrlrRcp); mAdvertisingProxy.SetEnabled(true); #endif #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY + mDiscoveryProxy.Init(ctrlrRcp); mDiscoveryProxy.SetEnabled(true); #endif +#if OTBR_ENABLE_TREL + mTrelDnssd.Init(ctrlrRcp); +#endif #if OTBR_ENABLE_OPENWRT - mUbusAgent.Init(); + mUbusAgent.Init(ctrlrRcp); #endif #if OTBR_ENABLE_REST_SERVER - mRestWebServer.Init(); -#endif -#if OTBR_ENABLE_DBUS_SERVER - mDBusAgent.Init(); + mRestWebServer.Init(ctrlrRcp); #endif #if OTBR_ENABLE_VENDOR_SERVER mVendorServer->Init(); #endif } +void Application::InitNcpMode(void) +{ +#if OTBR_ENABLE_DBUS_SERVER + mDBusAgent.Init(mCtrlr); +#endif +} + void Application::Deinit(void) { + if (mCtrlr->GetCoprocessorType() == OT_COPROCESSOR_RCP) + { #if OTBR_ENABLE_SRP_ADVERTISING_PROXY - mAdvertisingProxy.SetEnabled(false); + mAdvertisingProxy.SetEnabled(false); #endif #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY - mDiscoveryProxy.SetEnabled(false); + mDiscoveryProxy.SetEnabled(false); #endif #if OTBR_ENABLE_BORDER_AGENT - mBorderAgent.SetEnabled(false); + mBorderAgent.SetEnabled(false); #endif #if OTBR_ENABLE_MDNS - mPublisher->Stop(); + mPublisher->Stop(); #endif + } - mNcp.Deinit(); + mCtrlr->Deinit(); } otbrError Application::Run(void) diff --git a/src/agent/application.hpp b/src/agent/application.hpp index 2f92d69438f..e336f3a01a3 100644 --- a/src/agent/application.hpp +++ b/src/agent/application.hpp @@ -44,7 +44,7 @@ #if OTBR_ENABLE_BORDER_AGENT #include "border_agent/border_agent.hpp" #endif -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread.hpp" #if OTBR_ENABLE_BACKBONE_ROUTER #include "backbone_router/backbone_agent.hpp" #endif @@ -93,24 +93,23 @@ class Application : private NonCopyable * * @param[in] aInterfaceName Name of the Thread network interface. * @param[in] aBackboneInterfaceName Name of the backbone network interface. - * @param[in] aRadioUrls The radio URLs (can be IEEE802.15.4 or TREL radio). - * @param[in] aEnableAutoAttach Whether or not to automatically attach to the saved network. * @param[in] aRestListenAddress Network address to listen on. * @param[in] aRestListenPort Network port to listen on. * */ explicit Application(const std::string &aInterfaceName, const std::vector &aBackboneInterfaceNames, - const std::vector &aRadioUrls, - bool aEnableAutoAttach, const std::string &aRestListenAddress, int aRestListenPort); /** * This method initializes the Application instance. * + * @param[in] aRadioUrls The radio URLs (can be IEEE802.15.4 or TREL radio). + * @param[in] aEnableAutoAttach Whether or not to automatically attach to the saved network. + * */ - void Init(void); + void Init(const std::vector &aRadioUrls, bool aEnableAutoAttach); /** * This method de-initializes the Application instance. @@ -127,13 +126,6 @@ class Application : private NonCopyable */ otbrError Run(void); - /** - * Get the OpenThread controller object the application is using. - * - * @returns The OpenThread controller object. - */ - Ncp::ControllerOpenThread &GetNcp(void) { return mNcp; } - #if OTBR_ENABLE_MDNS /** * Get the Publisher object the application is using. @@ -256,12 +248,15 @@ class Application : private NonCopyable static void HandleSignal(int aSignal); + void InitRcpMode(void); + void InitNcpMode(void); + std::string mInterfaceName; #if __linux__ otbr::Utils::InfraLinkSelector mInfraLinkSelector; #endif - const char *mBackboneInterfaceName; - Ncp::ControllerOpenThread mNcp; + const char *mBackboneInterfaceName; + Ncp::IControllerOpenThread *mCtrlr; #if OTBR_ENABLE_MDNS std::unique_ptr mPublisher; #endif diff --git a/src/agent/main.cpp b/src/agent/main.cpp index 776c3e7229b..3f74b22143e 100644 --- a/src/agent/main.cpp +++ b/src/agent/main.cpp @@ -56,7 +56,7 @@ #include "common/logging.hpp" #include "common/mainloop.hpp" #include "common/types.hpp" -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread_rcp.hpp" static const char kDefaultInterfaceName[] = "wpan0"; @@ -176,17 +176,20 @@ static otbrLogLevel GetDefaultLogLevel(void) static void PrintRadioVersionAndExit(const std::vector &aRadioUrls) { - otbr::Ncp::ControllerOpenThread ncpOpenThread{/* aInterfaceName */ "", aRadioUrls, /* aBackboneInterfaceName */ "", - /* aDryRun */ true, /* aEnableAutoAttach */ false}; - const char *radioVersion; + otbr::Ncp::IControllerOpenThread *ctrlr = + otbr::Ncp::IControllerOpenThread::CreateInstance(/* aInterfaceName */ "", aRadioUrls, + /* aBackboneInterfaceName */ "", + /* aDryRun */ true, /* aEnableAutoAttach */ false); + const char *coprocessorVersion; - ncpOpenThread.Init(); + ctrlr->Init(); - radioVersion = otPlatRadioGetVersionString(ncpOpenThread.GetInstance()); - otbrLogNotice("Radio version: %s", radioVersion); - printf("%s\n", radioVersion); + coprocessorVersion = ctrlr->GetCoprocessorVersion(); + otbrLogNotice("Co-processor version: %s", coprocessorVersion); + printf("%s\n", coprocessorVersion); - ncpOpenThread.Deinit(); + ctrlr->Deinit(); + delete ctrlr; exit(EXIT_SUCCESS); } @@ -279,7 +282,12 @@ static int realmain(int argc, char *argv[]) otbrLogInit(argv[0], logLevel, verbose, syslogDisable); otbrLogNotice("Running %s", OTBR_PACKAGE_VERSION); - otbrLogNotice("Thread version: %s", otbr::Ncp::ControllerOpenThread::GetThreadVersion()); + // The version is a constant configured during compiling. At this moment, the co-processor type + // is not yet known. + // - If the co-processor type is RCP, the Thread version here will be the actual Thread version. + // - If the co-processor type is NCP, the actual Thread version will be later evaluated after + // initialization. The Thread version printed here may not equal to the actual Thread version. + otbrLogNotice("Thread version on host side: %s", otbr::Ncp::ControllerOpenThreadRcp::GetThreadVersion()); otbrLogNotice("Thread interface: %s", interfaceName); if (backboneInterfaceNames.empty()) @@ -300,11 +308,10 @@ static int realmain(int argc, char *argv[]) } { - otbr::Application app(interfaceName, backboneInterfaceNames, radioUrls, enableAutoAttach, restListenAddress, - restListenPort); + otbr::Application app(interfaceName, backboneInterfaceNames, restListenAddress, restListenPort); gApp = &app; - app.Init(); + app.Init(radioUrls, enableAutoAttach); ret = app.Run(); diff --git a/src/backbone_router/backbone_agent.cpp b/src/backbone_router/backbone_agent.cpp index fc79b8f58c2..53da34aad13 100644 --- a/src/backbone_router/backbone_agent.cpp +++ b/src/backbone_router/backbone_agent.cpp @@ -47,13 +47,11 @@ namespace otbr { namespace BackboneRouter { -BackboneAgent::BackboneAgent(otbr::Ncp::ControllerOpenThread &aNcp, - std::string aInterfaceName, - std::string aBackboneInterfaceName) - : mNcp(aNcp) +BackboneAgent::BackboneAgent(std::string aInterfaceName, std::string aBackboneInterfaceName) + : mCtrlr(nullptr) , mBackboneRouterState(OT_BACKBONE_ROUTER_STATE_DISABLED) #if OTBR_ENABLE_DUA_ROUTING - , mNdProxyManager(aNcp, aBackboneInterfaceName) + , mNdProxyManager(aBackboneInterfaceName) , mDuaRoutingManager(aInterfaceName, aBackboneInterfaceName) #endif { @@ -61,18 +59,20 @@ BackboneAgent::BackboneAgent(otbr::Ncp::ControllerOpenThread &aNcp, OTBR_UNUSED_VARIABLE(aBackboneInterfaceName); } -void BackboneAgent::Init(void) +void BackboneAgent::Init(Ncp::ControllerOpenThreadRcp *aCtrlr) { - mNcp.AddThreadStateChangedCallback([this](otChangedFlags aFlags) { HandleThreadStateChanged(aFlags); }); - otBackboneRouterSetDomainPrefixCallback(mNcp.GetInstance(), &BackboneAgent::HandleBackboneRouterDomainPrefixEvent, - this); + mCtrlr = aCtrlr; + + mCtrlr->AddThreadStateChangedCallback([this](otChangedFlags aFlags) { HandleThreadStateChanged(aFlags); }); + otBackboneRouterSetDomainPrefixCallback(mCtrlr->GetInstance(), + &BackboneAgent::HandleBackboneRouterDomainPrefixEvent, this); #if OTBR_ENABLE_DUA_ROUTING - otBackboneRouterSetNdProxyCallback(mNcp.GetInstance(), &BackboneAgent::HandleBackboneRouterNdProxyEvent, this); - mNdProxyManager.Init(); + otBackboneRouterSetNdProxyCallback(mCtrlr->GetInstance(), &BackboneAgent::HandleBackboneRouterNdProxyEvent, this); + mNdProxyManager.Init(mCtrlr); #endif #if OTBR_ENABLE_BACKBONE_ROUTER_ON_INIT - otBackboneRouterSetEnabled(mNcp.GetInstance(), /* aEnabled */ true); + otBackboneRouterSetEnabled(mCtrlr->GetInstance(), /* aEnabled */ true); #endif } @@ -86,7 +86,7 @@ void BackboneAgent::HandleThreadStateChanged(otChangedFlags aFlags) void BackboneAgent::HandleBackboneRouterState(void) { - otBackboneRouterState state = otBackboneRouterGetState(mNcp.GetInstance()); + otBackboneRouterState state = otBackboneRouterGetState(mCtrlr->GetInstance()); bool wasPrimary = (mBackboneRouterState == OT_BACKBONE_ROUTER_STATE_PRIMARY); otbrLogDebug("BackboneAgent: HandleBackboneRouterState: state=%d, mBackboneRouterState=%d", state, diff --git a/src/backbone_router/backbone_agent.hpp b/src/backbone_router/backbone_agent.hpp index c7566bccb9f..5ae449326b0 100644 --- a/src/backbone_router/backbone_agent.hpp +++ b/src/backbone_router/backbone_agent.hpp @@ -47,7 +47,7 @@ #include "backbone_router/dua_routing_manager.hpp" #include "backbone_router/nd_proxy.hpp" #include "common/code_utils.hpp" -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread_rcp.hpp" namespace otbr { namespace BackboneRouter { @@ -76,15 +76,13 @@ class BackboneAgent : private NonCopyable * @param[in] aNcp The Thread instance. * */ - BackboneAgent(otbr::Ncp::ControllerOpenThread &aNcp, - std::string aInterfaceName, - std::string aBackboneInterfaceName); + BackboneAgent(std::string aInterfaceName, std::string aBackboneInterfaceName); /** * This method initializes the Backbone agent. * */ - void Init(void); + void Init(Ncp::ControllerOpenThreadRcp *aCtrlr); private: void OnBecomePrimary(void); @@ -106,9 +104,9 @@ class BackboneAgent : private NonCopyable static const char *StateToString(otBackboneRouterState aState); - otbr::Ncp::ControllerOpenThread &mNcp; - otBackboneRouterState mBackboneRouterState; - Ip6Prefix mDomainPrefix; + otbr::Ncp::ControllerOpenThreadRcp *mCtrlr; + otBackboneRouterState mBackboneRouterState; + Ip6Prefix mDomainPrefix; #if OTBR_ENABLE_DUA_ROUTING NdProxyManager mNdProxyManager; DuaRoutingManager mDuaRoutingManager; diff --git a/src/backbone_router/dua_routing_manager.hpp b/src/backbone_router/dua_routing_manager.hpp index daf341df330..fd3097af5a1 100644 --- a/src/backbone_router/dua_routing_manager.hpp +++ b/src/backbone_router/dua_routing_manager.hpp @@ -43,7 +43,7 @@ #include #include "common/code_utils.hpp" -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread_rcp.hpp" #include "utils/system_utils.hpp" namespace otbr { diff --git a/src/backbone_router/nd_proxy.cpp b/src/backbone_router/nd_proxy.cpp index 15745654013..f370213761a 100644 --- a/src/backbone_router/nd_proxy.cpp +++ b/src/backbone_router/nd_proxy.cpp @@ -111,8 +111,10 @@ void NdProxyManager::Disable(void) otbrLogResult(error, "NdProxyManager: %s", __FUNCTION__); } -void NdProxyManager::Init(void) +void NdProxyManager::Init(Ncp::ControllerOpenThreadRcp *aCtrlr) { + mCtrlr = aCtrlr; + mBackboneIfIndex = if_nametoindex(mBackboneInterfaceName.c_str()); VerifyOrDie(mBackboneIfIndex > 0, "if_nametoindex failed"); } @@ -311,7 +313,7 @@ void NdProxyManager::SendNeighborAdvertisement(const Ip6Address &aTarget, const otbrError error = OTBR_ERROR_NONE; otBackboneRouterNdProxyInfo aNdProxyInfo; - VerifyOrExit(otBackboneRouterGetNdProxyInfo(mNcp.GetInstance(), reinterpret_cast(&aTarget), + VerifyOrExit(otBackboneRouterGetNdProxyInfo(mCtrlr->GetInstance(), reinterpret_cast(&aTarget), &aNdProxyInfo) == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD); diff --git a/src/backbone_router/nd_proxy.hpp b/src/backbone_router/nd_proxy.hpp index 3a7a2d26085..73b24bab8b7 100644 --- a/src/backbone_router/nd_proxy.hpp +++ b/src/backbone_router/nd_proxy.hpp @@ -55,7 +55,7 @@ #include "common/code_utils.hpp" #include "common/mainloop.hpp" #include "common/types.hpp" -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread_rcp.hpp" namespace otbr { namespace BackboneRouter { @@ -80,8 +80,8 @@ class NdProxyManager : public MainloopProcessor, private NonCopyable * This constructor initializes a NdProxyManager instance. * */ - explicit NdProxyManager(otbr::Ncp::ControllerOpenThread &aNcp, std::string aBackboneInterfaceName) - : mNcp(aNcp) + explicit NdProxyManager(std::string aBackboneInterfaceName) + : mCtrlr(nullptr) , mBackboneInterfaceName(std::move(aBackboneInterfaceName)) , mIcmp6RawSock(-1) , mUnicastNsQueueSock(-1) @@ -93,8 +93,10 @@ class NdProxyManager : public MainloopProcessor, private NonCopyable /** * This method initializes a ND Proxy manager instance. * + * @param[in] aCtrlr A pointer to the ControllerOpenThreadRcp. + * */ - void Init(void); + void Init(Ncp::ControllerOpenThreadRcp *aCtrlr); /** * This method enables the ND Proxy manager. @@ -153,16 +155,16 @@ class NdProxyManager : public MainloopProcessor, private NonCopyable void *aContext); int HandleNetfilterQueue(struct nfq_q_handle *aNfQueueHandler, struct nfgenmsg *aNfMsg, struct nfq_data *aNfData); - otbr::Ncp::ControllerOpenThread &mNcp; - std::string mBackboneInterfaceName; - 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; + otbr::Ncp::ControllerOpenThreadRcp *mCtrlr; + std::string mBackboneInterfaceName; + 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; }; /** diff --git a/src/border_agent/border_agent.cpp b/src/border_agent/border_agent.cpp index 08c84f24e5e..9af596521d5 100644 --- a/src/border_agent/border_agent.cpp +++ b/src/border_agent/border_agent.cpp @@ -56,7 +56,7 @@ #include #include "agent/uris.hpp" -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread_rcp.hpp" #if OTBR_ENABLE_BACKBONE_ROUTER #include "backbone_router/backbone_agent.hpp" #endif @@ -138,15 +138,20 @@ struct StateBitmap } }; -BorderAgent::BorderAgent(otbr::Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher) - : mNcp(aNcp) +BorderAgent::BorderAgent(Mdns::Publisher &aPublisher) + : mCtrlr(nullptr) , mPublisher(aPublisher) , mIsEnabled(false) , mVendorName(OTBR_VENDOR_NAME) , mProductName(OTBR_PRODUCT_NAME) , mBaseServiceInstanceName(OTBR_MESHCOP_SERVICE_INSTANCE_NAME) { - mNcp.AddThreadStateChangedCallback([this](otChangedFlags aFlags) { HandleThreadStateChanged(aFlags); }); +} + +void BorderAgent::Init(Ncp::ControllerOpenThreadRcp *aCtrlr) +{ + mCtrlr = aCtrlr; + mCtrlr->AddThreadStateChangedCallback([this](otChangedFlags aFlags) { HandleThreadStateChanged(aFlags); }); } otbrError BorderAgent::SetMeshCopServiceValues(const std::string &aServiceInstanceName, @@ -190,21 +195,24 @@ void BorderAgent::Start(void) { otbrLogInfo("Start Thread Border Agent"); + VerifyOrDie(mCtrlr != nullptr, "BorderAgent hasn't been initialized with a valid ControllerOpenThreadRcp"); + #if OTBR_ENABLE_DBUS_SERVER - mNcp.GetThreadHelper()->SetUpdateMeshCopTxtHandler([this](std::map> aUpdate) { + mCtrlr->GetThreadHelper()->SetUpdateMeshCopTxtHandler([this](std::map> aUpdate) { HandleUpdateVendorMeshCoPTxtEntries(std::move(aUpdate)); }); - mNcp.RegisterResetHandler([this]() { - mNcp.GetThreadHelper()->SetUpdateMeshCopTxtHandler([this](std::map> aUpdate) { - HandleUpdateVendorMeshCoPTxtEntries(std::move(aUpdate)); - }); + mCtrlr->RegisterResetHandler([this]() { + mCtrlr->GetThreadHelper()->SetUpdateMeshCopTxtHandler( + [this](std::map> aUpdate) { + HandleUpdateVendorMeshCoPTxtEntries(std::move(aUpdate)); + }); }); #endif mServiceInstanceName = GetServiceInstanceNameWithExtAddr(mBaseServiceInstanceName); UpdateMeshCopService(); - otBorderAgentSetEphemeralKeyCallback(mNcp.GetInstance(), BorderAgent::HandleEpskcStateChanged, this); + otBorderAgentSetEphemeralKeyCallback(mCtrlr->GetInstance(), BorderAgent::HandleEpskcStateChanged, this); } void BorderAgent::Stop(void) @@ -217,7 +225,7 @@ void BorderAgent::HandleEpskcStateChanged(void *aContext) { BorderAgent *borderAgent = static_cast(aContext); - if (otBorderAgentIsEphemeralKeyActive(borderAgent->mNcp.GetInstance())) + if (otBorderAgentIsEphemeralKeyActive(borderAgent->mCtrlr->GetInstance())) { borderAgent->PublishEpskcService(); } @@ -229,7 +237,7 @@ void BorderAgent::HandleEpskcStateChanged(void *aContext) void BorderAgent::PublishEpskcService() { - otInstance *instance = mNcp.GetInstance(); + otInstance *instance = mCtrlr->GetInstance(); int port = otBorderAgentGetUdpPort(instance); otbrLogInfo("Publish meshcop-e service %s.%s.local. port %d", mServiceInstanceName.c_str(), @@ -415,7 +423,7 @@ void BorderAgent::PublishMeshCopService(void) { StateBitmap state; uint32_t stateUint32; - otInstance *instance = mNcp.GetInstance(); + otInstance *instance = mCtrlr->GetInstance(); const otExtendedPanId *extPanId = otThreadGetExtendedPanId(instance); const otExtAddress *extAddr = otLinkGetExtendedAddress(instance); const char *networkName = otThreadGetNetworkName(instance); @@ -459,7 +467,7 @@ void BorderAgent::PublishMeshCopService(void) } txtList.emplace_back("nn", networkName); txtList.emplace_back("xp", extPanId->m8, sizeof(extPanId->m8)); - txtList.emplace_back("tv", mNcp.GetThreadVersion()); + txtList.emplace_back("tv", mCtrlr->GetThreadVersion()); // "xa" stands for Extended MAC Address (64-bit) of the Thread Interface of the Border Agent. txtList.emplace_back("xa", extAddr->m8, sizeof(extAddr->m8)); @@ -579,14 +587,14 @@ void BorderAgent::HandleThreadStateChanged(otChangedFlags aFlags) bool BorderAgent::IsThreadStarted(void) const { - otDeviceRole role = otThreadGetDeviceRole(mNcp.GetInstance()); + otDeviceRole role = otThreadGetDeviceRole(mCtrlr->GetInstance()); return role == OT_DEVICE_ROLE_CHILD || role == OT_DEVICE_ROLE_ROUTER || role == OT_DEVICE_ROLE_LEADER; } std::string BorderAgent::GetServiceInstanceNameWithExtAddr(const std::string &aServiceInstanceName) const { - const otExtAddress *extAddress = otLinkGetExtendedAddress(mNcp.GetInstance()); + const otExtAddress *extAddress = otLinkGetExtendedAddress(mCtrlr->GetInstance()); std::stringstream ss; ss << aServiceInstanceName << " #"; diff --git a/src/border_agent/border_agent.hpp b/src/border_agent/border_agent.hpp index 7ebfff3258c..2c8707c2872 100644 --- a/src/border_agent/border_agent.hpp +++ b/src/border_agent/border_agent.hpp @@ -48,7 +48,7 @@ #include "common/code_utils.hpp" #include "common/mainloop.hpp" #include "mdns/mdns.hpp" -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread_rcp.hpp" #include "sdp_proxy/advertising_proxy.hpp" #include "sdp_proxy/discovery_proxy.hpp" #include "trel_dnssd/trel_dnssd.hpp" @@ -86,14 +86,21 @@ class BorderAgent : private NonCopyable /** * The constructor to initialize the Thread border agent. * - * @param[in] aNcp A reference to the NCP controller. * @param[in] aPublisher A reference to the mDNS Publisher. * */ - BorderAgent(otbr::Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher); + BorderAgent(Mdns::Publisher &aPublisher); ~BorderAgent(void) = default; + /** + * Initialize the Border Agent. + * + * @param[in] aCtrlr A pointer to the ControllerOpenThreadRcp. + * + */ + void Init(Ncp::ControllerOpenThreadRcp *aCtrlr); + /** * Overrides MeshCoP service (i.e. _meshcop._udp) instance name, product name, vendor name and vendor OUI. * @@ -153,9 +160,9 @@ class BorderAgent : private NonCopyable void PublishEpskcService(void); void UnpublishEpskcService(void); - otbr::Ncp::ControllerOpenThread &mNcp; - Mdns::Publisher &mPublisher; - bool mIsEnabled; + otbr::Ncp::ControllerOpenThreadRcp *mCtrlr; + Mdns::Publisher &mPublisher; + bool mIsEnabled; #if OTBR_ENABLE_DBUS_SERVER std::map> mMeshCopTxtUpdate; diff --git a/src/common/mainloop_manager.hpp b/src/common/mainloop_manager.hpp index 381ebfb53e8..b5971cc4557 100644 --- a/src/common/mainloop_manager.hpp +++ b/src/common/mainloop_manager.hpp @@ -42,7 +42,7 @@ #include "common/code_utils.hpp" #include "common/mainloop.hpp" -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread_rcp.hpp" namespace otbr { diff --git a/src/dbus/server/dbus_agent.cpp b/src/dbus/server/dbus_agent.cpp index c28773e6caa..fd55c9daef9 100644 --- a/src/dbus/server/dbus_agent.cpp +++ b/src/dbus/server/dbus_agent.cpp @@ -44,17 +44,19 @@ namespace DBus { const struct timeval DBusAgent::kPollTimeout = {0, 0}; constexpr std::chrono::seconds DBusAgent::kDBusWaitAllowance; -DBusAgent::DBusAgent(otbr::Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher) - : mInterfaceName(aNcp.GetInterfaceName()) - , mNcp(aNcp) +DBusAgent::DBusAgent(Mdns::Publisher &aPublisher) + : mCtrlr(nullptr) , mPublisher(aPublisher) { } -void DBusAgent::Init(void) +void DBusAgent::Init(Ncp::IControllerOpenThread *aCtrlr) { otbrError error = OTBR_ERROR_NONE; + mCtrlr = aCtrlr; + mInterfaceName = mCtrlr->GetInterfaceName(); + auto connection_deadline = Clock::now() + kDBusWaitAllowance; while ((mConnection = PrepareDBusConnection()) == nullptr && Clock::now() < connection_deadline) @@ -66,7 +68,7 @@ void DBusAgent::Init(void) VerifyOrDie(mConnection != nullptr, "Failed to get DBus connection"); mThreadObject = - std::unique_ptr(new DBusThreadObject(mConnection.get(), mInterfaceName, &mNcp, &mPublisher)); + std::unique_ptr(new DBusThreadObject(mConnection.get(), mInterfaceName, mCtrlr, &mPublisher)); error = mThreadObject->Init(); VerifyOrDie(error == OTBR_ERROR_NONE, "Failed to initialize DBus Agent"); } diff --git a/src/dbus/server/dbus_agent.hpp b/src/dbus/server/dbus_agent.hpp index c9308ec3390..56f90c20301 100644 --- a/src/dbus/server/dbus_agent.hpp +++ b/src/dbus/server/dbus_agent.hpp @@ -48,7 +48,7 @@ #include "dbus/server/dbus_object.hpp" #include "dbus/server/dbus_thread_object.hpp" -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread_rcp.hpp" namespace otbr { namespace DBus { @@ -62,13 +62,15 @@ class DBusAgent : public MainloopProcessor, private NonCopyable * @param[in] aNcp A reference to the NCP controller. * */ - DBusAgent(otbr::Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher); + DBusAgent(Mdns::Publisher &aPublisher); /** * This method initializes the dbus agent. * + * @param[in] aCtrlr A pointer to the ControllerOpenThread. + * */ - void Init(void); + void Init(Ncp::IControllerOpenThread *aCtrlr); void Update(MainloopContext &aMainloop) override; void Process(const MainloopContext &aMainloop) override; @@ -88,7 +90,7 @@ class DBusAgent : public MainloopProcessor, private NonCopyable std::string mInterfaceName; std::unique_ptr mThreadObject; UniqueDBusConnection mConnection; - otbr::Ncp::ControllerOpenThread &mNcp; + otbr::Ncp::IControllerOpenThread *mCtrlr; Mdns::Publisher &mPublisher; /** diff --git a/src/dbus/server/dbus_object.cpp b/src/dbus/server/dbus_object.cpp index 64c384a6b3c..66c4f74a7b8 100644 --- a/src/dbus/server/dbus_object.cpp +++ b/src/dbus/server/dbus_object.cpp @@ -49,7 +49,7 @@ DBusObject::DBusObject(DBusConnection *aConnection, const std::string &aObjectPa { } -otbrError DBusObject::Init(void) +otbrError DBusObject::Init(bool aIsGetPropertyHandlerAsync) { otbrError error = OTBR_ERROR_NONE; DBusObjectPathVTable vTable; @@ -60,10 +60,19 @@ otbrError DBusObject::Init(void) VerifyOrExit(dbus_connection_register_object_path(mConnection, mObjectPath.c_str(), &vTable, this), error = OTBR_ERROR_DBUS); - RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_GET_METHOD, - std::bind(&DBusObject::GetPropertyMethodHandler, this, _1)); - RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_SET_METHOD, - std::bind(&DBusObject::SetPropertyMethodHandler, this, _1)); + + if (aIsGetPropertyHandlerAsync) + { + RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_GET_METHOD, + std::bind(&DBusObject::AsyncGetPropertyMethodHandler, this, _1)); + } + else + { + RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_GET_METHOD, + std::bind(&DBusObject::GetPropertyMethodHandler, this, _1)); + RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_SET_METHOD, + std::bind(&DBusObject::SetPropertyMethodHandler, this, _1)); + } RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_GET_ALL_METHOD, std::bind(&DBusObject::GetAllPropertiesMethodHandler, this, _1)); @@ -98,6 +107,13 @@ void DBusObject::RegisterSetPropertyHandler(const std::string &aInterfac mSetPropertyHandlers.emplace(fullPath, aHandler); } +void DBusObject::RegisterAsyncGetPropertyHandler(const std::string &aInterfaceName, + const std::string &aPropertyName, + const AsyncPropertyHandlerType &aHandler) +{ + mAsyncGetPropertyHandlers[aInterfaceName].emplace(aPropertyName, aHandler); +} + DBusHandlerResult DBusObject::sMessageHandler(DBusConnection *aConnection, DBusMessage *aMessage, void *aData) { DBusObject *server = reinterpret_cast(aData); @@ -181,6 +197,40 @@ void DBusObject::GetPropertyMethodHandler(DBusRequest &aRequest) } } +void DBusObject::AsyncGetPropertyMethodHandler(DBusRequest &aRequest) +{ + DBusMessageIter iter; + std::string interfaceName; + otError error = OT_ERROR_NONE; + std::string propertyName; + + VerifyOrExit(dbus_message_iter_init(aRequest.GetMessage(), &iter), error = OT_ERROR_FAILED); + VerifyOrExit(DBusMessageExtract(&iter, interfaceName) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE); + VerifyOrExit(DBusMessageExtract(&iter, propertyName) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE); + + { + auto propertyIter = mAsyncGetPropertyHandlers.find(interfaceName); + + otbrLogDebug("AsyncGetProperty %s.%s", interfaceName.c_str(), propertyName.c_str()); + VerifyOrExit(propertyIter != mAsyncGetPropertyHandlers.end(), error = OT_ERROR_NOT_FOUND); + { + auto &interfaceHandlers = propertyIter->second; + auto interfaceIter = interfaceHandlers.find(propertyName); + + VerifyOrExit(interfaceIter != interfaceHandlers.end(), error = OT_ERROR_NOT_FOUND); + (interfaceIter->second)(aRequest); + } + } + +exit: + if (error != OT_ERROR_NONE) + { + otbrLogWarning("GetProperty %s.%s error:%s", interfaceName.c_str(), propertyName.c_str(), + ConvertToDBusErrorName(error)); + aRequest.ReplyOtResult(error); + } +} + void DBusObject::GetAllPropertiesMethodHandler(DBusRequest &aRequest) { UniqueDBusMessage reply{dbus_message_new_method_return(aRequest.GetMessage())}; diff --git a/src/dbus/server/dbus_object.hpp b/src/dbus/server/dbus_object.hpp index 8aa335baf07..422257ace94 100644 --- a/src/dbus/server/dbus_object.hpp +++ b/src/dbus/server/dbus_object.hpp @@ -65,9 +65,9 @@ namespace DBus { class DBusObject : private NonCopyable { public: - using MethodHandlerType = std::function; - - using PropertyHandlerType = std::function; + using MethodHandlerType = std::function; + using AsyncPropertyHandlerType = std::function; + using PropertyHandlerType = std::function; /** * The constructor of a d-bus object. @@ -83,11 +83,13 @@ class DBusObject : private NonCopyable * * This method will register the object to the d-bus library. * + * @param[in] aIsGetPropertyHandlerAsync If the GetPropertyHandlers are async. + * * @retval OTBR_ERROR_NONE Successfully registered the object. * @retval OTBR_ERROR_DBUS Failed to ragister an object. * */ - virtual otbrError Init(void); + otbrError Init(bool aIsGetPropertyHandlerAsync = false); /** * This method registers the method handler. @@ -125,6 +127,18 @@ class DBusObject : private NonCopyable const std::string &aPropertyName, const PropertyHandlerType &aHandler); + /** + * This method registers the async get handler for a property. + * + * @param[in] aInterfaceName The interface name. + * @param[in] aPropertyName The property name. + * @param[in] aHandler The method handler. + * + */ + virtual void RegisterAsyncGetPropertyHandler(const std::string &aInterfaceName, + const std::string &aPropertyName, + const AsyncPropertyHandlerType &aHandler); + /** * This method sends a signal. * @@ -224,6 +238,7 @@ class DBusObject : private NonCopyable void GetAllPropertiesMethodHandler(DBusRequest &aRequest); void GetPropertyMethodHandler(DBusRequest &aRequest); void SetPropertyMethodHandler(DBusRequest &aRequest); + void AsyncGetPropertyMethodHandler(DBusRequest &aRequest); static DBusHandlerResult sMessageHandler(DBusConnection *aConnection, DBusMessage *aMessage, void *aData); DBusHandlerResult MessageHandler(DBusConnection *aConnection, DBusMessage *aMessage); @@ -233,8 +248,10 @@ class DBusObject : private NonCopyable std::unordered_map mMethodHandlers; std::unordered_map> mGetPropertyHandlers; std::unordered_map mSetPropertyHandlers; - DBusConnection *mConnection; - std::string mObjectPath; + std::unordered_map> + mAsyncGetPropertyHandlers; + DBusConnection *mConnection; + std::string mObjectPath; }; } // namespace DBus diff --git a/src/dbus/server/dbus_thread_object.cpp b/src/dbus/server/dbus_thread_object.cpp index 8a10417bfcc..6d9817f073b 100644 --- a/src/dbus/server/dbus_thread_object.cpp +++ b/src/dbus/server/dbus_thread_object.cpp @@ -90,26 +90,47 @@ static std::string GetNat64StateName(otNat64State aState) namespace otbr { namespace DBus { -DBusThreadObject::DBusThreadObject(DBusConnection *aConnection, - const std::string &aInterfaceName, - otbr::Ncp::ControllerOpenThread *aNcp, - Mdns::Publisher *aPublisher) +DBusThreadObject::DBusThreadObject(DBusConnection *aConnection, + const std::string &aInterfaceName, + otbr::Ncp::IControllerOpenThread *aNcp, + Mdns::Publisher *aPublisher) : DBusObject(aConnection, OTBR_DBUS_OBJECT_PREFIX + aInterfaceName) - , mNcp(aNcp) + , mCtrlr(aNcp) + , mCtrlrRcp(nullptr) + , mCtrlrNcp(nullptr) , mPublisher(aPublisher) { } otbrError DBusThreadObject::Init(void) { - otbrError error = OTBR_ERROR_NONE; - auto threadHelper = mNcp->GetThreadHelper(); + otbrError error = OTBR_ERROR_NONE; - SuccessOrExit(error = DBusObject::Init()); + SuccessOrExit(error = DBusObject::Init(mCtrlr->GetCoprocessorType() == OT_COPROCESSOR_NCP)); + + if (mCtrlr->GetCoprocessorType() == OT_COPROCESSOR_RCP) + { + mCtrlrRcp = static_cast(mCtrlr); + InitRcpMode(); + } + else if (mCtrlr->GetCoprocessorType() == OT_COPROCESSOR_NCP) + { + mCtrlrNcp = static_cast(mCtrlr); + InitNcpMode(); + } + + SuccessOrExit(error = Signal(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_SIGNAL_READY, std::make_tuple())); +exit: + return error; +} + +void DBusThreadObject::InitRcpMode(void) +{ + auto threadHelper = mCtrlrRcp->GetThreadHelper(); threadHelper->AddDeviceRoleHandler(std::bind(&DBusThreadObject::DeviceRoleHandler, this, _1)); threadHelper->AddActiveDatasetChangeHandler(std::bind(&DBusThreadObject::ActiveDatasetChangeHandler, this, _1)); - mNcp->RegisterResetHandler(std::bind(&DBusThreadObject::NcpResetHandler, this)); + mCtrlrRcp->RegisterResetHandler(std::bind(&DBusThreadObject::NcpResetHandler, this)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_SCAN_METHOD, std::bind(&DBusThreadObject::ScanHandler, this, _1)); @@ -279,11 +300,12 @@ otbrError DBusThreadObject::Init(void) std::bind(&DBusThreadObject::GetTelemetryDataHandler, this, _1)); RegisterGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_CAPABILITIES, std::bind(&DBusThreadObject::GetCapabilitiesHandler, this, _1)); +} - SuccessOrExit(error = Signal(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_SIGNAL_READY, std::make_tuple())); - -exit: - return error; +void DBusThreadObject::InitNcpMode(void) +{ + RegisterAsyncGetPropertyHandler(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_DEVICE_ROLE, + std::bind(&DBusThreadObject::AsyncGetDeviceRoleHandler, this, _1)); } void DBusThreadObject::DeviceRoleHandler(otDeviceRole aDeviceRole) @@ -293,8 +315,8 @@ void DBusThreadObject::DeviceRoleHandler(otDeviceRole aDeviceRole) void DBusThreadObject::NcpResetHandler(void) { - mNcp->GetThreadHelper()->AddDeviceRoleHandler(std::bind(&DBusThreadObject::DeviceRoleHandler, this, _1)); - mNcp->GetThreadHelper()->AddActiveDatasetChangeHandler( + mCtrlrRcp->GetThreadHelper()->AddDeviceRoleHandler(std::bind(&DBusThreadObject::DeviceRoleHandler, this, _1)); + mCtrlrRcp->GetThreadHelper()->AddActiveDatasetChangeHandler( std::bind(&DBusThreadObject::ActiveDatasetChangeHandler, this, _1)); SignalPropertyChanged(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_PROPERTY_DEVICE_ROLE, GetDeviceRoleName(OT_DEVICE_ROLE_DISABLED)); @@ -302,7 +324,7 @@ void DBusThreadObject::NcpResetHandler(void) void DBusThreadObject::ScanHandler(DBusRequest &aRequest) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); threadHelper->Scan(std::bind(&DBusThreadObject::ReplyScanResult, this, aRequest, _1, _2)); } @@ -338,7 +360,7 @@ void DBusThreadObject::ReplyScanResult(DBusRequest &aR void DBusThreadObject::EnergyScanHandler(DBusRequest &aRequest) { otError error = OT_ERROR_NONE; - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); uint32_t scanDuration; auto args = std::tie(scanDuration); @@ -381,7 +403,7 @@ void DBusThreadObject::ReplyEnergyScanResult(DBusRequest void DBusThreadObject::AttachHandler(DBusRequest &aRequest) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); std::string name; uint16_t panid; uint64_t extPanId; @@ -423,7 +445,7 @@ void DBusThreadObject::AttachAllNodesToHandler(DBusRequest &aRequest) VerifyOrExit(DBusMessageToTuple(*aRequest.GetMessage(), args) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); - mNcp->GetThreadHelper()->AttachAllNodesTo(dataset, [aRequest](otError error, int64_t aAttachDelayMs) mutable { + mCtrlrRcp->GetThreadHelper()->AttachAllNodesTo(dataset, [aRequest](otError error, int64_t aAttachDelayMs) mutable { aRequest.ReplyOtResult(error, aAttachDelayMs); }); @@ -436,16 +458,16 @@ void DBusThreadObject::AttachAllNodesToHandler(DBusRequest &aRequest) void DBusThreadObject::DetachHandler(DBusRequest &aRequest) { - aRequest.ReplyOtResult(mNcp->GetThreadHelper()->Detach()); + aRequest.ReplyOtResult(mCtrlrRcp->GetThreadHelper()->Detach()); } void DBusThreadObject::FactoryResetHandler(DBusRequest &aRequest) { otError error = OT_ERROR_NONE; - SuccessOrExit(error = mNcp->GetThreadHelper()->Detach()); - SuccessOrExit(otInstanceErasePersistentInfo(mNcp->GetThreadHelper()->GetInstance())); - mNcp->Reset(); + SuccessOrExit(error = mCtrlrRcp->GetThreadHelper()->Detach()); + SuccessOrExit(otInstanceErasePersistentInfo(mCtrlrRcp->GetThreadHelper()->GetInstance())); + mCtrlrRcp->Reset(); exit: aRequest.ReplyOtResult(error); @@ -453,13 +475,13 @@ void DBusThreadObject::FactoryResetHandler(DBusRequest &aRequest) void DBusThreadObject::ResetHandler(DBusRequest &aRequest) { - mNcp->Reset(); + mCtrlrRcp->Reset(); aRequest.ReplyOtResult(OT_ERROR_NONE); } void DBusThreadObject::JoinerStartHandler(DBusRequest &aRequest) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); std::string pskd, provisionUrl, vendorName, vendorModel, vendorSwVersion, vendorData; auto args = std::tie(pskd, provisionUrl, vendorName, vendorModel, vendorSwVersion, vendorData); @@ -476,7 +498,7 @@ void DBusThreadObject::JoinerStartHandler(DBusRequest &aRequest) void DBusThreadObject::JoinerStopHandler(DBusRequest &aRequest) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otJoinerStop(threadHelper->GetInstance()); aRequest.ReplyOtResult(OT_ERROR_NONE); @@ -485,7 +507,7 @@ void DBusThreadObject::JoinerStopHandler(DBusRequest &aRequest) void DBusThreadObject::PermitUnsecureJoinHandler(DBusRequest &aRequest) { #ifdef OTBR_ENABLE_UNSECURE_JOIN - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); uint16_t port; uint32_t timeout; auto args = std::tie(port, timeout); @@ -505,7 +527,7 @@ void DBusThreadObject::PermitUnsecureJoinHandler(DBusRequest &aRequest) void DBusThreadObject::AddOnMeshPrefixHandler(DBusRequest &aRequest) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); OnMeshPrefix onMeshPrefix; auto args = std::tie(onMeshPrefix); otError error = OT_ERROR_NONE; @@ -534,7 +556,7 @@ void DBusThreadObject::AddOnMeshPrefixHandler(DBusRequest &aRequest) void DBusThreadObject::RemoveOnMeshPrefixHandler(DBusRequest &aRequest) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); Ip6Prefix onMeshPrefix; auto args = std::tie(onMeshPrefix); otError error = OT_ERROR_NONE; @@ -554,7 +576,7 @@ void DBusThreadObject::RemoveOnMeshPrefixHandler(DBusRequest &aRequest) void DBusThreadObject::AddExternalRouteHandler(DBusRequest &aRequest) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); ExternalRoute route; auto args = std::tie(route); otError error = OT_ERROR_NONE; @@ -581,7 +603,7 @@ void DBusThreadObject::AddExternalRouteHandler(DBusRequest &aRequest) void DBusThreadObject::RemoveExternalRouteHandler(DBusRequest &aRequest) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); Ip6Prefix routePrefix; auto args = std::tie(routePrefix); otError error = OT_ERROR_NONE; @@ -611,7 +633,7 @@ void DBusThreadObject::IntrospectHandler(DBusRequest &aRequest) otError DBusThreadObject::SetMeshLocalPrefixHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otMeshLocalPrefix prefix; std::array data{}; otError error = OT_ERROR_NONE; @@ -626,7 +648,7 @@ otError DBusThreadObject::SetMeshLocalPrefixHandler(DBusMessageIter &aIter) otError DBusThreadObject::SetLinkModeHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); LinkModeConfig cfg; otLinkModeConfig otCfg; otError error = OT_ERROR_NONE; @@ -643,7 +665,7 @@ otError DBusThreadObject::SetLinkModeHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetLinkModeHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otLinkModeConfig otCfg = otThreadGetLinkMode(threadHelper->GetInstance()); LinkModeConfig cfg; otError error = OT_ERROR_NONE; @@ -660,7 +682,7 @@ otError DBusThreadObject::GetLinkModeHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetDeviceRoleHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otDeviceRole role = otThreadGetDeviceRole(threadHelper->GetInstance()); std::string roleName = GetDeviceRoleName(role); otError error = OT_ERROR_NONE; @@ -673,7 +695,7 @@ otError DBusThreadObject::GetDeviceRoleHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetNetworkNameHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); std::string networkName = otThreadGetNetworkName(threadHelper->GetInstance()); otError error = OT_ERROR_NONE; @@ -685,7 +707,7 @@ otError DBusThreadObject::GetNetworkNameHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetPanIdHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); uint16_t panId = otLinkGetPanId(threadHelper->GetInstance()); otError error = OT_ERROR_NONE; @@ -697,7 +719,7 @@ otError DBusThreadObject::GetPanIdHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetExtPanIdHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); const otExtendedPanId *extPanId = otThreadGetExtendedPanId(threadHelper->GetInstance()); uint64_t extPanIdVal; otError error = OT_ERROR_NONE; @@ -712,7 +734,7 @@ otError DBusThreadObject::GetExtPanIdHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetChannelHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); uint16_t channel = otLinkGetChannel(threadHelper->GetInstance()); otError error = OT_ERROR_NONE; @@ -724,7 +746,7 @@ otError DBusThreadObject::GetChannelHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetNetworkKeyHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otNetworkKey networkKey; otError error = OT_ERROR_NONE; @@ -738,7 +760,7 @@ otError DBusThreadObject::GetNetworkKeyHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetCcaFailureRateHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); uint16_t failureRate = otLinkGetCcaFailureRate(threadHelper->GetInstance()); otError error = OT_ERROR_NONE; @@ -750,7 +772,7 @@ otError DBusThreadObject::GetCcaFailureRateHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetLinkCountersHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); const otMacCounters *otCounters = otLinkGetCounters(threadHelper->GetInstance()); MacCounters counters; otError error = OT_ERROR_NONE; @@ -796,7 +818,7 @@ otError DBusThreadObject::GetLinkCountersHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetIp6CountersHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); const otIpCounters *otCounters = otThreadGetIp6Counters(threadHelper->GetInstance()); IpCounters counters; otError error = OT_ERROR_NONE; @@ -814,7 +836,7 @@ otError DBusThreadObject::GetIp6CountersHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetSupportedChannelMaskHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); uint32_t channelMask = otLinkGetSupportedChannelMask(threadHelper->GetInstance()); otError error = OT_ERROR_NONE; @@ -826,7 +848,7 @@ otError DBusThreadObject::GetSupportedChannelMaskHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetPreferredChannelMaskHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); uint32_t channelMask = otPlatRadioGetPreferredChannelMask(threadHelper->GetInstance()); otError error = OT_ERROR_NONE; @@ -838,7 +860,7 @@ otError DBusThreadObject::GetPreferredChannelMaskHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetRloc16Handler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; uint16_t rloc16 = otThreadGetRloc16(threadHelper->GetInstance()); @@ -850,7 +872,7 @@ otError DBusThreadObject::GetRloc16Handler(DBusMessageIter &aIter) otError DBusThreadObject::GetExtendedAddressHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; const otExtAddress *addr = otLinkGetExtendedAddress(threadHelper->GetInstance()); uint64_t extendedAddress = ConvertOpenThreadUint64(addr->m8); @@ -863,7 +885,7 @@ otError DBusThreadObject::GetExtendedAddressHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetRouterIdHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; uint16_t rloc16 = otThreadGetRloc16(threadHelper->GetInstance()); otRouterInfo info; @@ -878,7 +900,7 @@ otError DBusThreadObject::GetRouterIdHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetLeaderDataHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; struct otLeaderData data; LeaderData leaderData; @@ -898,7 +920,7 @@ otError DBusThreadObject::GetLeaderDataHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetNetworkDataHandler(DBusMessageIter &aIter) { static constexpr size_t kNetworkDataMaxSize = 255; - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; uint8_t data[kNetworkDataMaxSize]; uint8_t len = sizeof(data); @@ -915,7 +937,7 @@ otError DBusThreadObject::GetNetworkDataHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetStableNetworkDataHandler(DBusMessageIter &aIter) { static constexpr size_t kNetworkDataMaxSize = 255; - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; uint8_t data[kNetworkDataMaxSize]; uint8_t len = sizeof(data); @@ -931,7 +953,7 @@ otError DBusThreadObject::GetStableNetworkDataHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetLocalLeaderWeightHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; uint8_t weight = otThreadGetLocalLeaderWeight(threadHelper->GetInstance()); @@ -944,7 +966,7 @@ otError DBusThreadObject::GetLocalLeaderWeightHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetChannelMonitorSampleCountHandler(DBusMessageIter &aIter) { #if OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; uint32_t cnt = otChannelMonitorGetSampleCount(threadHelper->GetInstance()); @@ -961,7 +983,7 @@ otError DBusThreadObject::GetChannelMonitorSampleCountHandler(DBusMessageIter &a otError DBusThreadObject::GetChannelMonitorAllChannelQualities(DBusMessageIter &aIter) { #if OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; uint32_t channelMask = otLinkGetSupportedChannelMask(threadHelper->GetInstance()); constexpr uint8_t kNumChannels = sizeof(channelMask) * 8; // 8 bit per byte @@ -989,7 +1011,7 @@ otError DBusThreadObject::GetChannelMonitorAllChannelQualities(DBusMessageIter & otError DBusThreadObject::GetChildTableHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; uint16_t childIndex = 0; otChildInfo childInfo; @@ -1025,7 +1047,7 @@ otError DBusThreadObject::GetChildTableHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetNeighborTableHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; otNeighborInfoIterator iter = OT_NEIGHBOR_INFO_ITERATOR_INIT; otNeighborInfo neighborInfo; @@ -1061,7 +1083,7 @@ otError DBusThreadObject::GetNeighborTableHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetPartitionIDHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; uint32_t partitionId = otThreadGetPartitionId(threadHelper->GetInstance()); @@ -1073,7 +1095,7 @@ otError DBusThreadObject::GetPartitionIDHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetInstantRssiHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; int8_t rssi = otPlatRadioGetRssi(threadHelper->GetInstance()); @@ -1085,7 +1107,7 @@ otError DBusThreadObject::GetInstantRssiHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetRadioTxPowerHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; int8_t txPower; @@ -1099,7 +1121,7 @@ otError DBusThreadObject::GetRadioTxPowerHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetExternalRoutesHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT; otExternalRouteConfig config; @@ -1128,7 +1150,7 @@ otError DBusThreadObject::GetExternalRoutesHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetOnMeshPrefixesHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT; otBorderRouterConfig config; @@ -1162,7 +1184,7 @@ otError DBusThreadObject::GetOnMeshPrefixesHandler(DBusMessageIter &aIter) otError DBusThreadObject::SetActiveDatasetTlvsHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); std::vector data; otOperationalDatasetTlvs datasetTlvs; otError error = OT_ERROR_NONE; @@ -1179,7 +1201,7 @@ otError DBusThreadObject::SetActiveDatasetTlvsHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetActiveDatasetTlvsHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; std::vector data; otOperationalDatasetTlvs datasetTlvs; @@ -1195,7 +1217,7 @@ otError DBusThreadObject::GetActiveDatasetTlvsHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetPendingDatasetTlvsHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; std::vector data; otOperationalDatasetTlvs datasetTlvs; @@ -1218,7 +1240,7 @@ otError DBusThreadObject::SetFeatureFlagListDataHandler(DBusMessageIter &aIter) VerifyOrExit(DBusMessageExtractFromVariant(&aIter, data) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); VerifyOrExit(featureFlagList.ParseFromString(std::string(data.begin(), data.end())), error = OT_ERROR_INVALID_ARGS); - VerifyOrExit((error = mNcp->ApplyFeatureFlagList(featureFlagList)) == OT_ERROR_NONE); + VerifyOrExit((error = mCtrlrRcp->ApplyFeatureFlagList(featureFlagList)) == OT_ERROR_NONE); exit: return error; #else @@ -1231,7 +1253,7 @@ otError DBusThreadObject::GetFeatureFlagListDataHandler(DBusMessageIter &aIter) { #if OTBR_ENABLE_FEATURE_FLAGS otError error = OT_ERROR_NONE; - const std::string appliedFeatureFlagListBytes = mNcp->GetAppliedFeatureFlagListBytes(); + const std::string appliedFeatureFlagListBytes = mCtrlrRcp->GetAppliedFeatureFlagListBytes(); std::vector data(appliedFeatureFlagListBytes.begin(), appliedFeatureFlagListBytes.end()); VerifyOrExit(DBusMessageEncodeToVariant(&aIter, data) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); @@ -1246,7 +1268,7 @@ otError DBusThreadObject::GetFeatureFlagListDataHandler(DBusMessageIter &aIter) otError DBusThreadObject::SetRadioRegionHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); std::string radioRegion; uint16_t regionCode; otError error = OT_ERROR_NONE; @@ -1263,7 +1285,7 @@ otError DBusThreadObject::SetRadioRegionHandler(DBusMessageIter &aIter) void DBusThreadObject::UpdateMeshCopTxtHandler(DBusRequest &aRequest) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; std::map> update; std::vector updatedTxtEntries; @@ -1286,7 +1308,7 @@ void DBusThreadObject::UpdateMeshCopTxtHandler(DBusRequest &aRequest) otError DBusThreadObject::GetRadioRegionHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; std::string radioRegion; uint16_t regionCode; @@ -1305,7 +1327,7 @@ otError DBusThreadObject::GetRadioRegionHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetSrpServerInfoHandler(DBusMessageIter &aIter) { #if OTBR_ENABLE_SRP_ADVERTISING_PROXY - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); auto instance = threadHelper->GetInstance(); otError error = OT_ERROR_NONE; SrpServerInfo srpServerInfo{}; @@ -1384,7 +1406,7 @@ otError DBusThreadObject::GetMdnsTelemetryInfoHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetDnssdCountersHandler(DBusMessageIter &aIter) { #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); auto instance = threadHelper->GetInstance(); otError error = OT_ERROR_NONE; DnssdCounters dnssdCounters; @@ -1413,7 +1435,7 @@ otError DBusThreadObject::GetDnssdCountersHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetTrelInfoHandler(DBusMessageIter &aIter) { #if OTBR_ENABLE_TREL - auto instance = mNcp->GetThreadHelper()->GetInstance(); + auto instance = mCtrlrRcp->GetThreadHelper()->GetInstance(); otError error = OT_ERROR_NONE; TrelInfo trelInfo; otTrelCounters otTrelCounters = *otTrelGetCounters(instance); @@ -1442,7 +1464,7 @@ otError DBusThreadObject::GetTelemetryDataHandler(DBusMessageIter &aIter) #if OTBR_ENABLE_TELEMETRY_DATA_API otError error = OT_ERROR_NONE; threadnetwork::TelemetryData telemetryData; - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); if (threadHelper->RetrieveTelemetryData(mPublisher, telemetryData) != OT_ERROR_NONE) { @@ -1556,7 +1578,7 @@ otError DBusThreadObject::GetOtHostVersionHandler(DBusMessageIter &aIter) otError DBusThreadObject::GetEui64Handler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; otExtAddress extAddr; uint64_t eui64; @@ -1573,7 +1595,7 @@ otError DBusThreadObject::GetEui64Handler(DBusMessageIter &aIter) otError DBusThreadObject::GetOtRcpVersionHandler(DBusMessageIter &aIter) { - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); otError error = OT_ERROR_NONE; std::string version = otGetRadioVersionString(threadHelper->GetInstance()); @@ -1637,7 +1659,7 @@ otError DBusThreadObject::GetUptimeHandler(DBusMessageIter &aIter) { otError error = OT_ERROR_NONE; - VerifyOrExit(DBusMessageEncodeToVariant(&aIter, otInstanceGetUptime(mNcp->GetThreadHelper()->GetInstance())) == + VerifyOrExit(DBusMessageEncodeToVariant(&aIter, otInstanceGetUptime(mCtrlrRcp->GetThreadHelper()->GetInstance())) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); @@ -1651,7 +1673,7 @@ otError DBusThreadObject::GetRadioCoexMetrics(DBusMessageIter &aIter) otRadioCoexMetrics otRadioCoexMetrics; RadioCoexMetrics radioCoexMetrics; - SuccessOrExit(error = otPlatRadioGetCoexMetrics(mNcp->GetInstance(), &otRadioCoexMetrics)); + SuccessOrExit(error = otPlatRadioGetCoexMetrics(mCtrlrRcp->GetInstance(), &otRadioCoexMetrics)); radioCoexMetrics.mNumGrantGlitch = otRadioCoexMetrics.mNumGrantGlitch; radioCoexMetrics.mNumTxRequest = otRadioCoexMetrics.mNumTxRequest; @@ -1683,7 +1705,7 @@ otError DBusThreadObject::GetRadioCoexMetrics(DBusMessageIter &aIter) otError DBusThreadObject::GetBorderRoutingCountersHandler(DBusMessageIter &aIter) { #if OTBR_ENABLE_BORDER_ROUTING_COUNTERS - auto threadHelper = mNcp->GetThreadHelper(); + auto threadHelper = mCtrlrRcp->GetThreadHelper(); auto instance = threadHelper->GetInstance(); otError error = OT_ERROR_NONE; BorderRoutingCounters borderRoutingCounters; @@ -1727,10 +1749,10 @@ void DBusThreadObject::LeaveNetworkHandler(DBusRequest &aRequest) { constexpr int kExitCodeShouldRestart = 7; - mNcp->GetThreadHelper()->DetachGracefully([aRequest, this](otError error) mutable { + mCtrlrRcp->GetThreadHelper()->DetachGracefully([aRequest, this](otError error) mutable { SuccessOrExit(error); mPublisher->Stop(); - SuccessOrExit(error = otInstanceErasePersistentInfo(mNcp->GetThreadHelper()->GetInstance())); + SuccessOrExit(error = otInstanceErasePersistentInfo(mCtrlrRcp->GetThreadHelper()->GetInstance())); exit: aRequest.ReplyOtResult(error); @@ -1750,7 +1772,7 @@ void DBusThreadObject::SetNat64Enabled(DBusRequest &aRequest) auto args = std::tie(enable); VerifyOrExit(DBusMessageToTuple(*aRequest.GetMessage(), args) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); - otNat64SetEnabled(mNcp->GetThreadHelper()->GetInstance(), enable); + otNat64SetEnabled(mCtrlrRcp->GetThreadHelper()->GetInstance(), enable); exit: aRequest.ReplyOtResult(error); @@ -1762,8 +1784,9 @@ otError DBusThreadObject::GetNat64State(DBusMessageIter &aIter) Nat64ComponentState state; - state.mPrefixManagerState = GetNat64StateName(otNat64GetPrefixManagerState(mNcp->GetThreadHelper()->GetInstance())); - state.mTranslatorState = GetNat64StateName(otNat64GetTranslatorState(mNcp->GetThreadHelper()->GetInstance())); + state.mPrefixManagerState = + GetNat64StateName(otNat64GetPrefixManagerState(mCtrlrRcp->GetThreadHelper()->GetInstance())); + state.mTranslatorState = GetNat64StateName(otNat64GetTranslatorState(mCtrlrRcp->GetThreadHelper()->GetInstance())); VerifyOrExit(DBusMessageEncodeToVariant(&aIter, state) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); @@ -1780,8 +1803,9 @@ otError DBusThreadObject::GetNat64Mappings(DBusMessageIter &aIter) otNat64AddressMapping otMapping; Nat64AddressMapping mapping; - otNat64InitAddressMappingIterator(mNcp->GetThreadHelper()->GetInstance(), &iterator); - while (otNat64GetNextAddressMapping(mNcp->GetThreadHelper()->GetInstance(), &iterator, &otMapping) == OT_ERROR_NONE) + otNat64InitAddressMappingIterator(mCtrlrRcp->GetThreadHelper()->GetInstance(), &iterator); + while (otNat64GetNextAddressMapping(mCtrlrRcp->GetThreadHelper()->GetInstance(), &iterator, &otMapping) == + OT_ERROR_NONE) { mapping.mId = otMapping.mId; std::copy(std::begin(otMapping.mIp4.mFields.m8), std::end(otMapping.mIp4.mFields.m8), mapping.mIp4.data()); @@ -1823,7 +1847,7 @@ otError DBusThreadObject::GetNat64ProtocolCounters(DBusMessageIter &aIter) otNat64ProtocolCounters otCounters; Nat64ProtocolCounters counters; - otNat64GetCounters(mNcp->GetThreadHelper()->GetInstance(), &otCounters); + otNat64GetCounters(mCtrlrRcp->GetThreadHelper()->GetInstance(), &otCounters); counters.mTotal.m4To6Packets = otCounters.mTotal.m4To6Packets; counters.mTotal.m4To6Bytes = otCounters.mTotal.m4To6Bytes; @@ -1854,7 +1878,7 @@ otError DBusThreadObject::GetNat64ErrorCounters(DBusMessageIter &aIter) otNat64ErrorCounters otCounters; Nat64ErrorCounters counters; - otNat64GetErrorCounters(mNcp->GetThreadHelper()->GetInstance(), &otCounters); + otNat64GetErrorCounters(mCtrlrRcp->GetThreadHelper()->GetInstance(), &otCounters); counters.mUnknown.m4To6Packets = otCounters.mCount4To6[OT_NAT64_DROP_REASON_UNKNOWN]; counters.mUnknown.m6To4Packets = otCounters.mCount6To4[OT_NAT64_DROP_REASON_UNKNOWN]; @@ -1878,7 +1902,7 @@ otError DBusThreadObject::GetNat64Cidr(DBusMessageIter &aIter) otIp4Cidr cidr; char cidrString[OT_IP4_CIDR_STRING_SIZE]; - SuccessOrExit(error = otNat64GetCidr(mNcp->GetThreadHelper()->GetInstance(), &cidr)); + SuccessOrExit(error = otNat64GetCidr(mCtrlrRcp->GetThreadHelper()->GetInstance(), &cidr)); otIp4CidrToString(&cidr, cidrString, sizeof(cidrString)); VerifyOrExit(DBusMessageEncodeToVariant(&aIter, std::string(cidrString)) == OTBR_ERROR_NONE, @@ -1896,7 +1920,7 @@ otError DBusThreadObject::SetNat64Cidr(DBusMessageIter &aIter) VerifyOrExit(DBusMessageExtractFromVariant(&aIter, cidrString) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); SuccessOrExit(error = otIp4CidrFromString(cidrString.c_str(), &cidr)); - SuccessOrExit(error = otNat64SetIp4Cidr(mNcp->GetThreadHelper()->GetInstance(), &cidr)); + SuccessOrExit(error = otNat64SetIp4Cidr(mCtrlrRcp->GetThreadHelper()->GetInstance(), &cidr)); exit: return error; @@ -1982,7 +2006,7 @@ otError DBusThreadObject::SetDnsUpstreamQueryState(DBusMessageIter &aIter) bool enable; VerifyOrExit(DBusMessageExtractFromVariant(&aIter, enable) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); - otDnssdUpstreamQuerySetEnabled(mNcp->GetThreadHelper()->GetInstance(), enable); + otDnssdUpstreamQuerySetEnabled(mCtrlrRcp->GetThreadHelper()->GetInstance(), enable); exit: return error; @@ -1999,7 +2023,8 @@ otError DBusThreadObject::GetDnsUpstreamQueryState(DBusMessageIter &aIter) otError error = OT_ERROR_NONE; VerifyOrExit(DBusMessageEncodeToVariant( - &aIter, otDnssdUpstreamQueryIsEnabled(mNcp->GetThreadHelper()->GetInstance())) == OTBR_ERROR_NONE, + &aIter, otDnssdUpstreamQueryIsEnabled(mCtrlrRcp->GetThreadHelper()->GetInstance())) == + OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); exit: @@ -2011,6 +2036,15 @@ otError DBusThreadObject::GetDnsUpstreamQueryState(DBusMessageIter &aIter) #endif } +void DBusThreadObject::AsyncGetDeviceRoleHandler(DBusRequest &aRequest) +{ + mCtrlrNcp->GetDeviceRole([aRequest](otError aError, otDeviceRole aRole) mutable { + std::string roleName = (aError == OT_ERROR_NONE) ? GetDeviceRoleName(aRole) : "Error getting device role!"; + + aRequest.Reply(std::tie(roleName)); + }); +} + static_assert(OTBR_SRP_SERVER_STATE_DISABLED == static_cast(OT_SRP_SERVER_STATE_DISABLED), "OTBR_SRP_SERVER_STATE_DISABLED value is incorrect"); static_assert(OTBR_SRP_SERVER_STATE_RUNNING == static_cast(OT_SRP_SERVER_STATE_RUNNING), diff --git a/src/dbus/server/dbus_thread_object.hpp b/src/dbus/server/dbus_thread_object.hpp index c3fa8d56c5f..f258d3a806e 100644 --- a/src/dbus/server/dbus_thread_object.hpp +++ b/src/dbus/server/dbus_thread_object.hpp @@ -42,7 +42,8 @@ #include "dbus/server/dbus_object.hpp" #include "mdns/mdns.hpp" -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread_ncp.hpp" +#include "ncp/controller_openthread_rcp.hpp" namespace otbr { namespace DBus { @@ -72,18 +73,21 @@ class DBusThreadObject : public DBusObject * @param[in] aPublisher The Mdns::Publisher * */ - DBusThreadObject(DBusConnection *aConnection, - const std::string &aInterfaceName, - otbr::Ncp::ControllerOpenThread *aNcp, - Mdns::Publisher *aPublisher); + DBusThreadObject(DBusConnection *aConnection, + const std::string &aInterfaceName, + otbr::Ncp::IControllerOpenThread *aNcp, + Mdns::Publisher *aPublisher); - otbrError Init(void) override; + otbrError Init(void); void RegisterGetPropertyHandler(const std::string &aInterfaceName, const std::string &aPropertyName, const PropertyHandlerType &aHandler) override; private: + void InitRcpMode(void); + void InitNcpMode(void); + void DeviceRoleHandler(otDeviceRole aDeviceRole); void ActiveDatasetChangeHandler(const otOperationalDatasetTlvs &aDatasetTlvs); void NcpResetHandler(void); @@ -175,10 +179,14 @@ class DBusThreadObject : public DBusObject otError GetTelemetryDataHandler(DBusMessageIter &aIter); otError GetCapabilitiesHandler(DBusMessageIter &aIter); + void AsyncGetDeviceRoleHandler(DBusRequest &aRequest); + void ReplyScanResult(DBusRequest &aRequest, otError aError, const std::vector &aResult); void ReplyEnergyScanResult(DBusRequest &aRequest, otError aError, const std::vector &aResult); - otbr::Ncp::ControllerOpenThread *mNcp; + otbr::Ncp::IControllerOpenThread *mCtrlr; + otbr::Ncp::ControllerOpenThreadRcp *mCtrlrRcp; + otbr::Ncp::ControllerOpenThreadNcp *mCtrlrNcp; std::unordered_map mGetPropertyHandlers; otbr::Mdns::Publisher *mPublisher; }; diff --git a/src/ncp/CMakeLists.txt b/src/ncp/CMakeLists.txt index 1540225b677..1a1aa197520 100644 --- a/src/ncp/CMakeLists.txt +++ b/src/ncp/CMakeLists.txt @@ -27,8 +27,14 @@ # add_library(otbr-ncp - ncp_openthread.cpp - ncp_openthread.hpp + controller_openthread_rcp.cpp + controller_openthread_rcp.hpp + controller_openthread.cpp + controller_openthread.hpp + controller_openthread_ncp.cpp + controller_openthread_ncp.hpp + ncp_spinel.cpp + ncp_spinel.hpp ) target_link_libraries(otbr-ncp PRIVATE diff --git a/src/ncp/controller_openthread.cpp b/src/ncp/controller_openthread.cpp new file mode 100644 index 00000000000..a25b0f8e5bf --- /dev/null +++ b/src/ncp/controller_openthread.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define OTBR_LOG_TAG "CTRL_OT" + +#include "controller_openthread.hpp" + +#include +#include + +#include "lib/spinel/coprocessor_type.h" + +#include "controller_openthread_ncp.hpp" +#include "controller_openthread_rcp.hpp" + +namespace otbr { +namespace Ncp { + +IControllerOpenThread *IControllerOpenThread::CreateInstance(const char *aInterfaceName, + const std::vector &aRadioUrls, + const char *aBackboneInterfaceName, + bool aDryRun, + bool aEnableAutoAttach) +{ + otPlatformConfig config; + otInstance *instance; + IControllerOpenThread *controller_instance; + otLogLevel level = ConvertToOtLogLevel(otbrLogGetLevel()); + + VerifyOrDie(aRadioUrls.size() <= OT_PLATFORM_CONFIG_MAX_RADIO_URLS, "Too many Radio URLs!"); + memset(&config, 0, sizeof(config)); + + config.mInterfaceName = aInterfaceName; + config.mBackboneInterfaceName = aBackboneInterfaceName; + config.mDryRun = aDryRun; + + for (const char *url : aRadioUrls) + { + config.mRadioUrls[config.mRadioUrlNum++] = url; + } + config.mSpeedUpFactor = 1; + + VerifyOrDie(otLoggingSetLevel(level) == OT_ERROR_NONE, "Failed to set OT log Level!"); + + instance = otSysInit(&config); + if (config.mCoprocessorType == OT_COPROCESSOR_RCP) + { + controller_instance = new ControllerOpenThreadRcp(instance, config, aEnableAutoAttach); + } + else if (config.mCoprocessorType == OT_COPROCESSOR_NCP) + { + controller_instance = new ControllerOpenThreadNcp(config); + } + else + { + VerifyOrDie(false, "Unknown coprocessor type!"); + } + + return controller_instance; +} + +otLogLevel IControllerOpenThread::ConvertToOtLogLevel(otbrLogLevel aLevel) +{ + otLogLevel level; + + switch (aLevel) + { + case OTBR_LOG_EMERG: + case OTBR_LOG_ALERT: + case OTBR_LOG_CRIT: + level = OT_LOG_LEVEL_CRIT; + break; + case OTBR_LOG_ERR: + case OTBR_LOG_WARNING: + level = OT_LOG_LEVEL_WARN; + break; + case OTBR_LOG_NOTICE: + level = OT_LOG_LEVEL_NOTE; + break; + case OTBR_LOG_INFO: + level = OT_LOG_LEVEL_INFO; + break; + case OTBR_LOG_DEBUG: + default: + level = OT_LOG_LEVEL_DEBG; + break; + } + + return level; +} + +IControllerOpenThread::~IControllerOpenThread(void) +{ + /* empty */ +} + +} // namespace Ncp +} // namespace otbr diff --git a/src/ncp/controller_openthread.hpp b/src/ncp/controller_openthread.hpp new file mode 100644 index 00000000000..118947b938a --- /dev/null +++ b/src/ncp/controller_openthread.hpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes definitions of OpenThead Controller Interface. + */ + +#ifndef OTBR_AGENT_CONTROLLER_OPENTHREAD_HPP_ +#define OTBR_AGENT_CONTROLLER_OPENTHREAD_HPP_ + +#include +#include + +#include +#include + +#include "lib/spinel/coprocessor_type.h" + +#include "common/logging.hpp" + +namespace otbr { +namespace Ncp { + +class IControllerOpenThread +{ +public: + /** + * Create an OpenThread Controller Instance. + * + * This is a factory method that will decide which implementation class will be created. + * + * @param[in] aInterfaceName A string of the Thread interface name. + * @param[in] aRadioUrls The radio URLs (can be IEEE802.15.4 or TREL radio). + * @param[in] aBackboneInterfaceName The Backbone network interface name. + * @param[in] aDryRun TRUE to indicate dry-run mode. FALSE otherwise. + * @param[in] aEnableAutoAttach Whether or not to automatically attach to the saved network. + * + * @retval Non-null OpenThread Controller instance. + * + */ + static IControllerOpenThread *CreateInstance(const char *aInterfaceName, + const std::vector &aRadioUrls, + const char *aBackboneInterfaceName, + bool aDryRun, + bool aEnableAutoAttach); + + /** + * Thread Control API: GetDeviceRole + * + * This method gets the device role and return the role through the handler. + * + * @param[in] aHandler A handler to return the role. + */ + using DeviceRoleHandler = std::function; + virtual void GetDeviceRole(DeviceRoleHandler aHandler) = 0; + + /** + * Returns the co-processor type. + * + */ + virtual CoprocessorType GetCoprocessorType(void) = 0; + + /** + * Returns the Thread interface name. + * + */ + virtual const char *GetInterfaceName(void) const = 0; + + /** + * Returns the Co-processor version string. + * + */ + virtual const char *GetCoprocessorVersion(void) = 0; + + /** + * This method initialize the OpenThread controller. + * + */ + virtual void Init(void) = 0; + + /** + * This method deinitialize the OpenThread controller. + * + */ + virtual void Deinit(void) = 0; + + /** + * The decontructor. + * + */ + virtual ~IControllerOpenThread(void) = 0; + +protected: + static otLogLevel ConvertToOtLogLevel(otbrLogLevel aLevel); +}; + +} // namespace Ncp +} // namespace otbr + +#endif // OTBR_AGENT_CONTROLLER_OPENTHREAD_HPP_ diff --git a/src/ncp/controller_openthread_ncp.cpp b/src/ncp/controller_openthread_ncp.cpp new file mode 100644 index 00000000000..33dd83f0a30 --- /dev/null +++ b/src/ncp/controller_openthread_ncp.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define OTBR_LOG_TAG "CTRL_OT_NCP" + +#include "controller_openthread_ncp.hpp" + +#include "posix/platform/spinel_manager.hpp" + +namespace otbr { +namespace Ncp { + +ControllerOpenThreadNcp::ControllerOpenThreadNcp(const otPlatformConfig &aConfig) + : mConfig(aConfig) +{ +} + +void ControllerOpenThreadNcp::Init(void) +{ + mNcpSpinel.Init(&ot::Posix::SpinelManager::GetSpinelDriver()); +} + +void ControllerOpenThreadNcp::Deinit(void) +{ + mNcpSpinel.Deinit(); + + otSysDeinit(); +} + +void ControllerOpenThreadNcp::GetDeviceRole(DeviceRoleHandler aHandler) +{ + mNcpSpinel.GetDeviceRole(aHandler); +} + +void ControllerOpenThreadNcp::Process(const MainloopContext &aMainloop) +{ + ot::Posix::SpinelManager::GetSpinelDriver().Process(&aMainloop); +} + +void ControllerOpenThreadNcp::Update(MainloopContext &aMainloop) +{ + ot::Posix::SpinelManager::GetSpinelManager().GetSpinelInterface().UpdateFdSet(&aMainloop); + + if (ot::Posix::SpinelManager::GetSpinelDriver().HasPendingFrame()) + { + aMainloop.mTimeout.tv_sec = 0; + aMainloop.mTimeout.tv_usec = 0; + } +} + +} // namespace Ncp +} // namespace otbr diff --git a/src/ncp/controller_openthread_ncp.hpp b/src/ncp/controller_openthread_ncp.hpp new file mode 100644 index 00000000000..b0156ac7dcb --- /dev/null +++ b/src/ncp/controller_openthread_ncp.hpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes definitions of OpenThead Controller for NCP. + */ + +#ifndef OTBR_AGENT_CONTROLLER_OPENTHREAD_NCP_HPP_ +#define OTBR_AGENT_CONTROLLER_OPENTHREAD_NCP_HPP_ + +#include "lib/spinel/coprocessor_type.h" + +#include "controller_openthread.hpp" +#include "ncp_spinel.hpp" +#include "common/mainloop.hpp" + +namespace otbr { +namespace Ncp { + +class ControllerOpenThreadNcp : public MainloopProcessor, public IControllerOpenThread +{ +public: + /** + * Constructor. + * + * @param[in] aPlatformConfig A reference to the platform config. + * + */ + ControllerOpenThreadNcp(const otPlatformConfig &aConfig); + + /** + * Deconstructor. + * + */ + ~ControllerOpenThreadNcp(void) override + { /* empty */ + } + + // IControllerOpenThread methods + void GetDeviceRole(DeviceRoleHandler aHandler) override; + CoprocessorType GetCoprocessorType(void) override { return OT_COPROCESSOR_NCP; } + const char *GetInterfaceName(void) const override { return mConfig.mInterfaceName; } + const char *GetCoprocessorVersion(void) { return mNcpSpinel.GetCoprocessorVersion(); } + void Init(void) override; + void Deinit(void) override; + + // MainloopProcessor methods + void Update(MainloopContext &aMainloop) override; + void Process(const MainloopContext &aMainloop) override; + +private: + otPlatformConfig mConfig; + NcpSpinel mNcpSpinel; +}; + +} // namespace Ncp +} // namespace otbr + +#endif // OTBR_AGENT_CONTROLLER_OPENTHREAD_NCP_HPP_ diff --git a/src/ncp/ncp_openthread.cpp b/src/ncp/controller_openthread_rcp.cpp similarity index 76% rename from src/ncp/ncp_openthread.cpp rename to src/ncp/controller_openthread_rcp.cpp index 80a5d7a2274..8734de5d6bb 100644 --- a/src/ncp/ncp_openthread.cpp +++ b/src/ncp/controller_openthread_rcp.cpp @@ -28,7 +28,7 @@ #define OTBR_LOG_TAG "NCP" -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread_rcp.hpp" #include #include @@ -58,6 +58,8 @@ #include "proto/feature_flag.pb.h" #endif +#include "posix/platform/spinel_manager.hpp" + namespace otbr { namespace Ncp { @@ -66,36 +68,20 @@ static const uint16_t kThreadVersion12 = 3; ///< Thread Version 1.2 static const uint16_t kThreadVersion13 = 4; ///< Thread Version 1.3 static const uint16_t kThreadVersion14 = 5; ///< Thread Version 1.4 -ControllerOpenThread::ControllerOpenThread(const char *aInterfaceName, - const std::vector &aRadioUrls, - const char *aBackboneInterfaceName, - bool aDryRun, - bool aEnableAutoAttach) - : mInstance(nullptr) +ControllerOpenThreadRcp::ControllerOpenThreadRcp(otInstance *aInstance, + const otPlatformConfig &aConfig, + bool aEnableAutoAttach) + : mInstance(aInstance) + , mConfig(aConfig) , mEnableAutoAttach(aEnableAutoAttach) { - VerifyOrDie(aRadioUrls.size() <= OT_PLATFORM_CONFIG_MAX_RADIO_URLS, "Too many Radio URLs!"); - - memset(&mConfig, 0, sizeof(mConfig)); - - mConfig.mInterfaceName = aInterfaceName; - mConfig.mBackboneInterfaceName = aBackboneInterfaceName; - mConfig.mDryRun = aDryRun; - - for (const char *url : aRadioUrls) - { - mConfig.mRadioUrls[mConfig.mRadioUrlNum++] = url; - } - mConfig.mSpeedUpFactor = 1; } -ControllerOpenThread::~ControllerOpenThread(void) +ControllerOpenThreadRcp::~ControllerOpenThreadRcp(void) { - // Make sure OpenThread Instance was gracefully de-initialized. - assert(mInstance == nullptr); } -otbrLogLevel ControllerOpenThread::ConvertToOtbrLogLevel(otLogLevel aLogLevel) +otbrLogLevel ControllerOpenThreadRcp::ConvertToOtbrLogLevel(otLogLevel aLogLevel) { otbrLogLevel otbrLogLevel; @@ -164,37 +150,7 @@ otbrLogLevel ConvertProtoToOtbrLogLevel(ProtoLogLevel aProtoLogLevel) } #endif -otLogLevel ControllerOpenThread::ConvertToOtLogLevel(otbrLogLevel aLevel) -{ - otLogLevel level; - - switch (aLevel) - { - case OTBR_LOG_EMERG: - case OTBR_LOG_ALERT: - case OTBR_LOG_CRIT: - level = OT_LOG_LEVEL_CRIT; - break; - case OTBR_LOG_ERR: - case OTBR_LOG_WARNING: - level = OT_LOG_LEVEL_WARN; - break; - case OTBR_LOG_NOTICE: - level = OT_LOG_LEVEL_NOTE; - break; - case OTBR_LOG_INFO: - level = OT_LOG_LEVEL_INFO; - break; - case OTBR_LOG_DEBUG: - default: - level = OT_LOG_LEVEL_DEBG; - break; - } - - return level; -} - -otError ControllerOpenThread::SetOtbrAndOtLogLevel(otbrLogLevel aLevel) +otError ControllerOpenThreadRcp::SetOtbrAndOtLogLevel(otbrLogLevel aLevel) { otError error = OT_ERROR_NONE; otbrLogSetLevel(aLevel); @@ -202,22 +158,29 @@ otError ControllerOpenThread::SetOtbrAndOtLogLevel(otbrLogLevel aLevel) return error; } -void ControllerOpenThread::Init(void) +void ControllerOpenThreadRcp::Init(void) { otbrError error = OTBR_ERROR_NONE; otLogLevel level = ConvertToOtLogLevel(otbrLogGetLevel()); - #if OTBR_ENABLE_FEATURE_FLAGS && OTBR_ENABLE_TREL FeatureFlagList featureFlagList; #endif VerifyOrExit(otLoggingSetLevel(level) == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD); - mInstance = otSysInit(&mConfig); + // There are two cases: + // 1. The `Init` is called after `CreateInstance`. In this case, `otSysInit` has been called + // and an otInstance has been created. So there is no need to create an instance again. + // 2. `Reset` is called. `Deinit` is called first and then `Init` is called again. In this + // case need to call `otSysInit` to reset the co-processor and creat an otInstance again. + if (mInstance == nullptr) + { + mInstance = otSysInit(&mConfig); + } assert(mInstance != nullptr); { - otError result = otSetStateChangedCallback(mInstance, &ControllerOpenThread::HandleStateChanged, this); + otError result = otSetStateChangedCallback(mInstance, &ControllerOpenThreadRcp::HandleStateChanged, this); agent::ThreadHelper::LogOpenThreadResult("Set state callback", result); VerifyOrExit(result == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD); @@ -258,7 +221,7 @@ void ControllerOpenThread::Init(void) } #if OTBR_ENABLE_FEATURE_FLAGS -otError ControllerOpenThread::ApplyFeatureFlagList(const FeatureFlagList &aFeatureFlagList) +otError ControllerOpenThreadRcp::ApplyFeatureFlagList(const FeatureFlagList &aFeatureFlagList) { otError error = OT_ERROR_NONE; // Save a cached copy of feature flags for debugging purpose. @@ -294,7 +257,7 @@ otError ControllerOpenThread::ApplyFeatureFlagList(const FeatureFlagList &aFeatu } #endif -void ControllerOpenThread::Deinit(void) +void ControllerOpenThreadRcp::Deinit(void) { assert(mInstance != nullptr); @@ -305,7 +268,7 @@ void ControllerOpenThread::Deinit(void) mResetHandlers.clear(); } -void ControllerOpenThread::HandleStateChanged(otChangedFlags aFlags) +void ControllerOpenThreadRcp::HandleStateChanged(otChangedFlags aFlags) { for (auto &stateCallback : mThreadStateChangedCallbacks) { @@ -315,7 +278,7 @@ void ControllerOpenThread::HandleStateChanged(otChangedFlags aFlags) mThreadHelper->StateChangedCallback(aFlags); } -void ControllerOpenThread::Update(MainloopContext &aMainloop) +void ControllerOpenThreadRcp::Update(MainloopContext &aMainloop) { if (otTaskletsArePending(mInstance)) { @@ -325,7 +288,7 @@ void ControllerOpenThread::Update(MainloopContext &aMainloop) otSysMainloopUpdate(mInstance, &aMainloop); } -void ControllerOpenThread::Process(const MainloopContext &aMainloop) +void ControllerOpenThreadRcp::Process(const MainloopContext &aMainloop) { otTaskletsProcess(mInstance); @@ -337,32 +300,32 @@ void ControllerOpenThread::Process(const MainloopContext &aMainloop) } } -bool ControllerOpenThread::IsAutoAttachEnabled(void) +bool ControllerOpenThreadRcp::IsAutoAttachEnabled(void) { return mEnableAutoAttach; } -void ControllerOpenThread::DisableAutoAttach(void) +void ControllerOpenThreadRcp::DisableAutoAttach(void) { mEnableAutoAttach = false; } -void ControllerOpenThread::PostTimerTask(Milliseconds aDelay, TaskRunner::Task aTask) +void ControllerOpenThreadRcp::PostTimerTask(Milliseconds aDelay, TaskRunner::Task aTask) { mTaskRunner.Post(std::move(aDelay), std::move(aTask)); } -void ControllerOpenThread::RegisterResetHandler(std::function aHandler) +void ControllerOpenThreadRcp::RegisterResetHandler(std::function aHandler) { mResetHandlers.emplace_back(std::move(aHandler)); } -void ControllerOpenThread::AddThreadStateChangedCallback(ThreadStateChangedCallback aCallback) +void ControllerOpenThreadRcp::AddThreadStateChangedCallback(ThreadStateChangedCallback aCallback) { mThreadStateChangedCallbacks.emplace_back(std::move(aCallback)); } -void ControllerOpenThread::Reset(void) +void ControllerOpenThreadRcp::Reset(void) { gPlatResetReason = OT_PLAT_RESET_REASON_SOFTWARE; @@ -377,7 +340,7 @@ void ControllerOpenThread::Reset(void) mEnableAutoAttach = true; } -const char *ControllerOpenThread::GetThreadVersion(void) +const char *ControllerOpenThreadRcp::GetThreadVersion(void) { const char *version; @@ -402,6 +365,12 @@ const char *ControllerOpenThread::GetThreadVersion(void) return version; } +void ControllerOpenThreadRcp::GetDeviceRole(DeviceRoleHandler aHandler) +{ + otDeviceRole role = otThreadGetDeviceRole(mInstance); + aHandler(OT_ERROR_NONE, role); +} + /* * Provide, if required an "otPlatLog()" function */ @@ -409,7 +378,7 @@ extern "C" void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const ch { OT_UNUSED_VARIABLE(aLogRegion); - otbrLogLevel otbrLogLevel = ControllerOpenThread::ConvertToOtbrLogLevel(aLogLevel); + otbrLogLevel otbrLogLevel = ControllerOpenThreadRcp::ConvertToOtbrLogLevel(aLogLevel); va_list ap; va_start(ap, aFormat); @@ -419,7 +388,7 @@ extern "C" void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const ch extern "C" void otPlatLogHandleLevelChanged(otLogLevel aLogLevel) { - otbrLogSetLevel(ControllerOpenThread::ConvertToOtbrLogLevel(aLogLevel)); + otbrLogSetLevel(ControllerOpenThreadRcp::ConvertToOtbrLogLevel(aLogLevel)); otbrLogInfo("OpenThread log level changed to %d", aLogLevel); } diff --git a/src/ncp/ncp_openthread.hpp b/src/ncp/controller_openthread_rcp.hpp similarity index 82% rename from src/ncp/ncp_openthread.hpp rename to src/ncp/controller_openthread_rcp.hpp index 51ba31f4724..ca78c3da4de 100644 --- a/src/ncp/ncp_openthread.hpp +++ b/src/ncp/controller_openthread_rcp.hpp @@ -28,11 +28,11 @@ /** * @file - * This file includes definitions for NCP service. + * This file includes definitions of OpenThead Controller for RCP. */ -#ifndef OTBR_AGENT_NCP_OPENTHREAD_HPP_ -#define OTBR_AGENT_NCP_OPENTHREAD_HPP_ +#ifndef OTBR_AGENT_CONTROLLER_OPENTHREAD_RCP_HPP_ +#define OTBR_AGENT_CONTROLLER_OPENTHREAD_RCP_HPP_ #include "openthread-br/config.h" @@ -49,6 +49,10 @@ #include "common/mainloop.hpp" #include "common/task_runner.hpp" #include "common/types.hpp" +#include "lib/spinel/coprocessor_type.h" + +#include "controller_openthread.hpp" +#include "ncp_spinel.hpp" #include "utils/thread_helper.hpp" namespace otbr { @@ -60,10 +64,10 @@ class FeatureFlagList; namespace Ncp { /** - * This interface defines NCP Controller functionality. + * This interface defines OpenThread Controller (for RCP) functionality. * */ -class ControllerOpenThread : public MainloopProcessor +class ControllerOpenThreadRcp : public MainloopProcessor, public IControllerOpenThread { public: using ThreadStateChangedCallback = std::function; @@ -71,35 +75,29 @@ class ControllerOpenThread : public MainloopProcessor /** * This constructor initializes this object. * - * @param[in] aInterfaceName A string of the NCP interface name. - * @param[in] aRadioUrls The radio URLs (can be IEEE802.15.4 or TREL radio). - * @param[in] aBackboneInterfaceName The Backbone network interface name. - * @param[in] aDryRun TRUE to indicate dry-run mode. FALSE otherwise. - * @param[in] aEnableAutoAttach Whether or not to automatically attach to the saved network. + * @param[in] aInstance A pointer to an otInstance. + * @param[in] aConfig A reference to The platform config. + * @param[in] aEnableAutoAttach Whether or not to automatically attach to the saved network. * */ - ControllerOpenThread(const char *aInterfaceName, - const std::vector &aRadioUrls, - const char *aBackboneInterfaceName, - bool aDryRun, - bool aEnableAutoAttach); + ControllerOpenThreadRcp(otInstance *aInstance, const otPlatformConfig &aConfig, bool aEnableAutoAttach); /** * This method initialize the NCP controller. * */ - void Init(void); + void Init(void) override; /** * This method deinitialize the NCP controller. * */ - void Deinit(void); + void Deinit(void) override; /** * Returns an OpenThread instance. * - * @retval Non-null OpenThread instance if `ControllerOpenThread::Init()` has been called. + * @retval Non-null OpenThread instance if `ControllerOpenThreadRcp::Init()` has been called. * Otherwise, it's guaranteed to be `null` */ otInstance *GetInstance(void) { return mInstance; } @@ -164,7 +162,7 @@ class ControllerOpenThread : public MainloopProcessor * @returns A pointer to the Thread network interface name string. * */ - const char *GetInterfaceName(void) const { return mConfig.mInterfaceName; } + const char *GetInterfaceName(void) const override { return mConfig.mInterfaceName; } static otbrLogLevel ConvertToOtbrLogLevel(otLogLevel aLogLevel); @@ -191,12 +189,24 @@ class ControllerOpenThread : public MainloopProcessor } #endif - ~ControllerOpenThread(void) override; + ~ControllerOpenThreadRcp(void) override; + + void GetDeviceRole(DeviceRoleHandler aHandler) override; + + CoprocessorType GetCoprocessorType(void) override + { + return OT_COPROCESSOR_RCP; + } + + const char *GetCoprocessorVersion(void) override + { + return otPlatRadioGetVersionString(mInstance); + } private: static void HandleStateChanged(otChangedFlags aFlags, void *aContext) { - static_cast(aContext)->HandleStateChanged(aFlags); + static_cast(aContext)->HandleStateChanged(aFlags); } void HandleStateChanged(otChangedFlags aFlags); @@ -216,8 +226,6 @@ class ControllerOpenThread : public MainloopProcessor bool IsAutoAttachEnabled(void); void DisableAutoAttach(void); - static otLogLevel ConvertToOtLogLevel(otbrLogLevel aLevel); - otError SetOtbrAndOtLogLevel(otbrLogLevel aLevel); otInstance *mInstance; @@ -237,4 +245,4 @@ class ControllerOpenThread : public MainloopProcessor } // namespace Ncp } // namespace otbr -#endif // OTBR_AGENT_NCP_OPENTHREAD_HPP_ +#endif // OTBR_AGENT_CONTROLLER_OPENTHREAD_RCP_HPP_ diff --git a/src/ncp/ncp_spinel.cpp b/src/ncp/ncp_spinel.cpp new file mode 100644 index 00000000000..227812263fb --- /dev/null +++ b/src/ncp/ncp_spinel.cpp @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define OTBR_LOG_TAG "NcpSpinel" + +#include "ncp_spinel.hpp" + +#include + +#include + +#include "common/code_utils.hpp" +#include "common/logging.hpp" +#include "lib/spinel/spinel.h" +#include "lib/spinel/spinel_driver.hpp" + +namespace otbr { +namespace Ncp { + +constexpr spinel_tid_t sTid = 1; ///< 1 will be used the Tid for all the APIs of NcpSpinel + +NcpSpinel::NcpSpinel(void) + : mSpinelDriver(nullptr) + , mCmdTidsInUse(0) + , mCmdNextTid(1) + , mDeviceRole(OT_DEVICE_ROLE_DISABLED) + , mGetDeviceRoleHandler(nullptr) +{ + memset(mWaitingKeyTable, 0xff, sizeof(mWaitingKeyTable)); +} + +NcpSpinel::~NcpSpinel(void) = default; + +void NcpSpinel::Init(ot::Spinel::SpinelDriver *aSpinelDriver) +{ + mSpinelDriver = aSpinelDriver; + mSpinelDriver->SetFrameHandler(&HandleReceivedFrame, &HandleSavedFrame, this); +} + +void NcpSpinel::Deinit(void) +{ + mSpinelDriver = nullptr; +} + +void NcpSpinel::GetDeviceRole(GetDeviceRoleHandler aHandler) +{ + otError error = OT_ERROR_NONE; + spinel_tid_t tid = GetNextTid(); + va_list args; + + error = mSpinelDriver->SendCommand(SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_NET_ROLE, tid, nullptr, args); + if (error != OT_ERROR_NONE) + { + FreeTid(tid); + aHandler(error, OT_DEVICE_ROLE_DISABLED); + } + mWaitingKeyTable[tid] = SPINEL_PROP_NET_ROLE; + + mGetDeviceRoleHandler = aHandler; + + return; +} + +void NcpSpinel::HandleReceivedFrame(const uint8_t *aFrame, + uint16_t aLength, + uint8_t aHeader, + bool &aSave, + void *aContext) +{ + static_cast(aContext)->HandleReceivedFrame(aFrame, aLength, aHeader, aSave); +} + +void NcpSpinel::HandleReceivedFrame(const uint8_t *aFrame, uint16_t aLength, uint8_t aHeader, bool &aShouldSaveFrame) +{ + spinel_tid_t tid = SPINEL_HEADER_GET_TID(aHeader); + + if (tid == 0) + { + HandleNotification(aFrame, aLength); + } + else if (tid < kMaxTids) + { + HandleResponse(tid, aFrame, aLength); + } + else + { + otbrLogCrit("Received unexpected tid: %u", sTid); + } + + aShouldSaveFrame = false; +} + +void NcpSpinel::HandleSavedFrame(const uint8_t *aFrame, uint16_t aLength, void *aContext) +{ + OT_UNUSED_VARIABLE(aFrame); + OT_UNUSED_VARIABLE(aLength); + OT_UNUSED_VARIABLE(aContext); +} + +void NcpSpinel::HandleNotification(const uint8_t *aFrame, uint16_t aLength) +{ + spinel_prop_key_t key; + spinel_size_t len = 0; + spinel_ssize_t unpacked; + uint8_t *data = nullptr; + uint32_t cmd; + uint8_t header; + otbrError error = OTBR_ERROR_NONE; + + unpacked = spinel_datatype_unpack(aFrame, aLength, "CiiD", &header, &cmd, &key, &data, &len); + VerifyOrExit(unpacked > 0, error = OTBR_ERROR_PARSE); + VerifyOrExit(SPINEL_HEADER_GET_TID(header) == 0, error = OTBR_ERROR_PARSE); + VerifyOrExit(cmd == SPINEL_CMD_PROP_VALUE_IS); + HandleValueIs(key, data, static_cast(len)); + +exit: + if (error != OTBR_ERROR_NONE) + { + otbrLogResult(error, "HandleNotification: %s", __FUNCTION__); + } +} + +void NcpSpinel::HandleResponse(spinel_tid_t aTid, const uint8_t *aFrame, uint16_t aLength) +{ + spinel_prop_key_t key; + spinel_size_t len = 0; + spinel_ssize_t unpacked; + uint8_t *data = nullptr; + uint32_t cmd; + uint8_t header; + otError error = OT_ERROR_NONE; + + unpacked = spinel_datatype_unpack(aFrame, aLength, "CiiD", &header, &cmd, &key, &data, &len); + VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE); + + VerifyOrExit(cmd == SPINEL_CMD_PROP_VALUE_IS && key == mWaitingKeyTable[aTid], error = OT_ERROR_INVALID_STATE); + + if (key == SPINEL_PROP_NET_ROLE) + { + spinel_net_role_t spinelRole; + otDeviceRole role; + unpacked = spinel_datatype_unpack(data, len, "i", &spinelRole); + + switch (spinelRole) + { + case SPINEL_NET_ROLE_DISABLED: + role = OT_DEVICE_ROLE_DISABLED; + break; + case SPINEL_NET_ROLE_DETACHED: + role = OT_DEVICE_ROLE_DETACHED; + break; + case SPINEL_NET_ROLE_CHILD: + role = OT_DEVICE_ROLE_CHILD; + break; + case SPINEL_NET_ROLE_ROUTER: + role = OT_DEVICE_ROLE_ROUTER; + break; + case SPINEL_NET_ROLE_LEADER: + role = OT_DEVICE_ROLE_LEADER; + break; + } + + if (mGetDeviceRoleHandler) + { + mGetDeviceRoleHandler(error, role); + } + } + +exit: + if (error == OT_ERROR_INVALID_STATE) + { + otbrLogCrit("Received unexpected response with cmd:%u, key:%u, waiting key:%u for tid:%u", cmd, key, + mWaitingKeyTable[aTid], aTid); + } +} + +void NcpSpinel::HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength) +{ + otbrError error = OTBR_ERROR_NONE; + spinel_ssize_t unpacked; + + if (aKey == SPINEL_PROP_LAST_STATUS) + { + spinel_status_t status = SPINEL_STATUS_OK; + + unpacked = spinel_datatype_unpack(aBuffer, aLength, "i", &status); + VerifyOrExit(unpacked > 0, error = OTBR_ERROR_PARSE); + + otbrLogInfo("NCP last status: %s", spinel_status_to_cstr(status)); + } + else if (aKey == SPINEL_PROP_NET_ROLE) + { + spinel_net_role_t role; + + unpacked = spinel_datatype_unpack(aBuffer, aLength, "C", &role); + VerifyOrExit(unpacked > 0, error = OTBR_ERROR_PARSE); + + switch (role) + { + case SPINEL_NET_ROLE_DETACHED: + mDeviceRole = OT_DEVICE_ROLE_DETACHED; + break; + case SPINEL_NET_ROLE_CHILD: + mDeviceRole = OT_DEVICE_ROLE_CHILD; + break; + case SPINEL_NET_ROLE_ROUTER: + mDeviceRole = OT_DEVICE_ROLE_ROUTER; + break; + case SPINEL_NET_ROLE_LEADER: + mDeviceRole = OT_DEVICE_ROLE_LEADER; + break; + case SPINEL_NET_ROLE_DISABLED: + mDeviceRole = OT_DEVICE_ROLE_DISABLED; + break; + } + + otbrLogInfo("Device role changed to %s", otThreadDeviceRoleToString(mDeviceRole)); + } + +exit: + otbrLogResult(error, "NcpSpinel: %s", __FUNCTION__); + return; +} + +spinel_tid_t NcpSpinel::GetNextTid(void) +{ + spinel_tid_t tid = mCmdNextTid; + + while (((1 << tid) & mCmdTidsInUse) != 0) + { + tid = SPINEL_GET_NEXT_TID(tid); + + if (tid == mCmdNextTid) + { + // We looped back to `mCmdNextTid` indicating that all + // TIDs are in-use. + + ExitNow(tid = 0); + } + } + + mCmdTidsInUse |= (1 << tid); + mCmdNextTid = SPINEL_GET_NEXT_TID(tid); + +exit: + return tid; +} + +} // namespace Ncp +} // namespace otbr diff --git a/src/ncp/ncp_spinel.hpp b/src/ncp/ncp_spinel.hpp new file mode 100644 index 00000000000..3bf2866fa1d --- /dev/null +++ b/src/ncp/ncp_spinel.hpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes definitions for the spinel based Thread controller. + */ + +#ifndef OTBR_AGENT_NCP_SPINEL_HPP_ +#define OTBR_AGENT_NCP_SPINEL_HPP_ + +#include + +#include +#include +#include + +#include "lib/spinel/spinel.h" +#include "lib/spinel/spinel_driver.hpp" + +namespace otbr { +namespace Ncp { + +/** + * The class for controlling the Thread stack on the neetwork NCP co-processor (NCP). + * + */ +class NcpSpinel +{ +public: + /** + * Constructor. + * + */ + NcpSpinel(void); + + /** + * Destructor. + * + */ + ~NcpSpinel(void); + + /** + * Do the initialization. + * + * @param[in] aSoftwareReset TRUE to try SW reset first, FALSE to directly try HW reset. + * @param[in] aSpinelDriver Pointer to the SpinelDriver instance that this object depends. + * + */ + void Init(ot::Spinel::SpinelDriver *aSpinelDriver); + + /** + * Do the de-initialization. + * + */ + void Deinit(void); + + /** + * Returns the Co-processor version string. + * + */ + const char *GetCoprocessorVersion(void) { return mSpinelDriver->GetVersion(); } + + using GetDeviceRoleHandler = std::function; + void GetDeviceRole(GetDeviceRoleHandler aHandler); + +private: + static constexpr uint8_t kMaxTids = 16; + + static void HandleReceivedFrame(const uint8_t *aFrame, + uint16_t aLength, + uint8_t aHeader, + bool &aSave, + void *aContext); + void HandleReceivedFrame(const uint8_t *aFrame, uint16_t aLength, uint8_t aHeader, bool &aShouldSaveFrame); + static void HandleSavedFrame(const uint8_t *aFrame, uint16_t aLength, void *aContext); + + void HandleNotification(const uint8_t *aFrame, uint16_t aLength); + void HandleResponse(spinel_tid_t aTid, const uint8_t *aFrame, uint16_t aLength); + void HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength); + + spinel_tid_t GetNextTid(void); + void FreeTid(spinel_tid_t tid) { mCmdTidsInUse &= ~(1 << tid); } + + ot::Spinel::SpinelDriver *mSpinelDriver; + uint16_t mCmdTidsInUse; ///< Used transaction ids. + spinel_tid_t mCmdNextTid; ///< Next available transaction id. + spinel_prop_key_t mWaitingKeyTable[kMaxTids]; ///< The property key of current transaction. + + otDeviceRole mDeviceRole; + GetDeviceRoleHandler mGetDeviceRoleHandler; +}; + +} // namespace Ncp +} // namespace otbr + +#endif // OTBR_AGENT_NCP_SPINEL_HPP_ diff --git a/src/openwrt/ubus/otubus.cpp b/src/openwrt/ubus/otubus.cpp index 4dfaac2ac04..83007e12d77 100644 --- a/src/openwrt/ubus/otubus.cpp +++ b/src/openwrt/ubus/otubus.cpp @@ -44,7 +44,7 @@ #include #include "common/logging.hpp" -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread_rcp.hpp" namespace otbr { namespace ubus { @@ -58,12 +58,12 @@ const static int PANID_LENGTH = 10; const static int XPANID_LENGTH = 64; const static int NETWORKKEY_LENGTH = 64; -UbusServer::UbusServer(Ncp::ControllerOpenThread *aController, std::mutex *aMutex) +UbusServer::UbusServer(Ncp::ControllerOpenThreadRcp *aCtrlr, std::mutex *aMutex) : mIfFinishScan(false) , mContext(nullptr) , mSockPath(nullptr) - , mController(aController) - , mNcpThreadMutex(aMutex) + , mController(aCtrlr) + , mCtrlrThreadMutex(aMutex) , mSecond(0) { memset(&mNetworkdataBuf, 0, sizeof(mNetworkdataBuf)); @@ -78,9 +78,9 @@ UbusServer &UbusServer::GetInstance(void) return *sUbusServerInstance; } -void UbusServer::Initialize(Ncp::ControllerOpenThread *aController, std::mutex *aMutex) +void UbusServer::Initialize(Ncp::ControllerOpenThreadRcp *aCtrlr, std::mutex *aMutex) { - sUbusServerInstance = new UbusServer(aController, aMutex); + sUbusServerInstance = new UbusServer(aCtrlr, aMutex); } enum @@ -229,11 +229,11 @@ void UbusServer::ProcessScan(void) uint32_t scanChannels = 0; uint16_t scanDuration = 0; - mNcpThreadMutex->lock(); + mCtrlrThreadMutex->lock(); SuccessOrExit(error = otLinkActiveScan(mController->GetInstance(), scanChannels, scanDuration, &UbusServer::HandleActiveScanResult, this)); exit: - mNcpThreadMutex->unlock(); + mCtrlrThreadMutex->unlock(); return; } @@ -679,7 +679,7 @@ int UbusServer::UbusLeaveHandlerDetail(struct ubus_context *aContext, uint64_t eventNum; ssize_t retval; - mNcpThreadMutex->lock(); + mCtrlrThreadMutex->lock(); otInstanceFactoryReset(mController->GetInstance()); eventNum = 1; @@ -693,7 +693,7 @@ int UbusServer::UbusLeaveHandlerDetail(struct ubus_context *aContext, blob_buf_init(&mBuf, 0); exit: - mNcpThreadMutex->unlock(); + mCtrlrThreadMutex->unlock(); AppendResult(error, aContext, aRequest); return 0; } @@ -714,19 +714,19 @@ int UbusServer::UbusThreadHandler(struct ubus_context *aContext, if (!strcmp(aAction, "start")) { - mNcpThreadMutex->lock(); + mCtrlrThreadMutex->lock(); SuccessOrExit(error = otIp6SetEnabled(mController->GetInstance(), true)); SuccessOrExit(error = otThreadSetEnabled(mController->GetInstance(), true)); } else if (!strcmp(aAction, "stop")) { - mNcpThreadMutex->lock(); + mCtrlrThreadMutex->lock(); SuccessOrExit(error = otThreadSetEnabled(mController->GetInstance(), false)); SuccessOrExit(error = otIp6SetEnabled(mController->GetInstance(), false)); } exit: - mNcpThreadMutex->unlock(); + mCtrlrThreadMutex->unlock(); AppendResult(error, aContext, aRequest); return 0; } @@ -750,7 +750,7 @@ int UbusServer::UbusParentHandlerDetail(struct ubus_context *aContext, blob_buf_init(&mBuf, 0); - mNcpThreadMutex->lock(); + mCtrlrThreadMutex->lock(); SuccessOrExit(error = otThreadGetParentInfo(mController->GetInstance(), &parentInfo)); jsonArray = blobmsg_open_array(&mBuf, "parent_list"); @@ -772,7 +772,7 @@ int UbusServer::UbusParentHandlerDetail(struct ubus_context *aContext, blobmsg_close_array(&mBuf, jsonArray); exit: - mNcpThreadMutex->unlock(); + mCtrlrThreadMutex->unlock(); AppendResult(error, aContext, aRequest); return error; } @@ -799,7 +799,7 @@ int UbusServer::UbusNeighborHandlerDetail(struct ubus_context *aContext, sJsonUri = blobmsg_open_array(&mBuf, "neighbor_list"); - mNcpThreadMutex->lock(); + mCtrlrThreadMutex->lock(); while (otThreadGetNextNeighborInfo(mController->GetInstance(), &iterator, &neighborInfo) == OT_ERROR_NONE) { jsonList = blobmsg_open_table(&mBuf, nullptr); @@ -847,7 +847,7 @@ int UbusServer::UbusNeighborHandlerDetail(struct ubus_context *aContext, blobmsg_close_array(&mBuf, sJsonUri); - mNcpThreadMutex->unlock(); + mCtrlrThreadMutex->unlock(); AppendResult(error, aContext, aRequest); return 0; @@ -944,7 +944,7 @@ int UbusServer::UbusCommissioner(struct ubus_context *aContext, otError error = OT_ERROR_NONE; - mNcpThreadMutex->lock(); + mCtrlrThreadMutex->lock(); if (!strcmp(aAction, "start")) { @@ -1010,7 +1010,7 @@ int UbusServer::UbusCommissioner(struct ubus_context *aContext, } exit: - mNcpThreadMutex->unlock(); + mCtrlrThreadMutex->unlock(); blob_buf_init(&mBuf, 0); AppendResult(error, aContext, aRequest); return 0; @@ -1087,7 +1087,7 @@ int UbusServer::UbusGetInformation(struct ubus_context *aContext, blob_buf_init(&mBuf, 0); - mNcpThreadMutex->lock(); + mCtrlrThreadMutex->lock(); if (!strcmp(aAction, "networkname")) blobmsg_add_string(&mBuf, "NetworkName", otThreadGetNetworkName(mController->GetInstance())); else if (!strcmp(aAction, "interfacename")) @@ -1304,7 +1304,7 @@ int UbusServer::UbusGetInformation(struct ubus_context *aContext, AppendResult(error, aContext, aRequest); exit: - mNcpThreadMutex->unlock(); + mCtrlrThreadMutex->unlock(); return 0; } @@ -1440,7 +1440,7 @@ int UbusServer::UbusSetInformation(struct ubus_context *aContext, blob_buf_init(&mBuf, 0); - mNcpThreadMutex->lock(); + mCtrlrThreadMutex->lock(); if (!strcmp(aAction, "networkname")) { struct blob_attr *tb[SET_NETWORK_MAX]; @@ -1614,7 +1614,7 @@ int UbusServer::UbusSetInformation(struct ubus_context *aContext, } exit: - mNcpThreadMutex->unlock(); + mCtrlrThreadMutex->unlock(); AppendResult(error, aContext, aRequest); return 0; } @@ -1806,11 +1806,13 @@ int UbusServer::Hex2Bin(const char *aHex, uint8_t *aBin, uint16_t aBinLength) return rval; } -void UBusAgent::Init(void) +void UBusAgent::Init(Ncp::OpenThreadController *aCtrlr) { + mCtrlr = aCtrlr; + otbr::ubus::sUbusEfd = eventfd(0, 0); - otbr::ubus::UbusServer::Initialize(&mNcp, &mThreadMutex); + otbr::ubus::UbusServer::Initialize(mCtrlr, &mThreadMutex); if (otbr::ubus::sUbusEfd == -1) { diff --git a/src/openwrt/ubus/otubus.hpp b/src/openwrt/ubus/otubus.hpp index d82b6c25bb0..be63e50bfb0 100644 --- a/src/openwrt/ubus/otubus.hpp +++ b/src/openwrt/ubus/otubus.hpp @@ -46,7 +46,7 @@ #include "common/code_utils.hpp" #include "common/mainloop.hpp" -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread_rcp.hpp" extern "C" { #include @@ -58,7 +58,7 @@ extern "C" { namespace otbr { namespace Ncp { -class ControllerOpenThread; +class ControllerOpenThreadRcp; } namespace ubus { @@ -77,10 +77,10 @@ class UbusServer /** * Constructor * - * @param[in] aController A pointer to OpenThread Controller structure. + * @param[in] aCtrlr A pointer to OpenThread Controller structure. * @param[in] aMutex A pointer to mutex. */ - static void Initialize(Ncp::ControllerOpenThread *aController, std::mutex *aMutex); + static void Initialize(Ncp::ControllerOpenThreadRcp *aCtrlr, std::mutex *aMutex); /** * This method return the instance of the global UbusServer. @@ -787,14 +787,14 @@ class UbusServer void HandleDiagnosticGetResponse(otError aError, otMessage *aMessage, const otMessageInfo *aMessageInfo); private: - bool mIfFinishScan; - struct ubus_context *mContext; - const char *mSockPath; - struct blob_buf mBuf; - struct blob_buf mNetworkdataBuf; - Ncp::ControllerOpenThread *mController; - std::mutex *mNcpThreadMutex; - time_t mSecond; + bool mIfFinishScan; + struct ubus_context *mContext; + const char *mSockPath; + struct blob_buf mBuf; + struct blob_buf mNetworkdataBuf; + Ncp::ControllerOpenThreadRcp *mController; + std::mutex *mCtrlrThreadMutex; + time_t mSecond; enum { kDefaultJoinerTimeout = 120, @@ -803,10 +803,10 @@ class UbusServer /** * Constructor * - * @param[in] aController The pointer to OpenThread Controller structure. + * @param[in] aCtrlr The pointer to OpenThread Controller structure. * @param[in] aMutex A pointer to mutex. */ - UbusServer(Ncp::ControllerOpenThread *aController, std::mutex *aMutex); + UbusServer(Ncp::ControllerOpenThreadRcp *aCtrlr, std::mutex *aMutex); /** * This method start scan. @@ -1152,8 +1152,8 @@ class UBusAgent : public MainloopProcessor * @param[in] aNcp A reference to the NCP controller. * */ - UBusAgent(otbr::Ncp::ControllerOpenThread &aNcp) - : mNcp(aNcp) + UBusAgent(void) + : mCtrlr(nullptr) , mThreadMutex() { } @@ -1162,7 +1162,7 @@ class UBusAgent : public MainloopProcessor * This method initializes the UBus agent. * */ - void Init(void); + void Init(Ncp::OpenThreadController *aCtrlr); void Update(MainloopContext &aMainloop) override; void Process(const MainloopContext &aMainloop) override; @@ -1170,8 +1170,8 @@ class UBusAgent : public MainloopProcessor private: static void UbusServerRun(void) { otbr::ubus::UbusServer::GetInstance().InstallUbusObject(); } - otbr::Ncp::ControllerOpenThread &mNcp; - std::mutex mThreadMutex; + otbr::Ncp::ControllerOpenThreadRcp *mCtrlr; + std::mutex mThreadMutex; }; } // namespace ubus } // namespace otbr diff --git a/src/rest/resource.cpp b/src/rest/resource.cpp index 6b1647b84d9..e0da8375655 100644 --- a/src/rest/resource.cpp +++ b/src/rest/resource.cpp @@ -121,9 +121,9 @@ static std::string GetHttpStatus(HttpStatusCode aErrorCode) return httpStatus; } -Resource::Resource(ControllerOpenThread *aNcp) +Resource::Resource(void) : mInstance(nullptr) - , mNcp(aNcp) + , mCtrlr(nullptr) { // Resource Handler mResourceMap.emplace(OT_REST_RESOURCE_PATH_DIAGNOSTICS, &Resource::Diagnostic); @@ -144,9 +144,11 @@ Resource::Resource(ControllerOpenThread *aNcp) mResourceCallbackMap.emplace(OT_REST_RESOURCE_PATH_DIAGNOSTICS, &Resource::HandleDiagnosticCallback); } -void Resource::Init(void) +void Resource::Init(ControllerOpenThread *aNcp) { - mInstance = mNcp->GetThreadHelper()->GetInstance(); + mCtrlr = aNcp; + + mInstance = mCtrlr->GetThreadHelper()->GetInstance(); } void Resource::Handle(Request &aRequest, Response &aResponse) const @@ -262,9 +264,9 @@ void Resource::DeleteNodeInfo(Response &aResponse) const otbrError error = OTBR_ERROR_NONE; std::string errorCode; - VerifyOrExit(mNcp->GetThreadHelper()->Detach() == OT_ERROR_NONE, error = OTBR_ERROR_INVALID_STATE); + VerifyOrExit(mCtrlr->GetThreadHelper()->Detach() == OT_ERROR_NONE, error = OTBR_ERROR_INVALID_STATE); VerifyOrExit(otInstanceErasePersistentInfo(mInstance) == OT_ERROR_NONE, error = OTBR_ERROR_REST); - mNcp->Reset(); + mCtrlr->Reset(); exit: if (error == OTBR_ERROR_NONE) diff --git a/src/rest/resource.hpp b/src/rest/resource.hpp index d79085dbfcb..def36b50edf 100644 --- a/src/rest/resource.hpp +++ b/src/rest/resource.hpp @@ -42,7 +42,7 @@ #include #include "common/api_strings.hpp" -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread_rcp.hpp" #include "openthread/dataset.h" #include "openthread/dataset_ftd.h" #include "rest/json.hpp" @@ -50,7 +50,7 @@ #include "rest/response.hpp" #include "utils/thread_helper.hpp" -using otbr::Ncp::ControllerOpenThread; +using otbr::Ncp::ControllerOpenThreadRcp; using std::chrono::steady_clock; namespace otbr { @@ -66,17 +66,16 @@ class Resource /** * The constructor initializes the resource handler instance. * - * @param[in] aNcp A pointer to the NCP controller. - * */ - Resource(ControllerOpenThread *aNcp); + Resource(void); /** * This method initialize the Resource handler. * + * @param[in] aNcp A pointer to the NCP controller. * */ - void Init(void); + void Init(ControllerOpenThreadRcp *aNcp); /** * This method is the main entry of resource handler, which find corresponding handler according to request url @@ -160,8 +159,8 @@ class Resource void *aContext); void DiagnosticResponseHandler(otError aError, const otMessage *aMessage, const otMessageInfo *aMessageInfo); - otInstance *mInstance; - ControllerOpenThread *mNcp; + otInstance *mInstance; + ControllerOpenThreadRcp *mCtrlr; std::unordered_map mResourceMap; std::unordered_map mResourceCallbackMap; diff --git a/src/rest/rest_web_server.cpp b/src/rest/rest_web_server.cpp index 0327bb44eac..7df69e61c9a 100644 --- a/src/rest/rest_web_server.cpp +++ b/src/rest/rest_web_server.cpp @@ -47,8 +47,8 @@ namespace rest { // Maximum number of connection a server support at the same time. static const uint32_t kMaxServeNum = 500; -RestWebServer::RestWebServer(ControllerOpenThread &aNcp, const std::string &aRestListenAddress, int aRestListenPort) - : mResource(Resource(&aNcp)) +RestWebServer::RestWebServer(const std::string &aRestListenAddress, int aRestListenPort) + : mResource() , mListenFd(-1) { mAddress.sin6_family = AF_INET6; @@ -71,9 +71,9 @@ RestWebServer::~RestWebServer(void) } } -void RestWebServer::Init(void) +void RestWebServer::Init(ControllerOpenThreadRcp *aNcp) { - mResource.Init(); + mResource.Init(aNcp); InitializeListenFd(); } diff --git a/src/rest/rest_web_server.hpp b/src/rest/rest_web_server.hpp index 1da2e0133ab..1fb349321d6 100644 --- a/src/rest/rest_web_server.hpp +++ b/src/rest/rest_web_server.hpp @@ -43,7 +43,7 @@ #include "common/mainloop.hpp" #include "rest/connection.hpp" -using otbr::Ncp::ControllerOpenThread; +using otbr::Ncp::ControllerOpenThreadRcp; using std::chrono::steady_clock; namespace otbr { @@ -59,10 +59,8 @@ class RestWebServer : public MainloopProcessor /** * The constructor to initialize a REST server. * - * @param[in] aNcp A reference to the NCP controller. - * */ - RestWebServer(ControllerOpenThread &aNcp, const std::string &aRestListenAddress, int aRestListenPort); + RestWebServer(const std::string &aRestListenAddress, int aRestListenPort); /** * The destructor destroys the server instance. @@ -73,8 +71,10 @@ class RestWebServer : public MainloopProcessor /** * This method initializes the REST server. * + * @param[in] aCtrlr A pointer to the ControllerOpenThreadRcp. + * */ - void Init(void); + void Init(ControllerOpenThreadRcp *aCtrlr); void Update(MainloopContext &aMainloop) override; void Process(const MainloopContext &aMainloop) override; diff --git a/src/sdp_proxy/advertising_proxy.cpp b/src/sdp_proxy/advertising_proxy.cpp index 16a93c4ddae..edcca571451 100644 --- a/src/sdp_proxy/advertising_proxy.cpp +++ b/src/sdp_proxy/advertising_proxy.cpp @@ -93,12 +93,17 @@ static otError OtbrErrorToOtError(otbrError aError) return error; } -AdvertisingProxy::AdvertisingProxy(Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher) - : mNcp(aNcp) +AdvertisingProxy::AdvertisingProxy(Mdns::Publisher &aPublisher) + : mCtrlr(nullptr) , mPublisher(aPublisher) , mIsEnabled(false) { - mNcp.RegisterResetHandler( +} + +void AdvertisingProxy::Init(Ncp::ControllerOpenThreadRcp *aCtrlr) +{ + mCtrlr = aCtrlr; + mCtrlr->RegisterResetHandler( [this]() { otSrpServerSetServiceUpdateHandler(GetInstance(), AdvertisingHandler, this); }); } diff --git a/src/sdp_proxy/advertising_proxy.hpp b/src/sdp_proxy/advertising_proxy.hpp index 99566930f6d..3adf31b8312 100644 --- a/src/sdp_proxy/advertising_proxy.hpp +++ b/src/sdp_proxy/advertising_proxy.hpp @@ -45,7 +45,7 @@ #include "common/code_utils.hpp" #include "mdns/mdns.hpp" -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread_rcp.hpp" namespace otbr { @@ -59,11 +59,18 @@ class AdvertisingProxy : private NonCopyable /** * This constructor initializes the Advertising Proxy object. * - * @param[in] aNcp A reference to the NCP controller. * @param[in] aPublisher A reference to the mDNS publisher. * */ - explicit AdvertisingProxy(Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher); + explicit AdvertisingProxy(Mdns::Publisher &aPublisher); + + /** + * Initialize the Border Agent. + * + * @param[in] aCtrlr A pointer to the ControllerOpenThreadRcp. + * + */ + void Init(Ncp::ControllerOpenThreadRcp *aCtrlr); /** * This method enables/disables the Advertising Proxy. @@ -126,10 +133,10 @@ class AdvertisingProxy : private NonCopyable */ otbrError PublishHostAndItsServices(const otSrpServerHost *aHost, OutstandingUpdate *aUpdate); - otInstance *GetInstance(void) { return mNcp.GetInstance(); } + otInstance *GetInstance(void) { return mCtrlr.GetInstance(); } // A reference to the NCP controller, has no ownership. - Ncp::ControllerOpenThread &mNcp; + Ncp::ControllerOpenThreadRcp *mCtrlr; // A reference to the mDNS publisher, has no ownership. Mdns::Publisher &mPublisher; diff --git a/src/sdp_proxy/discovery_proxy.cpp b/src/sdp_proxy/discovery_proxy.cpp index ea0072aa2a7..3f84b076edc 100644 --- a/src/sdp_proxy/discovery_proxy.cpp +++ b/src/sdp_proxy/discovery_proxy.cpp @@ -58,13 +58,18 @@ static inline bool DnsLabelsEqual(const std::string &aLabel1, const std::string return StringUtils::EqualCaseInsensitive(aLabel1, aLabel2); } -DiscoveryProxy::DiscoveryProxy(Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher) - : mNcp(aNcp) +DiscoveryProxy::DiscoveryProxy(Mdns::Publisher &aPublisher) + : mCtrlr(nullptr) , mMdnsPublisher(aPublisher) , mIsEnabled(false) { - mNcp.RegisterResetHandler([this]() { - otDnssdQuerySetCallbacks(mNcp.GetInstance(), &DiscoveryProxy::OnDiscoveryProxySubscribe, +} + +void DiscoveryProxy::Init(Ncp::ControllerOpenThreadRcp *aCtrlr) +{ + mCtrlr = aCtrlr; + mCtrlr->RegisterResetHandler([this]() { + otDnssdQuerySetCallbacks(mCtrlr->GetInstance(), &DiscoveryProxy::OnDiscoveryProxySubscribe, &DiscoveryProxy::OnDiscoveryProxyUnsubscribe, this); }); } @@ -89,7 +94,7 @@ void DiscoveryProxy::Start(void) { assert(mSubscriberId == 0); - otDnssdQuerySetCallbacks(mNcp.GetInstance(), &DiscoveryProxy::OnDiscoveryProxySubscribe, + otDnssdQuerySetCallbacks(mCtrlr->GetInstance(), &DiscoveryProxy::OnDiscoveryProxySubscribe, &DiscoveryProxy::OnDiscoveryProxyUnsubscribe, this); mSubscriberId = mMdnsPublisher.AddSubscriptionCallbacks( @@ -109,7 +114,7 @@ void DiscoveryProxy::Start(void) void DiscoveryProxy::Stop(void) { - otDnssdQuerySetCallbacks(mNcp.GetInstance(), nullptr, nullptr, nullptr); + otDnssdQuerySetCallbacks(mCtrlr->GetInstance(), nullptr, nullptr, nullptr); if (mSubscriberId > 0) { @@ -200,7 +205,7 @@ void DiscoveryProxy::OnServiceDiscovered(const std::string instanceInfo.mTxtData = aInstanceInfo.mTxtData.data(); instanceInfo.mTtl = CapTtl(aInstanceInfo.mTtl); - while ((query = otDnssdGetNextQuery(mNcp.GetInstance(), query)) != nullptr) + while ((query = otDnssdGetNextQuery(mCtrlr->GetInstance(), query)) != nullptr) { std::string instanceName; std::string serviceName; @@ -238,7 +243,7 @@ void DiscoveryProxy::OnServiceDiscovered(const std::string instanceInfo.mFullName = instanceFullName.c_str(); instanceInfo.mHostName = translatedHostName.c_str(); - otDnssdQueryHandleDiscoveredServiceInstance(mNcp.GetInstance(), serviceFullName.c_str(), &instanceInfo); + otDnssdQueryHandleDiscoveredServiceInstance(mCtrlr->GetInstance(), serviceFullName.c_str(), &instanceInfo); } } } @@ -270,7 +275,7 @@ void DiscoveryProxy::OnHostDiscovered(const std::string hostInfo.mTtl = CapTtl(aHostInfo.mTtl); - while ((query = otDnssdGetNextQuery(mNcp.GetInstance(), query)) != nullptr) + while ((query = otDnssdGetNextQuery(mCtrlr->GetInstance(), query)) != nullptr) { std::string hostName, domain; char queryName[OT_DNS_MAX_NAME_SIZE]; @@ -295,7 +300,7 @@ void DiscoveryProxy::OnHostDiscovered(const std::string { std::string hostFullName = TranslateDomain(resolvedHostName, domain); - otDnssdQueryHandleDiscoveredHost(mNcp.GetInstance(), hostFullName.c_str(), &hostInfo); + otDnssdQueryHandleDiscoveredHost(mCtrlr->GetInstance(), hostFullName.c_str(), &hostInfo); } } } @@ -321,7 +326,7 @@ int DiscoveryProxy::GetServiceSubscriptionCount(const DnsNameInfo &aNameInfo) co const otDnssdQuery *query = nullptr; int count = 0; - while ((query = otDnssdGetNextQuery(mNcp.GetInstance(), query)) != nullptr) + while ((query = otDnssdGetNextQuery(mCtrlr->GetInstance(), query)) != nullptr) { char queryName[OT_DNS_MAX_NAME_SIZE]; DnsNameInfo queryInfo; diff --git a/src/sdp_proxy/discovery_proxy.hpp b/src/sdp_proxy/discovery_proxy.hpp index c940e892271..223a1931a09 100644 --- a/src/sdp_proxy/discovery_proxy.hpp +++ b/src/sdp_proxy/discovery_proxy.hpp @@ -48,7 +48,7 @@ #include "common/dns_utils.hpp" #include "mdns/mdns.hpp" -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread_rcp.hpp" namespace otbr { namespace Dnssd { @@ -63,11 +63,18 @@ class DiscoveryProxy : private NonCopyable /** * This constructor initializes the Discovery Proxy instance. * - * @param[in] aNcp A reference to the OpenThread Controller instance. * @param[in] aPublisher A reference to the mDNS Publisher. * */ - explicit DiscoveryProxy(Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher); + explicit DiscoveryProxy(Mdns::Publisher &aPublisher); + + /** + * Initialize the Border Agent. + * + * @param[in] aCtrlr A pointer to the ControllerOpenThreadRcp. + * + */ + void Init(Ncp::ControllerOpenThreadRcp *aCtrlr); /** * This method enables/disables the Discovery Proxy. @@ -112,10 +119,10 @@ class DiscoveryProxy : private NonCopyable void Stop(void); bool IsEnabled(void) const { return mIsEnabled; } - Ncp::ControllerOpenThread &mNcp; - Mdns::Publisher &mMdnsPublisher; - bool mIsEnabled; - uint64_t mSubscriberId = 0; + Ncp::ControllerOpenThreadRcp *mCtrlr; + Mdns::Publisher &mMdnsPublisher; + bool mIsEnabled; + uint64_t mSubscriberId = 0; }; } // namespace Dnssd diff --git a/src/trel_dnssd/trel_dnssd.cpp b/src/trel_dnssd/trel_dnssd.cpp index e328ae39e80..45869451525 100644 --- a/src/trel_dnssd/trel_dnssd.cpp +++ b/src/trel_dnssd/trel_dnssd.cpp @@ -81,13 +81,18 @@ namespace otbr { namespace TrelDnssd { -TrelDnssd::TrelDnssd(Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher) +TrelDnssd::TrelDnssd(Mdns::Publisher &aPublisher) : mPublisher(aPublisher) - , mNcp(aNcp) + , mCtrlr(nullptr) { sTrelDnssd = this; } +void TrelDnssd::Init(Ncp::ControllerOpenThreadRcp *aCtrlr) +{ + mCtrlr = aCtrlr; +} + void TrelDnssd::Initialize(std::string aTrelNetif) { mTrelNetif = std::move(aTrelNetif); @@ -229,7 +234,7 @@ void TrelDnssd::OnTrelServiceInstanceResolved(const std::string std::string TrelDnssd::GetTrelInstanceName(void) { - const otExtAddress *extaddr = otLinkGetExtendedAddress(mNcp.GetInstance()); + const otExtAddress *extaddr = otLinkGetExtendedAddress(mCtrlr->GetInstance()); std::string name; char nameBuf[sizeof(otExtAddress) * 2 + 1]; @@ -331,7 +336,7 @@ void TrelDnssd::OnTrelServiceInstanceAdded(const Mdns::Publisher::DiscoveredInst VerifyOrExit(peer.mValid, otbrLogWarning("Peer %s is invalid", aInstanceInfo.mName.c_str())); - otPlatTrelHandleDiscoveredPeerInfo(mNcp.GetInstance(), &peerInfo); + otPlatTrelHandleDiscoveredPeerInfo(mCtrlr->GetInstance(), &peerInfo); mPeers.emplace(instanceName, peer); CheckPeersNumLimit(); @@ -392,7 +397,7 @@ void TrelDnssd::NotifyRemovePeer(const Peer &aPeer) peerInfo.mTxtLength = aPeer.mTxtData.size(); peerInfo.mSockAddr = aPeer.mSockAddr; - otPlatTrelHandleDiscoveredPeerInfo(mNcp.GetInstance(), &peerInfo); + otPlatTrelHandleDiscoveredPeerInfo(mCtrlr->GetInstance(), &peerInfo); } void TrelDnssd::RemoveAllPeers(void) diff --git a/src/trel_dnssd/trel_dnssd.hpp b/src/trel_dnssd/trel_dnssd.hpp index c22e7ba379c..411dfc86d5d 100644 --- a/src/trel_dnssd/trel_dnssd.hpp +++ b/src/trel_dnssd/trel_dnssd.hpp @@ -45,7 +45,7 @@ #include "common/types.hpp" #include "mdns/mdns.hpp" -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread_rcp.hpp" namespace otbr { @@ -70,7 +70,16 @@ class TrelDnssd * @param[in] aPublisher A reference to the mDNS Publisher. * */ - explicit TrelDnssd(Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher); + explicit TrelDnssd(Mdns::Publisher &aPublisher); + + /** + * This method Initializes the Trel Dnssd by setting the Controller OpenThread + * instance. + * + * @param[in] aCtrlr A pointer to the ControllerOpenThreadRcp. + * + */ + void Init(Ncp::ControllerOpenThreadRcp *aCtrlr); /** * This method initializes the TrelDnssd instance. @@ -176,15 +185,15 @@ class TrelDnssd void RemoveAllPeers(void); uint16_t CountDuplicatePeers(const Peer &aPeer); - Mdns::Publisher &mPublisher; - Ncp::ControllerOpenThread &mNcp; - TaskRunner mTaskRunner; - std::string mTrelNetif; - uint32_t mTrelNetifIndex = 0; - uint64_t mSubscriberId = 0; - RegisterInfo mRegisterInfo; - PeerMap mPeers; - bool mMdnsPublisherReady = false; + Mdns::Publisher &mPublisher; + Ncp::ControllerOpenThreadRcp *mCtrlr; + TaskRunner mTaskRunner; + std::string mTrelNetif; + uint32_t mTrelNetifIndex = 0; + uint64_t mSubscriberId = 0; + RegisterInfo mRegisterInfo; + PeerMap mPeers; + bool mMdnsPublisherReady = false; }; /** diff --git a/src/utils/thread_helper.cpp b/src/utils/thread_helper.cpp index a56eaf36ce7..30ef3860487 100644 --- a/src/utils/thread_helper.cpp +++ b/src/utils/thread_helper.cpp @@ -68,7 +68,7 @@ #include "common/code_utils.hpp" #include "common/logging.hpp" #include "common/tlv.hpp" -#include "ncp/ncp_openthread.hpp" +#include "ncp/controller_openthread_rcp.hpp" namespace otbr { namespace agent { @@ -227,9 +227,9 @@ void CopyMdnsResponseCounters(const MdnsResponseCounters &from, threadnetwork::T #endif // OTBR_ENABLE_TELEMETRY_DATA_API } // namespace -ThreadHelper::ThreadHelper(otInstance *aInstance, otbr::Ncp::ControllerOpenThread *aNcp) +ThreadHelper::ThreadHelper(otInstance *aInstance, otbr::Ncp::ControllerOpenThreadRcp *aCtrlr) : mInstance(aInstance) - , mNcp(aNcp) + , mCtrlr(aCtrlr) { #if OTBR_ENABLE_TELEMETRY_DATA_API && (OTBR_ENABLE_NAT64 || OTBR_ENABLE_DHCP6_PD) otError error; @@ -855,7 +855,7 @@ otError ThreadHelper::PermitUnsecureJoin(uint16_t aPort, uint32_t aSeconds) ++mUnsecurePortRefCounter[aPort]; - mNcp->PostTimerTask(delay, [this, aPort]() { + mCtrlr->PostTimerTask(delay, [this, aPort]() { assert(mUnsecurePortRefCounter.find(aPort) != mUnsecurePortRefCounter.end()); assert(mUnsecurePortRefCounter[aPort] > 0); diff --git a/src/utils/thread_helper.hpp b/src/utils/thread_helper.hpp index aa5f09575ca..c4f2b8ea8f2 100644 --- a/src/utils/thread_helper.hpp +++ b/src/utils/thread_helper.hpp @@ -56,7 +56,7 @@ namespace otbr { namespace Ncp { -class ControllerOpenThread; +class ControllerOpenThreadRcp; } } // namespace otbr @@ -81,10 +81,10 @@ class ThreadHelper * The constructor of a Thread helper. * * @param[in] aInstance The Thread instance. - * @param[in] aNcp The ncp controller. + * @param[in] aCtrlr The openthread controller. * */ - ThreadHelper(otInstance *aInstance, otbr::Ncp::ControllerOpenThread *aNcp); + ThreadHelper(otInstance *aInstance, otbr::Ncp::ControllerOpenThreadRcp *aCtrlr); /** * This method adds a callback for device role change. @@ -304,7 +304,7 @@ class ThreadHelper otInstance *mInstance; - otbr::Ncp::ControllerOpenThread *mNcp; + otbr::Ncp::ControllerOpenThreadRcp *mCtrlr; ScanHandler mScanHandler; std::vector mScanResults; diff --git a/tests/scripts/thread_control_api b/tests/scripts/thread_control_api new file mode 100755 index 00000000000..81c9ed302d1 --- /dev/null +++ b/tests/scripts/thread_control_api @@ -0,0 +1,223 @@ +#!/bin/bash +# +# Copyright (c) 2024, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# Test unified thread control apis provided by otbr-agent through dbus. The +# unified thread control apis can work under both NCP and RCP mode. +# +# Usage: +# ./thread_control_api # test the existing thread control apis. +set -euxo pipefail + +# Get our starting directory and remember it +ORIGIN_PWD="$(pwd)" +readonly ORIGIN_PWD + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +readonly SCRIPT_DIR + +#--------------------------------------- +# Configurations +#--------------------------------------- +OT_RCP="ot-rcp" +readonly OT_RCP + +OT_NCP="${OT_NCP:-ot-ncp-ftd}" +readonly OT_NCP + +ABS_TOP_BUILDDIR="$(cd "${top_builddir:-"${SCRIPT_DIR}"/../../}" && pwd)" +readonly ABS_TOP_BUILDDIR + +ABS_TOP_SRCDIR="$(cd "${top_srcdir:-"${SCRIPT_DIR}"/../../}" && pwd)" +readonly ABS_TOP_SRCDIR + +ABS_TOP_OT_SRCDIR=${ABS_TOP_SRCDIR}/third_party/openthread/repo +readonly ABS_TOP_OT_SRCDIR + +ABS_TOP_OT_BUILDDIR=${ABS_TOP_BUILDDIR}/../simulation +readonly ABS_TOP_BUILDDIR + +#---------------------------------------- +# Helper functions +#---------------------------------------- +die() +{ + exit_message="$*" + echo " *** ERROR: $*" + exit 1 +} + +exists_or_die() +{ + [[ -f $1 ]] || die "Missing file: $1" +} + +executable_or_die() +{ + [[ -x $1 ]] || die "Missing executable: $1" +} + +write_syslog() +{ + logger -s -p syslog.alert "OPENTHREAD_TEST: $*" +} + +#---------------------------------------- +# Test constants +#---------------------------------------- +TEST_BASE=/tmp/test-otbr +readonly TEST_BASE + +OTBR_AGENT=otbr-agent +readonly OTBR_AGENT + +STAGE_DIR="${TEST_BASE}/stage" +readonly STAGE_DIR + +BUILD_DIR="${TEST_BASE}/build" +readonly BUILD_DIR + +OTBR_DBUS_CONF="${ABS_TOP_BUILDDIR}/src/agent/otbr-agent.conf" +readonly OTBR_DBUS_CONF + +OTBR_AGENT_PATH="${ABS_TOP_BUILDDIR}/src/agent/${OTBR_AGENT}" +readonly OTBR_AGENT_PATH + +# The node ids +LEADER_NODE_ID=1 +readonly LEADER_NODE_ID + +# The TUN device for OpenThread border router. +TUN_NAME=wpan0 +readonly TUN_NAME + +#---------------------------------------- +# Test steps +#---------------------------------------- +build_ot_simulation() +{ + ${ABS_TOP_OT_SRCDIR}/script/cmake-build simulation -DOT_APP_CLI=OFF -DOT_MTD=OFF + ot_ncp=$(find ${ABS_TOP_OT_BUILDDIR} -name ${OT_NCP}) + ot_rcp=$(find ${ABS_TOP_OT_BUILDDIR} -name ${OT_RCP}) +} + +test_setup() +{ + executable_or_die "${OTBR_AGENT_PATH}" + + # Remove flashes + sudo rm -vrf "${TEST_BASE}/tmp" + # OPENTHREAD_POSIX_DAEMON_SOCKET_LOCK + sudo rm -vf "/tmp/openthread.lock" + + build_ot_simulation + + # We will be creating a lot of log information + # Rotate logs so we have a clean and empty set of logs uncluttered with other stuff + if [[ -f /etc/logrotate.conf ]]; then + sudo logrotate -f /etc/logrotate.conf || true + fi + + # From now on - all exits are TRAPPED + # When they occur, we call the function: output_logs'. + trap test_teardown EXIT +} + +test_teardown() +{ + exit_message="Test teardown" + + # Capture the exit code so we can return it below + EXIT_CODE=$? + readonly EXIT_CODE + write_syslog "EXIT ${EXIT_CODE} - output logs" + + sudo pkill -f "${OTBR_AGENT}" || true + wait + + echo 'clearing all' + sudo rm /etc/dbus-1/system.d/otbr-agent.conf || true + sudo rm -rf "${STAGE_DIR}" || true + sudo rm -rf "${BUILD_DIR}" || true + sudo rm -rf "${ABS_TOP_OT_BUILDDIR}" || true + + echo "EXIT ${EXIT_CODE}: MESSAGE: ${exit_message}" + exit ${EXIT_CODE} +} + +otbr-agent_start() +{ + exists_or_die "${OTBR_DBUS_CONF}" + sudo cp "${OTBR_DBUS_CONF}" /etc/dbus-1/system.d + + write_syslog "AGENT: kill old" + sudo killall "${OTBR_AGENT}" || true + sleep 5 + write_syslog "AGENT: starting" + + # we launch this in the background + ( + set -e + set -x + + cd "${ORIGIN_PWD}" + + # check version + sudo "${OTBR_AGENT_PATH}" -V + # check invalid arguments + sudo "${OTBR_AGENT_PATH}" -x && exit $? + + [[ ! -d tmp ]] || sudo rm -rf tmp + sudo "${OTBR_AGENT_PATH}" -I "${TUN_NAME}" -v -d 6 "spinel+hdlc+forkpty://${ot_ncp}?forkpty-arg=${LEADER_NODE_ID}" & + ) + + # wait for it to complete + sleep 10 + + pidof ${OTBR_AGENT} || die "AGENT: failed to start" + write_syslog "AGENT: start complete" +} + +test_thread_control_apis() +{ + sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 org.freedesktop.DBus.Properties.Get string:io.openthread.BorderRouter string:DeviceRole | grep -E "disabled" +} + +test_ncp_mode() +{ + test_setup + otbr-agent_start + test_thread_control_apis +} + +main() +{ + # TODO: Only test NCP mode for now to verify newly implemented APIs + test_ncp_mode +} + +main "$@"