blob: 9f510b37e5017ca54dee92cb183c4deac7af3c63 [file] [edit]
/*
* 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