• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *    Copyright (c) 2019, The OpenThread Authors.
3  *    All rights reserved.
4  *
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.
15  *
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.
27  */
28 
29 #define OTBR_LOG_TAG "NCP"
30 
31 #include "ncp/ncp_openthread.hpp"
32 
33 #include <assert.h>
34 #include <stdio.h>
35 #include <string.h>
36 
37 #include <openthread/backbone_router_ftd.h>
38 #include <openthread/border_routing.h>
39 #include <openthread/dataset.h>
40 #include <openthread/dnssd_server.h>
41 #include <openthread/logging.h>
42 #include <openthread/nat64.h>
43 #include <openthread/srp_server.h>
44 #include <openthread/tasklet.h>
45 #include <openthread/thread.h>
46 #include <openthread/thread_ftd.h>
47 #include <openthread/trel.h>
48 #include <openthread/platform/logging.h>
49 #include <openthread/platform/misc.h>
50 #include <openthread/platform/radio.h>
51 #include <openthread/platform/settings.h>
52 
53 #include "common/code_utils.hpp"
54 #include "common/logging.hpp"
55 #include "common/types.hpp"
56 #if OTBR_ENABLE_FEATURE_FLAGS
57 #include "proto/feature_flag.pb.h"
58 #endif
59 
60 namespace otbr {
61 namespace Ncp {
62 
63 static const uint16_t kThreadVersion11 = 2; ///< Thread Version 1.1
64 static const uint16_t kThreadVersion12 = 3; ///< Thread Version 1.2
65 static const uint16_t kThreadVersion13 = 4; ///< Thread Version 1.3
66 static const uint16_t kThreadVersion14 = 5; ///< Thread Version 1.4
67 
ControllerOpenThread(const char * aInterfaceName,const std::vector<const char * > & aRadioUrls,const char * aBackboneInterfaceName,bool aDryRun,bool aEnableAutoAttach)68 ControllerOpenThread::ControllerOpenThread(const char                      *aInterfaceName,
69                                            const std::vector<const char *> &aRadioUrls,
70                                            const char                      *aBackboneInterfaceName,
71                                            bool                             aDryRun,
72                                            bool                             aEnableAutoAttach)
73     : mInstance(nullptr)
74     , mEnableAutoAttach(aEnableAutoAttach)
75 {
76     VerifyOrDie(aRadioUrls.size() <= OT_PLATFORM_CONFIG_MAX_RADIO_URLS, "Too many Radio URLs!");
77 
78     memset(&mConfig, 0, sizeof(mConfig));
79 
80     mConfig.mInterfaceName         = aInterfaceName;
81     mConfig.mBackboneInterfaceName = aBackboneInterfaceName;
82     mConfig.mDryRun                = aDryRun;
83 
84     for (const char *url : aRadioUrls)
85     {
86         mConfig.mRadioUrls[mConfig.mRadioUrlNum++] = url;
87     }
88     mConfig.mSpeedUpFactor = 1;
89 }
90 
~ControllerOpenThread(void)91 ControllerOpenThread::~ControllerOpenThread(void)
92 {
93     // Make sure OpenThread Instance was gracefully de-initialized.
94     assert(mInstance == nullptr);
95 }
96 
ConvertToOtbrLogLevel(otLogLevel aLogLevel)97 otbrLogLevel ControllerOpenThread::ConvertToOtbrLogLevel(otLogLevel aLogLevel)
98 {
99     otbrLogLevel otbrLogLevel;
100 
101     switch (aLogLevel)
102     {
103     case OT_LOG_LEVEL_NONE:
104         otbrLogLevel = OTBR_LOG_EMERG;
105         break;
106     case OT_LOG_LEVEL_CRIT:
107         otbrLogLevel = OTBR_LOG_CRIT;
108         break;
109     case OT_LOG_LEVEL_WARN:
110         otbrLogLevel = OTBR_LOG_WARNING;
111         break;
112     case OT_LOG_LEVEL_NOTE:
113         otbrLogLevel = OTBR_LOG_NOTICE;
114         break;
115     case OT_LOG_LEVEL_INFO:
116         otbrLogLevel = OTBR_LOG_INFO;
117         break;
118     case OT_LOG_LEVEL_DEBG:
119     default:
120         otbrLogLevel = OTBR_LOG_DEBUG;
121         break;
122     }
123 
124     return otbrLogLevel;
125 }
126 
127 #if OTBR_ENABLE_FEATURE_FLAGS
128 /* Converts ProtoLogLevel to otbrLogLevel */
ConvertProtoToOtbrLogLevel(ProtoLogLevel aProtoLogLevel)129 otbrLogLevel ConvertProtoToOtbrLogLevel(ProtoLogLevel aProtoLogLevel)
130 {
131     otbrLogLevel otbrLogLevel;
132 
133     switch (aProtoLogLevel)
134     {
135     case PROTO_LOG_EMERG:
136         otbrLogLevel = OTBR_LOG_EMERG;
137         break;
138     case PROTO_LOG_ALERT:
139         otbrLogLevel = OTBR_LOG_ALERT;
140         break;
141     case PROTO_LOG_CRIT:
142         otbrLogLevel = OTBR_LOG_CRIT;
143         break;
144     case PROTO_LOG_ERR:
145         otbrLogLevel = OTBR_LOG_ERR;
146         break;
147     case PROTO_LOG_WARNING:
148         otbrLogLevel = OTBR_LOG_WARNING;
149         break;
150     case PROTO_LOG_NOTICE:
151         otbrLogLevel = OTBR_LOG_NOTICE;
152         break;
153     case PROTO_LOG_INFO:
154         otbrLogLevel = OTBR_LOG_INFO;
155         break;
156     case PROTO_LOG_DEBUG:
157     default:
158         otbrLogLevel = OTBR_LOG_DEBUG;
159         break;
160     }
161 
162     return otbrLogLevel;
163 }
164 #endif
165 
ConvertToOtLogLevel(otbrLogLevel aLevel)166 otLogLevel ControllerOpenThread::ConvertToOtLogLevel(otbrLogLevel aLevel)
167 {
168     otLogLevel level;
169 
170     switch (aLevel)
171     {
172     case OTBR_LOG_EMERG:
173     case OTBR_LOG_ALERT:
174     case OTBR_LOG_CRIT:
175         level = OT_LOG_LEVEL_CRIT;
176         break;
177     case OTBR_LOG_ERR:
178     case OTBR_LOG_WARNING:
179         level = OT_LOG_LEVEL_WARN;
180         break;
181     case OTBR_LOG_NOTICE:
182         level = OT_LOG_LEVEL_NOTE;
183         break;
184     case OTBR_LOG_INFO:
185         level = OT_LOG_LEVEL_INFO;
186         break;
187     case OTBR_LOG_DEBUG:
188     default:
189         level = OT_LOG_LEVEL_DEBG;
190         break;
191     }
192 
193     return level;
194 }
195 
SetOtbrAndOtLogLevel(otbrLogLevel aLevel)196 otError ControllerOpenThread::SetOtbrAndOtLogLevel(otbrLogLevel aLevel)
197 {
198     otError error = OT_ERROR_NONE;
199     otbrLogSetLevel(aLevel);
200     error = otLoggingSetLevel(ConvertToOtLogLevel(aLevel));
201     return error;
202 }
203 
Init(void)204 void ControllerOpenThread::Init(void)
205 {
206     otbrError  error = OTBR_ERROR_NONE;
207     otLogLevel level = ConvertToOtLogLevel(otbrLogGetLevel());
208 
209 #if OTBR_ENABLE_FEATURE_FLAGS && OTBR_ENABLE_TREL
210     FeatureFlagList featureFlagList;
211 #endif
212 
213     VerifyOrExit(otLoggingSetLevel(level) == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD);
214 
215     mInstance = otSysInit(&mConfig);
216     assert(mInstance != nullptr);
217 
218     {
219         otError result = otSetStateChangedCallback(mInstance, &ControllerOpenThread::HandleStateChanged, this);
220 
221         agent::ThreadHelper::LogOpenThreadResult("Set state callback", result);
222         VerifyOrExit(result == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD);
223     }
224 
225 #if OTBR_ENABLE_FEATURE_FLAGS && OTBR_ENABLE_TREL
226     // Enable/Disable trel according to feature flag default value.
227     otTrelSetEnabled(mInstance, featureFlagList.enable_trel());
228 #endif
229 
230 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
231 #if OTBR_ENABLE_SRP_SERVER_AUTO_ENABLE_MODE
232     // Let SRP server use auto-enable mode. The auto-enable mode delegates the control of SRP server to the Border
233     // Routing Manager. SRP server automatically starts when bi-directional connectivity is ready.
234     otSrpServerSetAutoEnableMode(mInstance, /* aEnabled */ true);
235 #else
236     otSrpServerSetEnabled(mInstance, /* aEnabled */ true);
237 #endif
238 #endif
239 
240 #if !OTBR_ENABLE_FEATURE_FLAGS
241     // Bring up all features when feature flags is not supported.
242 #if OTBR_ENABLE_NAT64
243     otNat64SetEnabled(mInstance, /* aEnabled */ true);
244 #endif
245 #if OTBR_ENABLE_DNS_UPSTREAM_QUERY
246     otDnssdUpstreamQuerySetEnabled(mInstance, /* aEnabled */ true);
247 #endif
248 #if OTBR_ENABLE_DHCP6_PD
249     otBorderRoutingDhcp6PdSetEnabled(mInstance, /* aEnabled */ true);
250 #endif
251 #endif // OTBR_ENABLE_FEATURE_FLAGS
252 
253     mThreadHelper = std::unique_ptr<otbr::agent::ThreadHelper>(new otbr::agent::ThreadHelper(mInstance, this));
254 
255 exit:
256     SuccessOrDie(error, "Failed to initialize NCP!");
257 }
258 
259 #if OTBR_ENABLE_FEATURE_FLAGS
ApplyFeatureFlagList(const FeatureFlagList & aFeatureFlagList)260 otError ControllerOpenThread::ApplyFeatureFlagList(const FeatureFlagList &aFeatureFlagList)
261 {
262     otError error = OT_ERROR_NONE;
263     // Save a cached copy of feature flags for debugging purpose.
264     mAppliedFeatureFlagListBytes = aFeatureFlagList.SerializeAsString();
265 
266 #if OTBR_ENABLE_NAT64
267     otNat64SetEnabled(mInstance, aFeatureFlagList.enable_nat64());
268 #endif
269 
270     if (aFeatureFlagList.enable_detailed_logging())
271     {
272         error = SetOtbrAndOtLogLevel(ConvertProtoToOtbrLogLevel(aFeatureFlagList.detailed_logging_level()));
273     }
274     else
275     {
276         error = SetOtbrAndOtLogLevel(otbrLogGetDefaultLevel());
277     }
278 
279 #if OTBR_ENABLE_TREL
280     otTrelSetEnabled(mInstance, aFeatureFlagList.enable_trel());
281 #endif
282 #if OTBR_ENABLE_DNS_UPSTREAM_QUERY
283     otDnssdUpstreamQuerySetEnabled(mInstance, aFeatureFlagList.enable_dns_upstream_query());
284 #endif
285 #if OTBR_ENABLE_DHCP6_PD
286     otBorderRoutingDhcp6PdSetEnabled(mInstance, aFeatureFlagList.enable_dhcp6_pd());
287 #endif
288 
289     return error;
290 }
291 #endif
292 
Deinit(void)293 void ControllerOpenThread::Deinit(void)
294 {
295     assert(mInstance != nullptr);
296 
297     otSysDeinit();
298     mInstance = nullptr;
299 
300     mThreadStateChangedCallbacks.clear();
301     mResetHandlers.clear();
302 }
303 
HandleStateChanged(otChangedFlags aFlags)304 void ControllerOpenThread::HandleStateChanged(otChangedFlags aFlags)
305 {
306     for (auto &stateCallback : mThreadStateChangedCallbacks)
307     {
308         stateCallback(aFlags);
309     }
310 
311     mThreadHelper->StateChangedCallback(aFlags);
312 }
313 
Update(MainloopContext & aMainloop)314 void ControllerOpenThread::Update(MainloopContext &aMainloop)
315 {
316     if (otTaskletsArePending(mInstance))
317     {
318         aMainloop.mTimeout = ToTimeval(Microseconds::zero());
319     }
320 
321     otSysMainloopUpdate(mInstance, &aMainloop);
322 }
323 
Process(const MainloopContext & aMainloop)324 void ControllerOpenThread::Process(const MainloopContext &aMainloop)
325 {
326     otTaskletsProcess(mInstance);
327 
328     otSysMainloopProcess(mInstance, &aMainloop);
329 
330     if (IsAutoAttachEnabled() && mThreadHelper->TryResumeNetwork() == OT_ERROR_NONE)
331     {
332         DisableAutoAttach();
333     }
334 }
335 
IsAutoAttachEnabled(void)336 bool ControllerOpenThread::IsAutoAttachEnabled(void)
337 {
338     return mEnableAutoAttach;
339 }
340 
DisableAutoAttach(void)341 void ControllerOpenThread::DisableAutoAttach(void)
342 {
343     mEnableAutoAttach = false;
344 }
345 
PostTimerTask(Milliseconds aDelay,TaskRunner::Task<void> aTask)346 void ControllerOpenThread::PostTimerTask(Milliseconds aDelay, TaskRunner::Task<void> aTask)
347 {
348     mTaskRunner.Post(std::move(aDelay), std::move(aTask));
349 }
350 
RegisterResetHandler(std::function<void (void)> aHandler)351 void ControllerOpenThread::RegisterResetHandler(std::function<void(void)> aHandler)
352 {
353     mResetHandlers.emplace_back(std::move(aHandler));
354 }
355 
AddThreadStateChangedCallback(ThreadStateChangedCallback aCallback)356 void ControllerOpenThread::AddThreadStateChangedCallback(ThreadStateChangedCallback aCallback)
357 {
358     mThreadStateChangedCallbacks.emplace_back(std::move(aCallback));
359 }
360 
Reset(void)361 void ControllerOpenThread::Reset(void)
362 {
363     gPlatResetReason = OT_PLAT_RESET_REASON_SOFTWARE;
364 
365     otSysDeinit();
366     mInstance = nullptr;
367 
368     Init();
369     for (auto &handler : mResetHandlers)
370     {
371         handler();
372     }
373     mEnableAutoAttach = true;
374 }
375 
GetThreadVersion(void)376 const char *ControllerOpenThread::GetThreadVersion(void)
377 {
378     const char *version;
379 
380     switch (otThreadGetVersion())
381     {
382     case kThreadVersion11:
383         version = "1.1.1";
384         break;
385     case kThreadVersion12:
386         version = "1.2.0";
387         break;
388     case kThreadVersion13:
389         version = "1.3.0";
390         break;
391     case kThreadVersion14:
392         version = "1.4";
393         break;
394     default:
395         otbrLogEmerg("Unexpected thread version %hu", otThreadGetVersion());
396         exit(-1);
397     }
398     return version;
399 }
400 
401 /*
402  * Provide, if required an "otPlatLog()" function
403  */
otPlatLog(otLogLevel aLogLevel,otLogRegion aLogRegion,const char * aFormat,...)404 extern "C" void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
405 {
406     OT_UNUSED_VARIABLE(aLogRegion);
407 
408     otbrLogLevel otbrLogLevel = ControllerOpenThread::ConvertToOtbrLogLevel(aLogLevel);
409 
410     va_list ap;
411     va_start(ap, aFormat);
412     otbrLogvNoFilter(otbrLogLevel, aFormat, ap);
413     va_end(ap);
414 }
415 
otPlatLogHandleLevelChanged(otLogLevel aLogLevel)416 extern "C" void otPlatLogHandleLevelChanged(otLogLevel aLogLevel)
417 {
418     otbrLogSetLevel(ControllerOpenThread::ConvertToOtbrLogLevel(aLogLevel));
419     otbrLogInfo("OpenThread log level changed to %d", aLogLevel);
420 }
421 
422 } // namespace Ncp
423 } // namespace otbr
424