2 * Copyright (c) 2017, The OpenThread Authors.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
31 * The file implements the Thread border agent.
34 #include "agent/border_agent.hpp"
36 #include <arpa/inet.h>
39 #include <netinet/in.h>
45 #include <openthread/platform/toolchain.h>
47 #include "agent/border_agent.hpp"
48 #include "agent/ncp.hpp"
49 #include "agent/ncp_openthread.hpp"
50 #include "agent/uris.hpp"
51 #include "common/code_utils.hpp"
52 #include "common/logging.hpp"
53 #include "common/tlv.hpp"
54 #include "common/types.hpp"
55 #include "utils/hex.hpp"
56 #include "utils/strcpy_utils.hpp"
60 static const uint16_t kThreadVersion11 = 2; ///< Thread Version 1.1
61 static const uint16_t kThreadVersion12 = 3; ///< Thread Version 1.2
63 static const char kBorderAgentServiceType[] = "_meshcop._udp."; ///< Border agent service type of mDNS
71 kAloc16Leader = 0xfc00, ///< leader anycast locator.
72 kInvalidLocator = 0xffff, ///< invalid locator.
81 kBorderAgentUdpPort = 49191, ///< Thread commissioning port.
84 BorderAgent::BorderAgent(Ncp::Controller *aNcp)
86 #if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
87 , mPublisher(Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, HandleMdnsState, this))
88 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
89 , mAdvertisingProxy(*reinterpret_cast<Ncp::ControllerOpenThread *>(aNcp), *mPublisher)
94 #if OTBR_ENABLE_BACKBONE_ROUTER
95 , mBackboneAgent(*reinterpret_cast<Ncp::ControllerOpenThread *>(aNcp))
97 , mThreadStarted(false)
101 void BorderAgent::Init(void)
103 memset(mNetworkName, 0, sizeof(mNetworkName));
104 memset(mExtPanId, 0, sizeof(mExtPanId));
105 memset(mExtAddr, 0, sizeof(mExtAddr));
106 mExtPanIdInitialized = false;
107 mExtAddrInitialized = false;
110 #if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
111 mNcp->On(Ncp::kEventExtPanId, HandleExtPanId, this);
112 mNcp->On(Ncp::kEventNetworkName, HandleNetworkName, this);
113 mNcp->On(Ncp::kEventThreadVersion, HandleThreadVersion, this);
114 mNcp->On(Ncp::kEventExtAddr, HandleExtAddr, this);
116 mNcp->On(Ncp::kEventThreadState, HandleThreadState, this);
117 mNcp->On(Ncp::kEventPSKc, HandlePSKc, this);
119 #if OTBR_ENABLE_BACKBONE_ROUTER
120 mBackboneAgent.Init();
123 otbrLogResult(mNcp->RequestEvent(Ncp::kEventThreadState), "Check if Thread is up");
124 otbrLogResult(mNcp->RequestEvent(Ncp::kEventPSKc), "Check if PSKc is initialized");
127 otbrError BorderAgent::Start(void)
129 otbrError error = OTBR_ERROR_NONE;
131 VerifyOrExit(mThreadStarted && mPSKcInitialized, errno = EAGAIN, error = OTBR_ERROR_ERRNO);
133 // In case we didn't receive Thread down event.
136 #if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
137 SuccessOrExit(error = mNcp->RequestEvent(Ncp::kEventNetworkName));
138 SuccessOrExit(error = mNcp->RequestEvent(Ncp::kEventExtPanId));
139 SuccessOrExit(error = mNcp->RequestEvent(Ncp::kEventThreadVersion));
140 SuccessOrExit(error = mNcp->RequestEvent(Ncp::kEventExtAddr));
142 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
143 mAdvertisingProxy.Start();
146 StartPublishService();
147 #endif // OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
149 // Suppress unused warning of label exit
153 otbrLogResult(error, "Start Thread Border Agent");
157 void BorderAgent::Stop(void)
159 #if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
160 StopPublishService();
161 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
162 mAdvertisingProxy.Stop();
167 BorderAgent::~BorderAgent(void)
171 if (mPublisher != nullptr)
174 mPublisher = nullptr;
178 void BorderAgent::HandleMdnsState(Mdns::Publisher::State aState)
182 case Mdns::Publisher::State::kReady:
186 otbrLog(OTBR_LOG_WARNING, "MDNS service not available!");
191 void BorderAgent::UpdateFdSet(fd_set & aReadFdSet,
192 fd_set & aWriteFdSet,
193 fd_set & aErrorFdSet,
197 #if OTBR_ENABLE_BACKBONE_ROUTER
198 mBackboneAgent.UpdateFdSet(aReadFdSet, aWriteFdSet, aErrorFdSet, aMaxFd, aTimeout);
201 if (mPublisher != nullptr)
203 mPublisher->UpdateFdSet(aReadFdSet, aWriteFdSet, aErrorFdSet, aMaxFd, aTimeout);
207 void BorderAgent::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet, const fd_set &aErrorFdSet)
209 #if OTBR_ENABLE_BACKBONE_ROUTER
210 mBackboneAgent.Process(aReadFdSet, aWriteFdSet, aErrorFdSet);
212 if (mPublisher != nullptr)
214 mPublisher->Process(aReadFdSet, aWriteFdSet, aErrorFdSet);
218 static const char *ThreadVersionToString(uint16_t aThreadVersion)
220 switch (aThreadVersion)
222 case kThreadVersion11:
224 case kThreadVersion12:
227 otbrLog(OTBR_LOG_ERR, "unexpected thread version %hu", aThreadVersion);
232 void BorderAgent::PublishService(void)
234 assert(mNetworkName[0] != '\0');
235 assert(mExtPanIdInitialized);
236 assert(mExtAddrInitialized);
237 assert(mThreadVersion != 0);
239 const char * versionString = ThreadVersionToString(mThreadVersion);
240 Mdns::Publisher::TxtList txtList{{"nn", mNetworkName},
241 {"xp", mExtPanId, sizeof(mExtPanId)},
242 {"tv", versionString},
243 // "dd" represents for device discriminator which
244 // should always be the IEEE 802.15.4 extended address.
245 {"dd", mExtAddr, sizeof(mExtAddr)}};
247 mPublisher->PublishService(/* aHostName */ nullptr, kBorderAgentUdpPort, mNetworkName, kBorderAgentServiceType,
251 void BorderAgent::StartPublishService(void)
253 VerifyOrExit(mNetworkName[0] != '\0');
254 VerifyOrExit(mExtPanIdInitialized);
255 VerifyOrExit(mExtAddrInitialized);
256 VerifyOrExit(mThreadVersion != 0);
258 if (mPublisher->IsStarted())
268 otbrLog(OTBR_LOG_INFO, "Start publishing service");
271 void BorderAgent::StopPublishService(void)
273 VerifyOrExit(mPublisher != nullptr);
275 if (mPublisher->IsStarted())
281 otbrLog(OTBR_LOG_INFO, "Stop publishing service");
284 void BorderAgent::SetNetworkName(const char *aNetworkName)
286 strcpy_safe(mNetworkName, sizeof(mNetworkName), aNetworkName);
288 #if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
291 // Restart publisher to publish new service name.
293 StartPublishService();
298 void BorderAgent::SetExtPanId(const uint8_t *aExtPanId)
300 memcpy(mExtPanId, aExtPanId, sizeof(mExtPanId));
301 mExtPanIdInitialized = true;
302 #if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
305 StartPublishService();
310 void BorderAgent::SetExtAddr(const uint8_t *aExtAddr)
312 memcpy(mExtAddr, aExtAddr, sizeof(mExtAddr));
313 mExtAddrInitialized = true;
314 #if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
317 StartPublishService();
322 void BorderAgent::SetThreadVersion(uint16_t aThreadVersion)
324 mThreadVersion = aThreadVersion;
325 #if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
328 StartPublishService();
333 void BorderAgent::HandlePSKc(void *aContext, int aEvent, va_list aArguments)
335 OT_UNUSED_VARIABLE(aEvent);
337 assert(aEvent == Ncp::kEventPSKc);
339 static_cast<BorderAgent *>(aContext)->HandlePSKc(va_arg(aArguments, const uint8_t *));
342 void BorderAgent::HandlePSKc(const uint8_t *aPSKc)
344 mPSKcInitialized = false;
346 for (size_t i = 0; i < kSizePSKc; ++i)
350 mPSKcInitialized = true;
355 if (mPSKcInitialized)
364 otbrLog(OTBR_LOG_INFO, "PSKc is %s", (mPSKcInitialized ? "initialized" : "not initialized"));
367 void BorderAgent::HandleThreadState(bool aStarted)
369 VerifyOrExit(mThreadStarted != aStarted);
371 mThreadStarted = aStarted;
375 SuccessOrExit(mNcp->RequestEvent(Ncp::kEventPSKc));
384 otbrLog(OTBR_LOG_INFO, "Thread is %s", (aStarted ? "up" : "down"));
387 void BorderAgent::HandleThreadState(void *aContext, int aEvent, va_list aArguments)
389 OT_UNUSED_VARIABLE(aEvent);
391 assert(aEvent == Ncp::kEventThreadState);
393 int started = va_arg(aArguments, int);
394 static_cast<BorderAgent *>(aContext)->HandleThreadState(started);
397 void BorderAgent::HandleNetworkName(void *aContext, int aEvent, va_list aArguments)
399 OT_UNUSED_VARIABLE(aEvent);
401 assert(aEvent == Ncp::kEventNetworkName);
403 const char *networkName = va_arg(aArguments, const char *);
404 static_cast<BorderAgent *>(aContext)->SetNetworkName(networkName);
407 void BorderAgent::HandleExtPanId(void *aContext, int aEvent, va_list aArguments)
409 OT_UNUSED_VARIABLE(aEvent);
411 assert(aEvent == Ncp::kEventExtPanId);
413 const uint8_t *xpanid = va_arg(aArguments, const uint8_t *);
414 static_cast<BorderAgent *>(aContext)->SetExtPanId(xpanid);
417 void BorderAgent::HandleThreadVersion(void *aContext, int aEvent, va_list aArguments)
419 OT_UNUSED_VARIABLE(aEvent);
421 assert(aEvent == Ncp::kEventThreadVersion);
423 // `uint16_t` has been promoted to `int`.
424 uint16_t threadVersion = static_cast<uint16_t>(va_arg(aArguments, int));
425 static_cast<BorderAgent *>(aContext)->SetThreadVersion(threadVersion);
428 void BorderAgent::HandleExtAddr(void *aContext, int aEvent, va_list aArguments)
430 OT_UNUSED_VARIABLE(aEvent);
432 assert(aEvent == Ncp::kEventExtAddr);
434 const uint8_t *extAddr = va_arg(aArguments, const uint8_t *);
435 static_cast<BorderAgent *>(aContext)->SetExtAddr(extAddr);