| /* |
| * Copyright (c) 2021, The OpenThread Authors. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the copyright holder nor the |
| * names of its contributors may be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /** |
| * @file |
| * The file implements the OTBR Agent. |
| */ |
| |
| #define OTBR_LOG_TAG "APP" |
| |
| #include <errno.h> |
| #include <limits.h> |
| #include <signal.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| |
| #ifdef HAVE_LIBSYSTEMD |
| #include <systemd/sd-daemon.h> |
| #endif |
| |
| #include "agent/application.hpp" |
| |
| #include "common/code_utils.hpp" |
| #include "common/mainloop_manager.hpp" |
| #include "host/posix/dnssd.hpp" |
| #include "utils/infra_link_selector.hpp" |
| |
| #if OTBR_ENABLE_NFTABLES |
| #include <algorithm> |
| #include <string.h> |
| #include <vector> |
| |
| #include <openthread/netdata.h> |
| #include <openthread/thread.h> |
| #endif |
| |
| namespace otbr { |
| |
| #ifndef OTBR_MAINLOOP_POLL_TIMEOUT_SEC |
| #define OTBR_MAINLOOP_POLL_TIMEOUT_SEC 10 |
| #endif |
| |
| std::atomic_bool Application::sShouldTerminate(false); |
| std::atomic_bool Application::sIsPseudoReset(false); |
| const struct timeval Application::kPollTimeout = {OTBR_MAINLOOP_POLL_TIMEOUT_SEC, 0}; |
| |
| Application::Application(Host::ThreadHost &aHost, |
| const std::string &aInterfaceName, |
| const std::string &aBackboneInterfaceName) |
| : mInterfaceName(aInterfaceName) |
| , mBackboneInterfaceName(aBackboneInterfaceName) |
| , mHost(aHost) |
| #if OTBR_ENABLE_MDNS |
| , mPublisher( |
| Mdns::Publisher::Create([this](Mdns::Publisher::State aState) { mMdnsStateSubject.UpdateState(aState); })) |
| #endif |
| #if OTBR_ENABLE_DNSSD_PLAT |
| , mDnssdPlatform(*mPublisher) |
| #endif |
| #if OTBR_ENABLE_BORDER_AGENT |
| #if OTBR_ENABLE_BORDER_AGENT_MESHCOP_SERVICE |
| , mBorderAgent(*mPublisher) |
| #endif |
| , mBorderAgentUdpProxy(mHost) |
| #if OTBR_ENABLE_EPSKC |
| , mEphemeralKeyUdpProxy(mHost) |
| #endif |
| #endif |
| #if OTBR_ENABLE_DBUS_SERVER |
| , mDBusAgent(MakeDBusDependentComponents()) |
| #endif |
| { |
| sShouldTerminate = false; |
| sIsPseudoReset = false; |
| |
| if (mHost.GetCoprocessorType() == OT_COPROCESSOR_RCP) |
| { |
| CreateRcpMode(); |
| } |
| else if (mHost.GetCoprocessorType() == OT_COPROCESSOR_NCP) |
| { |
| CreateNcpMode(); |
| } |
| else |
| { |
| DieNow("Unknown Co-processor type!"); |
| } |
| } |
| |
| void Application::Init(const std::string &aRestListenAddress, int aRestListenPort) |
| { |
| CoprocessorType type; |
| |
| mHost.Init(); |
| |
| type = mHost.GetCoprocessorType(); |
| |
| switch (type) |
| { |
| case OT_COPROCESSOR_RCP: |
| InitRcpMode(aRestListenAddress, aRestListenPort); |
| break; |
| case OT_COPROCESSOR_NCP: |
| InitNcpMode(); |
| break; |
| default: |
| DieNow("Unknown coprocessor type!"); |
| break; |
| } |
| |
| #if OTBR_ENABLE_DBUS_SERVER |
| mDBusAgent.Init(); |
| #endif |
| |
| otbrLogInfo("%s Co-processor version: %s", type == OT_COPROCESSOR_RCP ? "Radio" : "Network", |
| mHost.GetCoprocessorVersion()); |
| } |
| |
| void Application::Deinit(void) |
| { |
| switch (mHost.GetCoprocessorType()) |
| { |
| case OT_COPROCESSOR_RCP: |
| DeinitRcpMode(); |
| break; |
| case OT_COPROCESSOR_NCP: |
| DeinitNcpMode(); |
| break; |
| default: |
| DieNow("Unknown coprocessor type!"); |
| break; |
| } |
| |
| mHost.Deinit(); |
| |
| #if OTBR_ENABLE_DBUS_SERVER |
| mDBusAgent.Deinit(); |
| #endif |
| } |
| |
| otbrError Application::Run(void) |
| { |
| struct sigaction sa{}; |
| otbrError error = OTBR_ERROR_NONE; |
| |
| sigemptyset(&sa.sa_mask); |
| sa.sa_flags = SA_RESETHAND; |
| |
| // allow quitting elegantly |
| sa.sa_handler = HandleSignal; |
| if (sigaction(SIGTERM, &sa, nullptr) < 0) |
| { |
| otbrLogWarning("Failed to install SIGTERM handler: %s", strerror(errno)); |
| } |
| |
| // avoid exiting on SIGPIPE |
| sa.sa_handler = SIG_IGN; |
| sa.sa_flags = 0; |
| if (sigaction(SIGPIPE, &sa, nullptr) < 0) |
| { |
| otbrLogWarning("Failed to ignore SIGPIPE: %s", strerror(errno)); |
| } |
| |
| #ifdef HAVE_LIBSYSTEMD |
| if (getenv("SYSTEMD_EXEC_PID") != nullptr) |
| { |
| otbrLogInfo("Notify systemd the service is ready."); |
| |
| // Ignored return value as systemd recommends. |
| // See https://www.freedesktop.org/software/systemd/man/sd_notify.html |
| sd_notify(0, "READY=1"); |
| } |
| #endif |
| |
| #if OTBR_ENABLE_NOTIFY_UPSTART |
| if (getenv("UPSTART_JOB") != nullptr) |
| { |
| otbrLogInfo("Notify Upstart the service is ready."); |
| if (raise(SIGSTOP)) |
| { |
| otbrLogWarning("Failed to notify Upstart."); |
| } |
| } |
| #endif |
| |
| // Generic readiness notification for fd-based supervisors (s6, dinit, |
| // ...): write a newline to the file descriptor passed in OTBR_NOTIFY_FD. |
| // See https://skarnet.org/software/s6/notifywhenup.html |
| { |
| const char *notifyFdEnv = getenv("OTBR_NOTIFY_FD"); |
| |
| if (notifyFdEnv != nullptr) |
| { |
| char *end = nullptr; |
| long notifyFdLong; |
| |
| errno = 0; |
| notifyFdLong = strtol(notifyFdEnv, &end, 10); |
| |
| // Reject the standard I/O stream descriptors (0-2) |
| if (end != notifyFdEnv && *end == '\0' && errno == 0 && notifyFdLong >= 3 && notifyFdLong <= INT_MAX) |
| { |
| int notifyFd = static_cast<int>(notifyFdLong); |
| ssize_t rval; |
| |
| otbrLogInfo("Notify readiness on file descriptor %d.", notifyFd); |
| |
| do |
| { |
| rval = write(notifyFd, "\n", 1); |
| } while (rval == -1 && errno == EINTR); |
| |
| if (rval == -1) |
| { |
| otbrLogWarning("Failed to notify readiness on file descriptor %d: %s", notifyFd, strerror(errno)); |
| } |
| |
| close(notifyFd); |
| } |
| else |
| { |
| otbrLogWarning("Ignoring invalid OTBR_NOTIFY_FD value: %s", notifyFdEnv); |
| } |
| |
| // Run() may execute again within the same process lifecycle |
| // (pseudo reset) or after an in-place re-exec (otPlatReset), |
| // when the descriptor number may have been reused for an |
| // unrelated resource. Only notify once. |
| unsetenv("OTBR_NOTIFY_FD"); |
| } |
| } |
| |
| while (!sShouldTerminate) |
| { |
| otbr::MainloopContext mainloop; |
| int rval; |
| |
| mainloop.mMaxFd = -1; |
| mainloop.mTimeout = kPollTimeout; |
| |
| FD_ZERO(&mainloop.mReadFdSet); |
| FD_ZERO(&mainloop.mWriteFdSet); |
| FD_ZERO(&mainloop.mErrorFdSet); |
| |
| MainloopManager::GetInstance().Update(mainloop); |
| |
| rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet, |
| &mainloop.mTimeout); |
| |
| if (rval >= 0) |
| { |
| MainloopManager::GetInstance().Process(mainloop); |
| |
| if (mErrorCondition) |
| { |
| error = mErrorCondition(); |
| if (error != OTBR_ERROR_NONE) |
| { |
| break; |
| } |
| } |
| } |
| else if (errno != EINTR) |
| { |
| error = OTBR_ERROR_ERRNO; |
| otbrLogErr("select() failed: %s", strerror(errno)); |
| break; |
| } |
| } |
| |
| return error; |
| } |
| |
| void Application::HandleSignal(int aSignal) |
| { |
| OTBR_UNUSED_VARIABLE(aSignal); |
| |
| sShouldTerminate = true; |
| } |
| |
| void Application::CreateRcpMode(void) |
| { |
| otbr::Host::RcpHost &rcpHost = static_cast<otbr::Host::RcpHost &>(mHost); |
| #if OTBR_ENABLE_NFTABLES |
| mNftables = MakeUnique<Firewall::Nftables>(); |
| mFirewall = MakeUnique<Firewall::FirewallManager>(*mNftables, mInterfaceName); |
| #endif |
| #if OTBR_ENABLE_BACKBONE_ROUTER |
| mBackboneAgent = MakeUnique<BackboneRouter::BackboneAgent>(rcpHost); |
| #endif |
| #if OTBR_ENABLE_SRP_ADVERTISING_PROXY |
| mAdvertisingProxy = MakeUnique<AdvertisingProxy>(rcpHost, *mPublisher); |
| #endif |
| #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY |
| mDiscoveryProxy = MakeUnique<Dnssd::DiscoveryProxy>(rcpHost, *mPublisher); |
| #endif |
| #if OTBR_ENABLE_TREL_DNSSD |
| mTrelDnssd = MakeUnique<TrelDnssd::TrelDnssd>(rcpHost, *mPublisher); |
| #endif |
| #if OTBR_ENABLE_OPENWRT |
| mUbusAgent = MakeUnique<ubus::UBusAgent>(rcpHost); |
| #endif |
| #if OTBR_ENABLE_REST_SERVER |
| mRestWebServer = std::make_shared<rest::RestWebServer>(rcpHost); |
| #endif |
| #if OTBR_ENABLE_VENDOR_SERVER |
| mVendorServer = vendor::VendorServer::newInstance(*this); |
| #endif |
| |
| OTBR_UNUSED_VARIABLE(rcpHost); |
| } |
| |
| void Application::InitRcpMode(const std::string &aRestListenAddress, int aRestListenPort) |
| { |
| Host::RcpHost &rcpHost = static_cast<otbr::Host::RcpHost &>(mHost); |
| OTBR_UNUSED_VARIABLE(rcpHost); |
| OTBR_UNUSED_VARIABLE(aRestListenAddress); |
| OTBR_UNUSED_VARIABLE(aRestListenPort); |
| |
| #if OTBR_ENABLE_BORDER_AGENT && OTBR_ENABLE_BORDER_AGENT_MESHCOP_SERVICE |
| mMdnsStateSubject.AddObserver(mBorderAgent); |
| #endif |
| #if OTBR_ENABLE_SRP_ADVERTISING_PROXY |
| mMdnsStateSubject.AddObserver(*mAdvertisingProxy); |
| #endif |
| #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY |
| mMdnsStateSubject.AddObserver(*mDiscoveryProxy); |
| #endif |
| #if OTBR_ENABLE_TREL_DNSSD |
| mMdnsStateSubject.AddObserver(*mTrelDnssd); |
| #endif |
| #if OTBR_ENABLE_DNSSD_PLAT |
| mMdnsStateSubject.AddObserver(mDnssdPlatform); |
| mDnssdPlatform.SetDnssdStateChangedCallback(([&rcpHost](otPlatDnssdState aState) { |
| OTBR_UNUSED_VARIABLE(aState); |
| otPlatDnssdStateHandleStateChange(rcpHost.GetInstance()); |
| })); |
| #endif |
| |
| #if OTBR_ENABLE_MDNS |
| mPublisher->Start(); |
| #endif |
| #if OTBR_ENABLE_BORDER_AGENT |
| rcpHost.AddThreadRoleChangedCallback([this, &rcpHost](otDeviceRole aRole) { |
| OT_UNUSED_VARIABLE(aRole); |
| // This ensures the Border Agent is started only when the Thread device |
| // successfully attaches to a network. This aligns with the OpenThread |
| // core behavior and is particularly useful when the agent is initially |
| // disabled (e.g., via OTBR_STOP_BORDER_AGENT_ON_INIT). |
| if (rcpHost.IsAttached()) |
| { |
| mBorderAgent.SetEnabled(true); |
| } |
| }); |
| #if OTBR_ENABLE_BORDER_AGENT_MESHCOP_SERVICE |
| mHost.SetBorderAgentMeshCoPServiceChangedCallback( |
| [this](bool aIsActive, uint16_t aPort, const uint8_t *aTxtData, uint16_t aLength) { |
| mBorderAgent.HandleBorderAgentMeshCoPServiceChanged(aIsActive, aPort, |
| std::vector<uint8_t>(aTxtData, aTxtData + aLength)); |
| }); |
| mHost.AddEphemeralKeyStateChangedCallback([this](otBorderAgentEphemeralKeyState aEpskcState, uint16_t aPort) { |
| mBorderAgent.HandleEpskcStateChanged(aEpskcState, aPort); |
| }); |
| SetBorderAgentOnInitState(); |
| #else |
| mBorderAgent.SetVendorTxtDataChangedCallback([this](const BorderAgent::TxtData &aVendorTxtData) { |
| otError error = mHost.SetBorderAgentMeshCoPServiceBaseName(mBorderAgent.GetBaseServiceInstanceName()); |
| if (error != OT_ERROR_NONE) |
| { |
| otbrLogWarning("Failed to set Border Agent MeshCoP service base name: %s", otThreadErrorToString(error)); |
| } |
| |
| mHost.SetBorderAgentVendorTxtData(aVendorTxtData); |
| }); |
| #endif |
| #endif // OTBR_ENABLE_BORDER_AGENT |
| #if OTBR_ENABLE_NFTABLES |
| // The firewall is a security control: if it was built in (OTBR_NFTABLES) but |
| // cannot be installed, abort rather than silently forward traffic unfiltered. |
| // This mirrors the legacy script path, which `die`d when the otbr-firewall / |
| // otbr-nat44 services failed to start. |
| // Each result is taken once: SuccessOrDie() names its argument twice, so a |
| // call passed to it directly runs a second time on the failing path and the |
| // fatal log reports what that second attempt returned. |
| otbrError firewallError; |
| |
| firewallError = mNftables->Init(); |
| SuccessOrDie(firewallError, "Failed to initialize the nftables firewall!"); |
| firewallError = mFirewall->Init(); |
| SuccessOrDie(firewallError, "Failed to initialize the firewall manager!"); |
| firewallError = mFirewall->EnableIngressFilter(); |
| SuccessOrDie(firewallError, "Failed to install the Thread ingress filter!"); |
| if (!mBackboneInterfaceName.empty()) |
| { |
| firewallError = mFirewall->EnableNat44Masquerade(mBackboneInterfaceName); |
| SuccessOrDie(firewallError, "Failed to install NAT44 masquerade!"); |
| } |
| // Populate the ingress allow/deny sets from Thread network data, and keep |
| // them in sync as it changes. This is the in-process replacement for the |
| // OpenThread posix platform firewall's ipset producer. |
| rcpHost.AddThreadStateChangedCallback([this](otChangedFlags aFlags) { |
| // Network data carries the on-mesh prefixes; the active dataset carries |
| // the mesh-local prefix, which the deny set also covers. |
| if (aFlags & (OT_CHANGED_THREAD_NETDATA | OT_CHANGED_ACTIVE_DATASET)) |
| { |
| UpdateIngressPrefixes(); |
| } |
| }); |
| UpdateIngressPrefixes(); |
| #endif |
| #if OTBR_ENABLE_BACKBONE_ROUTER |
| mBackboneAgent->Init(); |
| #endif |
| #if OTBR_ENABLE_SRP_ADVERTISING_PROXY |
| mAdvertisingProxy->SetEnabled(true); |
| #endif |
| #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY |
| mDiscoveryProxy->SetEnabled(true); |
| #endif |
| #if OTBR_ENABLE_OPENWRT |
| mUbusAgent->Init(); |
| #endif |
| #if OTBR_ENABLE_REST_SERVER |
| mRestWebServer->Init(aRestListenAddress, aRestListenPort); |
| #endif |
| #if OTBR_ENABLE_VENDOR_SERVER |
| mVendorServer->Init(); |
| #endif |
| #if OTBR_ENABLE_DNSSD_PLAT |
| mDnssdPlatform.Start(); |
| #endif |
| } |
| |
| #if OTBR_ENABLE_NFTABLES |
| void Application::UpdateIngressPrefixes(void) |
| { |
| otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; |
| otBorderRouterConfig config; |
| const otMeshLocalPrefix *meshLocal; |
| std::vector<Ip6Prefix> denySrc; |
| std::vector<Ip6Prefix> allowDst; |
| otInstance *instance; |
| |
| // Several border routers can advertise the same on-mesh prefix, and duplicate |
| // intervals in a single transaction make the kernel reject the whole batch, |
| // so only distinct prefixes go in. (Declared before the first VerifyOrExit so |
| // no goto crosses its initialisation.) |
| auto addUnique = [](std::vector<Ip6Prefix> &aVec, const Ip6Prefix &aPrefix) { |
| if (std::find(aVec.begin(), aVec.end(), aPrefix) == aVec.end()) |
| { |
| aVec.push_back(aPrefix); |
| } |
| }; |
| |
| // The firewall only exists in RCP mode, so check it before downcasting mHost. |
| VerifyOrExit(mFirewall != nullptr && mFirewall->IsIngressFilterEnabled()); |
| |
| instance = static_cast<otbr::Host::RcpHost &>(mHost).GetInstance(); |
| VerifyOrExit(instance != nullptr); |
| |
| // Deny-src and allow-dst both cover every on-mesh prefix. |
| while (otNetDataGetNextOnMeshPrefix(instance, &iterator, &config) == OT_ERROR_NONE) |
| { |
| Ip6Prefix prefix; |
| prefix.Set(config.mPrefix); |
| addUnique(denySrc, prefix); |
| addUnique(allowDst, prefix); |
| } |
| |
| // Deny-src additionally covers the mesh-local /64. |
| meshLocal = otThreadGetMeshLocalPrefix(instance); |
| if (meshLocal != nullptr) |
| { |
| Ip6Prefix mlPrefix{}; |
| memcpy(mlPrefix.mPrefix.m8, meshLocal->m8, sizeof(meshLocal->m8)); |
| mlPrefix.mLength = 64; |
| addUnique(denySrc, mlPrefix); |
| } |
| |
| if (mFirewall->ReplaceIngressPrefixes(denySrc, allowDst) != OTBR_ERROR_NONE) |
| { |
| otbrLogWarning("FirewallManager: failed to update ingress prefixes"); |
| } |
| |
| exit: |
| return; |
| } |
| #endif |
| |
| void Application::DeinitRcpMode(void) |
| { |
| #if OTBR_ENABLE_NFTABLES |
| // Tear down the OTBR nftables table while the netlink socket is still open |
| // (mNftables outlives mFirewall by member declaration order). |
| if (mFirewall != nullptr) |
| { |
| otbrError firewallError = mFirewall->Deinit(); |
| if (firewallError != OTBR_ERROR_NONE) |
| { |
| otbrLogWarning("FirewallManager: teardown failed (%d)", firewallError); |
| } |
| } |
| // Close the netlink socket too, or a later InitRcpMode() dies in |
| // mNftables->Init() on the still-open socket. |
| if (mNftables != nullptr) |
| { |
| mNftables->Deinit(); |
| } |
| #endif |
| #if OTBR_ENABLE_DNSSD_PLAT |
| mDnssdPlatform.Stop(); |
| #endif |
| #if OTBR_ENABLE_SRP_ADVERTISING_PROXY |
| mAdvertisingProxy->SetEnabled(false); |
| #endif |
| #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY |
| mDiscoveryProxy->SetEnabled(false); |
| #endif |
| #if OTBR_ENABLE_BORDER_AGENT |
| mBorderAgent.SetEnabled(false); |
| mBorderAgent.Deinit(); |
| #endif |
| #if OTBR_ENABLE_MDNS |
| mMdnsStateSubject.Clear(); |
| mPublisher->Stop(); |
| #endif |
| } |
| |
| void Application::CreateNcpMode(void) |
| { |
| otbr::Host::NcpHost &ncpHost = static_cast<otbr::Host::NcpHost &>(mHost); |
| |
| mNetif = MakeUnique<Netif>(mInterfaceName, ncpHost); |
| mInfraIf = MakeUnique<InfraIf>(ncpHost); |
| #if OTBR_ENABLE_BACKBONE_ROUTER |
| mMulticastRoutingManager = MakeUnique<MulticastRoutingManager>(*mNetif, *mInfraIf, ncpHost); |
| #endif |
| } |
| |
| void Application::InitNcpMode(void) |
| { |
| otbr::Host::NcpHost &ncpHost = static_cast<otbr::Host::NcpHost &>(mHost); |
| |
| SuccessOrDie(mNetif->Init(), "Failed to initialize the Netif!"); |
| ncpHost.InitNetifCallbacks(*mNetif); |
| |
| mInfraIf->Init(); |
| if (!mBackboneInterfaceName.empty()) |
| { |
| mInfraIf->SetInfraIf(mBackboneInterfaceName); |
| } |
| ncpHost.InitInfraIfCallbacks(*mInfraIf); |
| |
| #if OTBR_ENABLE_SRP_ADVERTISING_PROXY |
| mMdnsStateSubject.AddObserver(ncpHost); |
| #endif |
| #if OTBR_ENABLE_BORDER_AGENT && OTBR_ENABLE_BORDER_AGENT_MESHCOP_SERVICE |
| mMdnsStateSubject.AddObserver(mBorderAgent); |
| #endif |
| #if OTBR_ENABLE_DNSSD_PLAT |
| mMdnsStateSubject.AddObserver(mDnssdPlatform); |
| #endif |
| #if OTBR_ENABLE_MDNS |
| ncpHost.SetMdnsPublisher(mPublisher.get()); |
| mPublisher->Start(); |
| #endif |
| |
| #if OTBR_ENABLE_BORDER_AGENT |
| mHost.SetBorderAgentMeshCoPServiceChangedCallback( |
| [this](bool aIsActive, uint16_t aPort, const uint8_t *aTxtData, uint16_t aLength) { |
| if (!aIsActive) |
| { |
| mBorderAgentUdpProxy.Stop(); |
| } |
| else |
| { |
| mBorderAgentUdpProxy.Start(aPort); |
| } |
| #if OTBR_ENABLE_BORDER_AGENT_MESHCOP_SERVICE |
| mBorderAgent.HandleBorderAgentMeshCoPServiceChanged(aIsActive, mBorderAgentUdpProxy.GetHostPort(), |
| std::vector<uint8_t>(aTxtData, aTxtData + aLength)); |
| #else |
| OTBR_UNUSED_VARIABLE(aTxtData); |
| OTBR_UNUSED_VARIABLE(aLength); |
| #endif |
| }); |
| mHost.SetUdpForwardToHostCallback([this](const uint8_t *aUdpPayload, uint16_t aLength, |
| const otIp6Address &aPeerAddr, uint16_t aPeerPort, uint16_t aLocalPort) { |
| if (aLocalPort == mBorderAgentUdpProxy.GetThreadPort()) |
| { |
| mBorderAgentUdpProxy.SendToPeer(aUdpPayload, aLength, aPeerAddr, aPeerPort); |
| } |
| #if OTBR_ENABLE_EPSKC |
| else if (aLocalPort == mEphemeralKeyUdpProxy.GetThreadPort()) |
| { |
| mEphemeralKeyUdpProxy.SendToPeer(aUdpPayload, aLength, aPeerAddr, aPeerPort); |
| } |
| #endif // OTBR_ENABLE_EPSKC |
| }); |
| #if OTBR_ENABLE_EPSKC |
| mHost.AddEphemeralKeyStateChangedCallback([this](otBorderAgentEphemeralKeyState aState, uint16_t aPort) { |
| if (aState == OT_BORDER_AGENT_STATE_STARTED) |
| { |
| otbrLogInfo("Border Agent Ephemeral Key State Changed: Active on port %d", aPort); |
| mEphemeralKeyUdpProxy.Start(aPort); |
| } |
| else if (aState == OT_BORDER_AGENT_STATE_STOPPED || aState == OT_BORDER_AGENT_STATE_DISABLED) |
| { |
| otbrLogInfo("Border Agent Ephemeral Key State Changed: Inactive"); |
| mEphemeralKeyUdpProxy.Stop(); |
| } |
| #if OTBR_ENABLE_BORDER_AGENT_MESHCOP_SERVICE |
| mBorderAgent.HandleEpskcStateChanged(aState, mEphemeralKeyUdpProxy.GetHostPort()); |
| #endif // OTBR_ENABLE_BORDER_AGENT_MESHCOP_SERVICE |
| }); |
| #endif // OTBR_ENABLE_EPSKC |
| SetBorderAgentOnInitState(); |
| #endif |
| #if OTBR_ENABLE_BACKBONE_ROUTER |
| mHost.SetBackboneRouterStateChangedCallback( |
| [this](otBackboneRouterState aState) { mMulticastRoutingManager->HandleStateChange(aState); }); |
| mHost.SetBackboneRouterMulticastListenerCallback( |
| [this](otBackboneRouterMulticastListenerEvent aEvent, const Ip6Address &aAddress) { |
| mMulticastRoutingManager->HandleBackboneMulticastListenerEvent(aEvent, aAddress); |
| }); |
| #if OTBR_ENABLE_BACKBONE_ROUTER_ON_INIT |
| mHost.SetBackboneRouterEnabled(true); |
| #endif |
| #endif |
| |
| #if OTBR_ENABLE_DNSSD_PLAT |
| mDnssdPlatform.Start(); |
| #endif |
| } |
| |
| void Application::DeinitNcpMode(void) |
| { |
| #if OTBR_ENABLE_BORDER_AGENT |
| mBorderAgent.SetEnabled(false); |
| mBorderAgent.Deinit(); |
| mBorderAgentUdpProxy.Stop(); |
| #endif |
| #if OTBR_ENABLE_SRP_ADVERTISING_PROXY |
| mPublisher->Stop(); |
| #endif |
| mNetif->Deinit(); |
| mInfraIf->Deinit(); |
| } |
| |
| #if OTBR_ENABLE_BORDER_AGENT |
| void Application::SetBorderAgentOnInitState(void) |
| { |
| // This is for delaying publishing the MeshCoP service until the correct |
| // vendor name and OUI etc. are correctly set by BorderAgent::SetMeshCopServiceValues() |
| #if OTBR_STOP_BORDER_AGENT_ON_INIT |
| mBorderAgent.SetEnabled(false); |
| #else |
| mBorderAgent.SetEnabled(true); |
| #endif |
| } |
| #endif |
| |
| #if OTBR_ENABLE_DBUS_SERVER |
| DBus::DependentComponents Application::MakeDBusDependentComponents(void) |
| { |
| return DBus::DependentComponents{mHost, *mPublisher, |
| #if OTBR_ENABLE_BORDER_AGENT |
| mBorderAgent |
| #endif |
| }; |
| } |
| #endif |
| |
| } // namespace otbr |