2 * Copyright (c) 2019, 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.
29 #include "agent/ncp_openthread.hpp"
35 #include <openthread/backbone_router_ftd.h>
36 #include <openthread/cli.h>
37 #include <openthread/dataset.h>
38 #include <openthread/logging.h>
39 #include <openthread/srp_server.h>
40 #include <openthread/tasklet.h>
41 #include <openthread/thread.h>
42 #include <openthread/thread_ftd.h>
43 #include <openthread/platform/logging.h>
44 #include <openthread/platform/misc.h>
45 #include <openthread/platform/radio.h>
46 #include <openthread/platform/settings.h>
48 #include "common/code_utils.hpp"
49 #include "common/logging.hpp"
50 #include "common/types.hpp"
52 #if OTBR_ENABLE_LEGACY
53 #include <ot-legacy-pairing-ext.h>
56 using std::chrono::duration_cast;
57 using std::chrono::microseconds;
58 using std::chrono::seconds;
59 using std::chrono::steady_clock;
64 ControllerOpenThread::ControllerOpenThread(const char *aInterfaceName,
65 const char *aRadioUrl,
66 const char *aBackboneInterfaceName)
69 memset(&mConfig, 0, sizeof(mConfig));
71 mConfig.mInterfaceName = aInterfaceName;
72 mConfig.mBackboneInterfaceName = aBackboneInterfaceName;
73 mConfig.mRadioUrl = aRadioUrl;
74 mConfig.mSpeedUpFactor = 1;
77 ControllerOpenThread::~ControllerOpenThread(void)
79 otInstanceFinalize(mInstance);
83 otbrError ControllerOpenThread::Init(void)
85 otbrError error = OTBR_ERROR_NONE;
86 otLogLevel level = OT_LOG_LEVEL_NONE;
88 switch (otbrLogGetLevel())
93 level = OT_LOG_LEVEL_CRIT;
96 case OTBR_LOG_WARNING:
97 level = OT_LOG_LEVEL_WARN;
100 level = OT_LOG_LEVEL_NOTE;
103 level = OT_LOG_LEVEL_INFO;
106 level = OT_LOG_LEVEL_DEBG;
109 ExitNow(error = OTBR_ERROR_OPENTHREAD);
112 VerifyOrExit(otLoggingSetLevel(level) == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD);
114 mInstance = otSysInit(&mConfig);
115 otCliUartInit(mInstance);
116 #if OTBR_ENABLE_LEGACY
121 otError result = otSetStateChangedCallback(mInstance, &ControllerOpenThread::HandleStateChanged, this);
123 agent::ThreadHelper::LogOpenThreadResult("Set state callback", result);
124 VerifyOrExit(result == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD);
127 #if OTBR_ENABLE_BACKBONE_ROUTER
128 otBackboneRouterSetDomainPrefixCallback(mInstance, &ControllerOpenThread::HandleBackboneRouterDomainPrefixEvent,
130 otBackboneRouterSetNdProxyCallback(mInstance, &ControllerOpenThread::HandleBackboneRouterNdProxyEvent, this);
133 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
134 otSrpServerSetEnabled(mInstance, /* aEnabled */ true);
137 mThreadHelper = std::unique_ptr<otbr::agent::ThreadHelper>(new otbr::agent::ThreadHelper(mInstance, this));
143 void ControllerOpenThread::HandleStateChanged(otChangedFlags aFlags)
145 if (aFlags & OT_CHANGED_THREAD_NETWORK_NAME)
147 EventEmitter::Emit(kEventNetworkName, otThreadGetNetworkName(mInstance));
150 if (aFlags & OT_CHANGED_THREAD_EXT_PANID)
152 EventEmitter::Emit(kEventExtPanId, otThreadGetExtendedPanId(mInstance));
155 if (aFlags & OT_CHANGED_THREAD_ROLE)
157 bool attached = false;
159 switch (otThreadGetDeviceRole(mInstance))
161 case OT_DEVICE_ROLE_DISABLED:
162 #if OTBR_ENABLE_LEGACY
166 case OT_DEVICE_ROLE_CHILD:
167 case OT_DEVICE_ROLE_ROUTER:
168 case OT_DEVICE_ROLE_LEADER:
169 #if OTBR_ENABLE_LEGACY
178 EventEmitter::Emit(kEventThreadState, attached);
181 #if OTBR_ENABLE_BACKBONE_ROUTER
182 if (aFlags & OT_CHANGED_THREAD_BACKBONE_ROUTER_STATE)
184 EventEmitter::Emit(kEventBackboneRouterState);
188 mThreadHelper->StateChangedCallback(aFlags);
191 static struct timeval ToTimeVal(const microseconds &aTime)
193 constexpr int kUsPerSecond = 1000000;
196 val.tv_sec = aTime.count() / kUsPerSecond;
197 val.tv_usec = aTime.count() % kUsPerSecond;
202 void ControllerOpenThread::UpdateFdSet(otSysMainloopContext &aMainloop)
204 microseconds timeout = microseconds(aMainloop.mTimeout.tv_usec) + seconds(aMainloop.mTimeout.tv_sec);
205 auto now = steady_clock::now();
207 if (otTaskletsArePending(mInstance))
209 timeout = microseconds::zero();
211 else if (!mTimers.empty())
213 if (mTimers.begin()->first < now)
215 timeout = microseconds::zero();
219 timeout = std::min(timeout, duration_cast<microseconds>(mTimers.begin()->first - now));
223 aMainloop.mTimeout = ToTimeVal(timeout);
225 otSysMainloopUpdate(mInstance, &aMainloop);
228 void ControllerOpenThread::Process(const otSysMainloopContext &aMainloop)
230 auto now = steady_clock::now();
232 otTaskletsProcess(mInstance);
234 otSysMainloopProcess(mInstance, &aMainloop);
236 while (!mTimers.empty() && mTimers.begin()->first <= now)
238 mTimers.begin()->second();
239 mTimers.erase(mTimers.begin());
242 if (getenv("OTBR_NO_AUTO_ATTACH") == nullptr && mThreadHelper->TryResumeNetwork() == OT_ERROR_NONE)
244 setenv("OTBR_NO_AUTO_ATTACH", "1", 0);
248 otbrError ControllerOpenThread::RequestEvent(int aEvent)
250 otbrError ret = OTBR_ERROR_NONE;
256 EventEmitter::Emit(kEventExtPanId, otThreadGetExtendedPanId(mInstance));
259 case kEventThreadState:
261 bool attached = false;
263 switch (otThreadGetDeviceRole(mInstance))
265 case OT_DEVICE_ROLE_CHILD:
266 case OT_DEVICE_ROLE_ROUTER:
267 case OT_DEVICE_ROLE_LEADER:
274 EventEmitter::Emit(kEventThreadState, attached);
277 case kEventNetworkName:
279 EventEmitter::Emit(kEventNetworkName, otThreadGetNetworkName(mInstance));
284 EventEmitter::Emit(kEventPSKc, otThreadGetPskc(mInstance));
287 case kEventThreadVersion:
289 EventEmitter::Emit(kEventThreadVersion, otThreadGetVersion());
294 const otExtAddress *extAddr;
296 extAddr = otLinkGetExtendedAddress(mInstance);
297 EventEmitter::Emit(kEventExtAddr, extAddr);
308 void ControllerOpenThread::PostTimerTask(std::chrono::steady_clock::time_point aTimePoint,
309 const std::function<void(void)> & aTask)
311 mTimers.insert({aTimePoint, aTask});
314 void ControllerOpenThread::RegisterResetHandler(std::function<void(void)> aHandler)
316 mResetHandlers.emplace_back(std::move(aHandler));
319 #if OTBR_ENABLE_BACKBONE_ROUTER
320 void ControllerOpenThread::HandleBackboneRouterDomainPrefixEvent(void * aContext,
321 otBackboneRouterDomainPrefixEvent aEvent,
322 const otIp6Prefix * aDomainPrefix)
324 static_cast<ControllerOpenThread *>(aContext)->HandleBackboneRouterDomainPrefixEvent(aEvent, aDomainPrefix);
327 void ControllerOpenThread::HandleBackboneRouterDomainPrefixEvent(otBackboneRouterDomainPrefixEvent aEvent,
328 const otIp6Prefix * aDomainPrefix)
330 EventEmitter::Emit(kEventBackboneRouterDomainPrefixEvent, aEvent, aDomainPrefix);
333 void ControllerOpenThread::HandleBackboneRouterNdProxyEvent(void * aContext,
334 otBackboneRouterNdProxyEvent aEvent,
335 const otIp6Address * aAddress)
337 static_cast<ControllerOpenThread *>(aContext)->HandleBackboneRouterNdProxyEvent(aEvent, aAddress);
340 void ControllerOpenThread::HandleBackboneRouterNdProxyEvent(otBackboneRouterNdProxyEvent aEvent,
341 const otIp6Address * aAddress)
343 EventEmitter::Emit(kEventBackboneRouterNdProxyEvent, aEvent, aAddress);
347 Controller *Controller::Create(const char *aInterfaceName, const char *aRadioUrl, const char *aBackboneInterfaceName)
349 return new ControllerOpenThread(aInterfaceName, aRadioUrl, aBackboneInterfaceName);
353 * Provide, if required an "otPlatLog()" function
355 extern "C" void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
357 OT_UNUSED_VARIABLE(aLogRegion);
363 case OT_LOG_LEVEL_NONE:
364 otbrLogLevel = OTBR_LOG_EMERG;
366 case OT_LOG_LEVEL_CRIT:
367 otbrLogLevel = OTBR_LOG_CRIT;
369 case OT_LOG_LEVEL_WARN:
370 otbrLogLevel = OTBR_LOG_WARNING;
372 case OT_LOG_LEVEL_NOTE:
373 otbrLogLevel = OTBR_LOG_NOTICE;
375 case OT_LOG_LEVEL_INFO:
376 otbrLogLevel = OTBR_LOG_INFO;
378 case OT_LOG_LEVEL_DEBG:
379 otbrLogLevel = OTBR_LOG_DEBUG;
382 otbrLogLevel = OTBR_LOG_DEBUG;
387 va_start(ap, aFormat);
388 otbrLogv(otbrLogLevel, aFormat, ap);