• 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/dataset.h>
39 #include <openthread/logging.h>
40 #include <openthread/srp_server.h>
41 #include <openthread/tasklet.h>
42 #include <openthread/thread.h>
43 #include <openthread/thread_ftd.h>
44 #include <openthread/platform/logging.h>
45 #include <openthread/platform/misc.h>
46 #include <openthread/platform/radio.h>
47 #include <openthread/platform/settings.h>
48 
49 #include "common/code_utils.hpp"
50 #include "common/logging.hpp"
51 #include "common/types.hpp"
52 
53 #if OTBR_ENABLE_LEGACY
54 #include <ot-legacy-pairing-ext.h>
55 #endif
56 
57 namespace otbr {
58 namespace Ncp {
59 
60 static const uint16_t kThreadVersion11 = 2; ///< Thread Version 1.1
61 static const uint16_t kThreadVersion12 = 3; ///< Thread Version 1.2
62 static const uint16_t kThreadVersion13 = 4; ///< Thread Version 1.3
63 
ControllerOpenThread(const char * aInterfaceName,const std::vector<const char * > & aRadioUrls,const char * aBackboneInterfaceName,bool aDryRun,bool aEnableAutoAttach)64 ControllerOpenThread::ControllerOpenThread(const char *                     aInterfaceName,
65                                            const std::vector<const char *> &aRadioUrls,
66                                            const char *                     aBackboneInterfaceName,
67                                            bool                             aDryRun,
68                                            bool                             aEnableAutoAttach)
69     : mInstance(nullptr)
70     , mEnableAutoAttach(aEnableAutoAttach)
71 {
72     VerifyOrDie(aRadioUrls.size() <= OT_PLATFORM_CONFIG_MAX_RADIO_URLS, "Too many Radio URLs!");
73 
74     memset(&mConfig, 0, sizeof(mConfig));
75 
76     mConfig.mInterfaceName         = aInterfaceName;
77     mConfig.mBackboneInterfaceName = aBackboneInterfaceName;
78     mConfig.mDryRun                = aDryRun;
79 
80     for (const char *url : aRadioUrls)
81     {
82         mConfig.mRadioUrls[mConfig.mRadioUrlNum++] = url;
83     }
84     mConfig.mSpeedUpFactor = 1;
85 }
86 
~ControllerOpenThread(void)87 ControllerOpenThread::~ControllerOpenThread(void)
88 {
89     // Make sure OpenThread Instance was gracefully de-initialized.
90     assert(mInstance == nullptr);
91 }
92 
ConvertToOtbrLogLevel(otLogLevel aLogLevel)93 otbrLogLevel ControllerOpenThread::ConvertToOtbrLogLevel(otLogLevel aLogLevel)
94 {
95     otbrLogLevel otbrLogLevel;
96 
97     switch (aLogLevel)
98     {
99     case OT_LOG_LEVEL_NONE:
100         otbrLogLevel = OTBR_LOG_EMERG;
101         break;
102     case OT_LOG_LEVEL_CRIT:
103         otbrLogLevel = OTBR_LOG_CRIT;
104         break;
105     case OT_LOG_LEVEL_WARN:
106         otbrLogLevel = OTBR_LOG_WARNING;
107         break;
108     case OT_LOG_LEVEL_NOTE:
109         otbrLogLevel = OTBR_LOG_NOTICE;
110         break;
111     case OT_LOG_LEVEL_INFO:
112         otbrLogLevel = OTBR_LOG_INFO;
113         break;
114     case OT_LOG_LEVEL_DEBG:
115     default:
116         otbrLogLevel = OTBR_LOG_DEBUG;
117         break;
118     }
119 
120     return otbrLogLevel;
121 }
122 
ConvertToOtLogLevel(otbrLogLevel aLevel)123 otLogLevel ControllerOpenThread::ConvertToOtLogLevel(otbrLogLevel aLevel)
124 {
125     otLogLevel level;
126 
127     switch (aLevel)
128     {
129     case OTBR_LOG_EMERG:
130     case OTBR_LOG_ALERT:
131     case OTBR_LOG_CRIT:
132         level = OT_LOG_LEVEL_CRIT;
133         break;
134     case OTBR_LOG_ERR:
135     case OTBR_LOG_WARNING:
136         level = OT_LOG_LEVEL_WARN;
137         break;
138     case OTBR_LOG_NOTICE:
139         level = OT_LOG_LEVEL_NOTE;
140         break;
141     case OTBR_LOG_INFO:
142         level = OT_LOG_LEVEL_INFO;
143         break;
144     case OTBR_LOG_DEBUG:
145     default:
146         level = OT_LOG_LEVEL_DEBG;
147         break;
148     }
149 
150     return level;
151 }
152 
Init(void)153 void ControllerOpenThread::Init(void)
154 {
155     otbrError  error = OTBR_ERROR_NONE;
156     otLogLevel level = ConvertToOtLogLevel(otbrLogGetLevel());
157 
158     VerifyOrExit(otLoggingSetLevel(level) == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD);
159 
160     mInstance = otSysInit(&mConfig);
161     assert(mInstance != nullptr);
162 
163 #if OTBR_ENABLE_LEGACY
164     otLegacyInit();
165 #endif
166 
167     {
168         otError result = otSetStateChangedCallback(mInstance, &ControllerOpenThread::HandleStateChanged, this);
169 
170         agent::ThreadHelper::LogOpenThreadResult("Set state callback", result);
171         VerifyOrExit(result == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD);
172     }
173 
174 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
175     otSrpServerSetEnabled(mInstance, /* aEnabled */ true);
176 #endif
177 
178     mThreadHelper = std::unique_ptr<otbr::agent::ThreadHelper>(new otbr::agent::ThreadHelper(mInstance, this));
179 
180 exit:
181     SuccessOrDie(error, "Failed to initialize NCP!");
182 }
183 
Deinit(void)184 void ControllerOpenThread::Deinit(void)
185 {
186     assert(mInstance != nullptr);
187 
188     otSysDeinit();
189     mInstance = nullptr;
190 }
191 
HandleStateChanged(otChangedFlags aFlags)192 void ControllerOpenThread::HandleStateChanged(otChangedFlags aFlags)
193 {
194     if (aFlags & OT_CHANGED_THREAD_ROLE)
195     {
196         switch (otThreadGetDeviceRole(mInstance))
197         {
198         case OT_DEVICE_ROLE_DISABLED:
199 #if OTBR_ENABLE_LEGACY
200             otLegacyStop();
201 #endif
202             break;
203         case OT_DEVICE_ROLE_CHILD:
204         case OT_DEVICE_ROLE_ROUTER:
205         case OT_DEVICE_ROLE_LEADER:
206 #if OTBR_ENABLE_LEGACY
207             otLegacyStart();
208 #endif
209             break;
210         default:
211             break;
212         }
213     }
214 
215     for (auto &stateCallback : mThreadStateChangedCallbacks)
216     {
217         stateCallback(aFlags);
218     }
219 
220     mThreadHelper->StateChangedCallback(aFlags);
221 }
222 
Update(MainloopContext & aMainloop)223 void ControllerOpenThread::Update(MainloopContext &aMainloop)
224 {
225     if (otTaskletsArePending(mInstance))
226     {
227         aMainloop.mTimeout = ToTimeval(Microseconds::zero());
228     }
229 
230     otSysMainloopUpdate(mInstance, &aMainloop);
231 }
232 
Process(const MainloopContext & aMainloop)233 void ControllerOpenThread::Process(const MainloopContext &aMainloop)
234 {
235     otTaskletsProcess(mInstance);
236 
237     otSysMainloopProcess(mInstance, &aMainloop);
238 
239     if (IsAutoAttachEnabled() && mThreadHelper->TryResumeNetwork() == OT_ERROR_NONE)
240     {
241         DisableAutoAttach();
242     }
243 }
244 
IsAutoAttachEnabled(void)245 bool ControllerOpenThread::IsAutoAttachEnabled(void)
246 {
247     return mEnableAutoAttach;
248 }
249 
DisableAutoAttach(void)250 void ControllerOpenThread::DisableAutoAttach(void)
251 {
252     mEnableAutoAttach = false;
253 }
254 
PostTimerTask(Milliseconds aDelay,TaskRunner::Task<void> aTask)255 void ControllerOpenThread::PostTimerTask(Milliseconds aDelay, TaskRunner::Task<void> aTask)
256 {
257     mTaskRunner.Post(std::move(aDelay), std::move(aTask));
258 }
259 
RegisterResetHandler(std::function<void (void)> aHandler)260 void ControllerOpenThread::RegisterResetHandler(std::function<void(void)> aHandler)
261 {
262     mResetHandlers.emplace_back(std::move(aHandler));
263 }
264 
AddThreadStateChangedCallback(ThreadStateChangedCallback aCallback)265 void ControllerOpenThread::AddThreadStateChangedCallback(ThreadStateChangedCallback aCallback)
266 {
267     mThreadStateChangedCallbacks.emplace_back(std::move(aCallback));
268 }
269 
Reset(void)270 void ControllerOpenThread::Reset(void)
271 {
272     gPlatResetReason = OT_PLAT_RESET_REASON_SOFTWARE;
273 
274     otSysDeinit();
275     mInstance = nullptr;
276 
277     Init();
278     for (auto &handler : mResetHandlers)
279     {
280         handler();
281     }
282     mEnableAutoAttach = true;
283 }
284 
GetThreadVersion(void)285 const char *ControllerOpenThread::GetThreadVersion(void)
286 {
287     const char *version;
288 
289     switch (otThreadGetVersion())
290     {
291     case kThreadVersion11:
292         version = "1.1.1";
293         break;
294     case kThreadVersion12:
295         version = "1.2.0";
296         break;
297     case kThreadVersion13:
298         version = "1.3.0";
299         break;
300     default:
301         otbrLogEmerg("Unexpected thread version %hu", otThreadGetVersion());
302         exit(-1);
303     }
304     return version;
305 }
306 
307 /*
308  * Provide, if required an "otPlatLog()" function
309  */
otPlatLog(otLogLevel aLogLevel,otLogRegion aLogRegion,const char * aFormat,...)310 extern "C" void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
311 {
312     OT_UNUSED_VARIABLE(aLogRegion);
313 
314     otbrLogLevel otbrLogLevel = ControllerOpenThread::ConvertToOtbrLogLevel(aLogLevel);
315 
316     va_list ap;
317     va_start(ap, aFormat);
318     otbrLogvNoFilter(otbrLogLevel, aFormat, ap);
319     va_end(ap);
320 }
321 
otPlatLogHandleLevelChanged(otLogLevel aLogLevel)322 extern "C" void otPlatLogHandleLevelChanged(otLogLevel aLogLevel)
323 {
324     otbrLogSetLevel(ControllerOpenThread::ConvertToOtbrLogLevel(aLogLevel));
325     otbrLogInfo("OpenThread log level changed to %d", aLogLevel);
326 }
327 
328 } // namespace Ncp
329 } // namespace otbr
330