• 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 "RCP_HOST"
30 
31 #include "host/rcp_host.hpp"
32 
33 #include <assert.h>
34 #include <limits.h>
35 #include <stdio.h>
36 #include <string.h>
37 
38 #include <openthread/backbone_router_ftd.h>
39 #include <openthread/border_routing.h>
40 #include <openthread/dataset.h>
41 #include <openthread/dnssd_server.h>
42 #include <openthread/link_metrics.h>
43 #include <openthread/logging.h>
44 #include <openthread/nat64.h>
45 #include <openthread/srp_server.h>
46 #include <openthread/tasklet.h>
47 #include <openthread/thread.h>
48 #include <openthread/thread_ftd.h>
49 #include <openthread/trel.h>
50 #include <openthread/platform/logging.h>
51 #include <openthread/platform/misc.h>
52 #include <openthread/platform/radio.h>
53 #include <openthread/platform/settings.h>
54 
55 #include "common/code_utils.hpp"
56 #include "common/logging.hpp"
57 #include "common/types.hpp"
58 #if OTBR_ENABLE_FEATURE_FLAGS
59 #include "proto/feature_flag.pb.h"
60 #endif
61 
62 namespace otbr {
63 namespace Host {
64 
65 static const uint16_t kThreadVersion11 = 2; ///< Thread Version 1.1
66 static const uint16_t kThreadVersion12 = 3; ///< Thread Version 1.2
67 static const uint16_t kThreadVersion13 = 4; ///< Thread Version 1.3
68 static const uint16_t kThreadVersion14 = 5; ///< Thread Version 1.4
69 
70 // =============================== OtNetworkProperties ===============================
71 
OtNetworkProperties(void)72 OtNetworkProperties::OtNetworkProperties(void)
73     : mInstance(nullptr)
74 {
75 }
76 
GetDeviceRole(void) const77 otDeviceRole OtNetworkProperties::GetDeviceRole(void) const
78 {
79     return otThreadGetDeviceRole(mInstance);
80 }
81 
Ip6IsEnabled(void) const82 bool OtNetworkProperties::Ip6IsEnabled(void) const
83 {
84     return otIp6IsEnabled(mInstance);
85 }
86 
GetPartitionId(void) const87 uint32_t OtNetworkProperties::GetPartitionId(void) const
88 {
89     return otThreadGetPartitionId(mInstance);
90 }
91 
GetDatasetActiveTlvs(otOperationalDatasetTlvs & aDatasetTlvs) const92 void OtNetworkProperties::GetDatasetActiveTlvs(otOperationalDatasetTlvs &aDatasetTlvs) const
93 {
94     otError error = otDatasetGetActiveTlvs(mInstance, &aDatasetTlvs);
95 
96     if (error != OT_ERROR_NONE)
97     {
98         aDatasetTlvs.mLength = 0;
99         memset(aDatasetTlvs.mTlvs, 0, sizeof(aDatasetTlvs.mTlvs));
100     }
101 }
102 
GetDatasetPendingTlvs(otOperationalDatasetTlvs & aDatasetTlvs) const103 void OtNetworkProperties::GetDatasetPendingTlvs(otOperationalDatasetTlvs &aDatasetTlvs) const
104 {
105     otError error = otDatasetGetPendingTlvs(mInstance, &aDatasetTlvs);
106 
107     if (error != OT_ERROR_NONE)
108     {
109         aDatasetTlvs.mLength = 0;
110         memset(aDatasetTlvs.mTlvs, 0, sizeof(aDatasetTlvs.mTlvs));
111     }
112 }
113 
SetInstance(otInstance * aInstance)114 void OtNetworkProperties::SetInstance(otInstance *aInstance)
115 {
116     mInstance = aInstance;
117 }
118 
119 // =============================== RcpHost ===============================
120 
RcpHost(const char * aInterfaceName,const std::vector<const char * > & aRadioUrls,const char * aBackboneInterfaceName,bool aDryRun,bool aEnableAutoAttach)121 RcpHost::RcpHost(const char                      *aInterfaceName,
122                  const std::vector<const char *> &aRadioUrls,
123                  const char                      *aBackboneInterfaceName,
124                  bool                             aDryRun,
125                  bool                             aEnableAutoAttach)
126     : mInstance(nullptr)
127     , mEnableAutoAttach(aEnableAutoAttach)
128     , mThreadEnabledState(ThreadEnabledState::kStateDisabled)
129 {
130     VerifyOrDie(aRadioUrls.size() <= OT_PLATFORM_CONFIG_MAX_RADIO_URLS, "Too many Radio URLs!");
131 
132     memset(&mConfig, 0, sizeof(mConfig));
133 
134     mConfig.mInterfaceName         = aInterfaceName;
135     mConfig.mBackboneInterfaceName = aBackboneInterfaceName;
136     mConfig.mDryRun                = aDryRun;
137 
138     for (const char *url : aRadioUrls)
139     {
140         mConfig.mCoprocessorUrls.mUrls[mConfig.mCoprocessorUrls.mNum++] = url;
141     }
142     mConfig.mSpeedUpFactor = 1;
143 }
144 
~RcpHost(void)145 RcpHost::~RcpHost(void)
146 {
147     // Make sure OpenThread Instance was gracefully de-initialized.
148     assert(mInstance == nullptr);
149 }
150 
ConvertToOtbrLogLevel(otLogLevel aLogLevel)151 otbrLogLevel RcpHost::ConvertToOtbrLogLevel(otLogLevel aLogLevel)
152 {
153     otbrLogLevel otbrLogLevel;
154 
155     switch (aLogLevel)
156     {
157     case OT_LOG_LEVEL_NONE:
158         otbrLogLevel = OTBR_LOG_EMERG;
159         break;
160     case OT_LOG_LEVEL_CRIT:
161         otbrLogLevel = OTBR_LOG_CRIT;
162         break;
163     case OT_LOG_LEVEL_WARN:
164         otbrLogLevel = OTBR_LOG_WARNING;
165         break;
166     case OT_LOG_LEVEL_NOTE:
167         otbrLogLevel = OTBR_LOG_NOTICE;
168         break;
169     case OT_LOG_LEVEL_INFO:
170         otbrLogLevel = OTBR_LOG_INFO;
171         break;
172     case OT_LOG_LEVEL_DEBG:
173     default:
174         otbrLogLevel = OTBR_LOG_DEBUG;
175         break;
176     }
177 
178     return otbrLogLevel;
179 }
180 
181 #if OTBR_ENABLE_FEATURE_FLAGS
182 /* Converts ProtoLogLevel to otbrLogLevel */
ConvertProtoToOtbrLogLevel(ProtoLogLevel aProtoLogLevel)183 otbrLogLevel ConvertProtoToOtbrLogLevel(ProtoLogLevel aProtoLogLevel)
184 {
185     otbrLogLevel otbrLogLevel;
186 
187     switch (aProtoLogLevel)
188     {
189     case PROTO_LOG_EMERG:
190         otbrLogLevel = OTBR_LOG_EMERG;
191         break;
192     case PROTO_LOG_ALERT:
193         otbrLogLevel = OTBR_LOG_ALERT;
194         break;
195     case PROTO_LOG_CRIT:
196         otbrLogLevel = OTBR_LOG_CRIT;
197         break;
198     case PROTO_LOG_ERR:
199         otbrLogLevel = OTBR_LOG_ERR;
200         break;
201     case PROTO_LOG_WARNING:
202         otbrLogLevel = OTBR_LOG_WARNING;
203         break;
204     case PROTO_LOG_NOTICE:
205         otbrLogLevel = OTBR_LOG_NOTICE;
206         break;
207     case PROTO_LOG_INFO:
208         otbrLogLevel = OTBR_LOG_INFO;
209         break;
210     case PROTO_LOG_DEBUG:
211     default:
212         otbrLogLevel = OTBR_LOG_DEBUG;
213         break;
214     }
215 
216     return otbrLogLevel;
217 }
218 #endif
219 
SetOtbrAndOtLogLevel(otbrLogLevel aLevel)220 otError RcpHost::SetOtbrAndOtLogLevel(otbrLogLevel aLevel)
221 {
222     otError error = OT_ERROR_NONE;
223     otbrLogSetLevel(aLevel);
224     error = otLoggingSetLevel(ConvertToOtLogLevel(aLevel));
225     return error;
226 }
227 
Init(void)228 void RcpHost::Init(void)
229 {
230     otbrError  error = OTBR_ERROR_NONE;
231     otLogLevel level = ConvertToOtLogLevel(otbrLogGetLevel());
232 
233 #if OTBR_ENABLE_FEATURE_FLAGS && OTBR_ENABLE_TREL
234     FeatureFlagList featureFlagList;
235 #endif
236 
237     VerifyOrExit(otLoggingSetLevel(level) == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD);
238 
239     mInstance = otSysInit(&mConfig);
240     assert(mInstance != nullptr);
241 
242     {
243         otError result = otSetStateChangedCallback(mInstance, &RcpHost::HandleStateChanged, this);
244 
245         agent::ThreadHelper::LogOpenThreadResult("Set state callback", result);
246         VerifyOrExit(result == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD);
247     }
248 
249 #if OTBR_ENABLE_FEATURE_FLAGS && OTBR_ENABLE_TREL
250     // Enable/Disable trel according to feature flag default value.
251     otTrelSetEnabled(mInstance, featureFlagList.enable_trel());
252 #endif
253 
254 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
255 #if OTBR_ENABLE_SRP_SERVER_AUTO_ENABLE_MODE
256     // Let SRP server use auto-enable mode. The auto-enable mode delegates the control of SRP server to the Border
257     // Routing Manager. SRP server automatically starts when bi-directional connectivity is ready.
258     otSrpServerSetAutoEnableMode(mInstance, /* aEnabled */ true);
259 #else
260     otSrpServerSetEnabled(mInstance, /* aEnabled */ true);
261 #endif
262 #endif
263 
264 #if !OTBR_ENABLE_FEATURE_FLAGS
265     // Bring up all features when feature flags is not supported.
266 #if OTBR_ENABLE_NAT64
267     otNat64SetEnabled(mInstance, /* aEnabled */ true);
268 #endif
269 #if OTBR_ENABLE_DNS_UPSTREAM_QUERY
270     otDnssdUpstreamQuerySetEnabled(mInstance, /* aEnabled */ true);
271 #endif
272 #if OTBR_ENABLE_DHCP6_PD && OTBR_ENABLE_BORDER_ROUTING
273     otBorderRoutingDhcp6PdSetEnabled(mInstance, /* aEnabled */ true);
274 #endif
275 #endif // OTBR_ENABLE_FEATURE_FLAGS
276 
277     mThreadHelper = MakeUnique<otbr::agent::ThreadHelper>(mInstance, this);
278 
279     OtNetworkProperties::SetInstance(mInstance);
280 
281 exit:
282     SuccessOrDie(error, "Failed to initialize the RCP Host!");
283 }
284 
285 #if OTBR_ENABLE_FEATURE_FLAGS
ApplyFeatureFlagList(const FeatureFlagList & aFeatureFlagList)286 otError RcpHost::ApplyFeatureFlagList(const FeatureFlagList &aFeatureFlagList)
287 {
288     otError error = OT_ERROR_NONE;
289     // Save a cached copy of feature flags for debugging purpose.
290     mAppliedFeatureFlagListBytes = aFeatureFlagList.SerializeAsString();
291 
292 #if OTBR_ENABLE_NAT64
293     otNat64SetEnabled(mInstance, aFeatureFlagList.enable_nat64());
294 #endif
295 
296     if (aFeatureFlagList.enable_detailed_logging())
297     {
298         error = SetOtbrAndOtLogLevel(ConvertProtoToOtbrLogLevel(aFeatureFlagList.detailed_logging_level()));
299     }
300     else
301     {
302         error = SetOtbrAndOtLogLevel(otbrLogGetDefaultLevel());
303     }
304 
305 #if OTBR_ENABLE_TREL
306     otTrelSetEnabled(mInstance, aFeatureFlagList.enable_trel());
307 #endif
308 #if OTBR_ENABLE_DNS_UPSTREAM_QUERY
309     otDnssdUpstreamQuerySetEnabled(mInstance, aFeatureFlagList.enable_dns_upstream_query());
310 #endif
311 #if OTBR_ENABLE_DHCP6_PD
312     otBorderRoutingDhcp6PdSetEnabled(mInstance, aFeatureFlagList.enable_dhcp6_pd());
313 #endif
314 #if OTBR_ENABLE_LINK_METRICS_TELEMETRY
315     otLinkMetricsManagerSetEnabled(mInstance, aFeatureFlagList.enable_link_metrics_manager());
316 #endif
317 
318     return error;
319 }
320 #endif
321 
Deinit(void)322 void RcpHost::Deinit(void)
323 {
324     assert(mInstance != nullptr);
325 
326     otSysDeinit();
327     mInstance = nullptr;
328 
329     OtNetworkProperties::SetInstance(nullptr);
330     mThreadStateChangedCallbacks.clear();
331     mThreadEnabledStateChangedCallbacks.clear();
332     mResetHandlers.clear();
333 
334     mJoinReceiver              = nullptr;
335     mSetThreadEnabledReceiver  = nullptr;
336     mScheduleMigrationReceiver = nullptr;
337     mDetachGracefullyCallbacks.clear();
338 }
339 
HandleStateChanged(otChangedFlags aFlags)340 void RcpHost::HandleStateChanged(otChangedFlags aFlags)
341 {
342     for (auto &stateCallback : mThreadStateChangedCallbacks)
343     {
344         stateCallback(aFlags);
345     }
346 
347     mThreadHelper->StateChangedCallback(aFlags);
348 
349     if ((aFlags & OT_CHANGED_THREAD_ROLE) && IsAttached() && mJoinReceiver != nullptr)
350     {
351         otbrLogInfo("Join succeeded");
352         SafeInvokeAndClear(mJoinReceiver, OT_ERROR_NONE, "Join succeeded");
353     }
354 }
355 
Update(MainloopContext & aMainloop)356 void RcpHost::Update(MainloopContext &aMainloop)
357 {
358     if (otTaskletsArePending(mInstance))
359     {
360         aMainloop.mTimeout = ToTimeval(Microseconds::zero());
361     }
362 
363     otSysMainloopUpdate(mInstance, &aMainloop);
364 }
365 
Process(const MainloopContext & aMainloop)366 void RcpHost::Process(const MainloopContext &aMainloop)
367 {
368     otTaskletsProcess(mInstance);
369 
370     otSysMainloopProcess(mInstance, &aMainloop);
371 
372     if (IsAutoAttachEnabled() && mThreadHelper->TryResumeNetwork() == OT_ERROR_NONE)
373     {
374         DisableAutoAttach();
375     }
376 }
377 
IsAutoAttachEnabled(void)378 bool RcpHost::IsAutoAttachEnabled(void)
379 {
380     return mEnableAutoAttach;
381 }
382 
DisableAutoAttach(void)383 void RcpHost::DisableAutoAttach(void)
384 {
385     mEnableAutoAttach = false;
386 }
387 
PostTimerTask(Milliseconds aDelay,TaskRunner::Task<void> aTask)388 void RcpHost::PostTimerTask(Milliseconds aDelay, TaskRunner::Task<void> aTask)
389 {
390     mTaskRunner.Post(std::move(aDelay), std::move(aTask));
391 }
392 
RegisterResetHandler(std::function<void (void)> aHandler)393 void RcpHost::RegisterResetHandler(std::function<void(void)> aHandler)
394 {
395     mResetHandlers.emplace_back(std::move(aHandler));
396 }
397 
AddThreadStateChangedCallback(ThreadStateChangedCallback aCallback)398 void RcpHost::AddThreadStateChangedCallback(ThreadStateChangedCallback aCallback)
399 {
400     mThreadStateChangedCallbacks.emplace_back(std::move(aCallback));
401 }
402 
AddThreadEnabledStateChangedCallback(ThreadEnabledStateCallback aCallback)403 void RcpHost::AddThreadEnabledStateChangedCallback(ThreadEnabledStateCallback aCallback)
404 {
405     mThreadEnabledStateChangedCallbacks.push_back(aCallback);
406 }
407 
Reset(void)408 void RcpHost::Reset(void)
409 {
410     gPlatResetReason = OT_PLAT_RESET_REASON_SOFTWARE;
411 
412     otSysDeinit();
413     mInstance = nullptr;
414 
415     Init();
416     for (auto &handler : mResetHandlers)
417     {
418         handler();
419     }
420     mEnableAutoAttach = true;
421 }
422 
GetThreadVersion(void)423 const char *RcpHost::GetThreadVersion(void)
424 {
425     const char *version;
426 
427     switch (otThreadGetVersion())
428     {
429     case kThreadVersion11:
430         version = "1.1.1";
431         break;
432     case kThreadVersion12:
433         version = "1.2.0";
434         break;
435     case kThreadVersion13:
436         version = "1.3.0";
437         break;
438     case kThreadVersion14:
439         version = "1.4.0";
440         break;
441     default:
442         otbrLogEmerg("Unexpected thread version %hu", otThreadGetVersion());
443         exit(-1);
444     }
445     return version;
446 }
447 
noNeedRejoin(const otOperationalDatasetTlvs & aLhs,const otOperationalDatasetTlvs & aRhs)448 static bool noNeedRejoin(const otOperationalDatasetTlvs &aLhs, const otOperationalDatasetTlvs &aRhs)
449 {
450     bool result = false;
451 
452     otOperationalDataset lhsDataset;
453     otOperationalDataset rhsDataset;
454 
455     SuccessOrExit(otDatasetParseTlvs(&aLhs, &lhsDataset));
456     SuccessOrExit(otDatasetParseTlvs(&aRhs, &rhsDataset));
457 
458     result =
459         (lhsDataset.mChannel == rhsDataset.mChannel) &&
460         (memcmp(lhsDataset.mNetworkKey.m8, rhsDataset.mNetworkKey.m8, sizeof(lhsDataset.mNetworkKey)) == 0) &&
461         (memcmp(lhsDataset.mExtendedPanId.m8, rhsDataset.mExtendedPanId.m8, sizeof(lhsDataset.mExtendedPanId)) == 0);
462 
463 exit:
464     return result;
465 }
466 
Join(const otOperationalDatasetTlvs & aActiveOpDatasetTlvs,const AsyncResultReceiver & aReceiver)467 void RcpHost::Join(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs, const AsyncResultReceiver &aReceiver)
468 {
469     otError                  error = OT_ERROR_NONE;
470     std::string              errorMsg;
471     bool                     receiveResultHere = true;
472     otOperationalDatasetTlvs curDatasetTlvs;
473 
474     VerifyOrExit(mInstance != nullptr, error = OT_ERROR_INVALID_STATE, errorMsg = "OT is not initialized");
475     VerifyOrExit(mThreadEnabledState != ThreadEnabledState::kStateDisabling, error = OT_ERROR_BUSY,
476                  errorMsg = "Thread is disabling");
477     VerifyOrExit(mThreadEnabledState == ThreadEnabledState::kStateEnabled, error = OT_ERROR_INVALID_STATE,
478                  errorMsg = "Thread is not enabled");
479 
480     otbrLogInfo("Start joining...");
481 
482     error = otDatasetGetActiveTlvs(mInstance, &curDatasetTlvs);
483     if (error == OT_ERROR_NONE && noNeedRejoin(aActiveOpDatasetTlvs, curDatasetTlvs) && IsAttached())
484     {
485         // Do not leave and re-join if this device has already joined the same network. This can help elimilate
486         // unnecessary connectivity and topology disruption and save the time for re-joining. It's more useful for use
487         // cases where Thread networks are dynamically brought up and torn down (e.g. Thread on mobile phones).
488         SuccessOrExit(error    = otDatasetSetActiveTlvs(mInstance, &aActiveOpDatasetTlvs),
489                       errorMsg = "Failed to set Active Operational Dataset");
490         errorMsg = "Already Joined the target network";
491         ExitNow();
492     }
493 
494     if (GetDeviceRole() != OT_DEVICE_ROLE_DISABLED)
495     {
496         ThreadDetachGracefully([aActiveOpDatasetTlvs, aReceiver, this] {
497             ConditionalErasePersistentInfo(true);
498             Join(aActiveOpDatasetTlvs, aReceiver);
499         });
500         receiveResultHere = false;
501         ExitNow();
502     }
503 
504     SuccessOrExit(error    = otDatasetSetActiveTlvs(mInstance, &aActiveOpDatasetTlvs),
505                   errorMsg = "Failed to set Active Operational Dataset");
506 
507     // TODO(b/273160198): check how we can implement join as a child
508     SuccessOrExit(error = otIp6SetEnabled(mInstance, true), errorMsg = "Failed to bring up Thread interface");
509     SuccessOrExit(error = otThreadSetEnabled(mInstance, true), errorMsg = "Failed to bring up Thread stack");
510 
511     // Abort an ongoing join()
512     if (mJoinReceiver != nullptr)
513     {
514         SafeInvoke(mJoinReceiver, OT_ERROR_ABORT, "Join() is aborted");
515     }
516     mJoinReceiver     = aReceiver;
517     receiveResultHere = false;
518 
519 exit:
520     if (receiveResultHere)
521     {
522         mTaskRunner.Post([aReceiver, error, errorMsg](void) { aReceiver(error, errorMsg); });
523     }
524 }
525 
Leave(bool aEraseDataset,const AsyncResultReceiver & aReceiver)526 void RcpHost::Leave(bool aEraseDataset, const AsyncResultReceiver &aReceiver)
527 {
528     otError     error = OT_ERROR_NONE;
529     std::string errorMsg;
530     bool        receiveResultHere = true;
531 
532     VerifyOrExit(mInstance != nullptr, error = OT_ERROR_INVALID_STATE, errorMsg = "OT is not initialized");
533     VerifyOrExit(mThreadEnabledState != ThreadEnabledState::kStateDisabling, error = OT_ERROR_BUSY,
534                  errorMsg = "Thread is disabling");
535 
536     if (mThreadEnabledState == ThreadEnabledState::kStateDisabled)
537     {
538         ConditionalErasePersistentInfo(aEraseDataset);
539         ExitNow();
540     }
541 
542     ThreadDetachGracefully([aEraseDataset, aReceiver, this] {
543         ConditionalErasePersistentInfo(aEraseDataset);
544         if (aReceiver)
545         {
546             aReceiver(OT_ERROR_NONE, "");
547         }
548     });
549 
550 exit:
551     if (receiveResultHere)
552     {
553         mTaskRunner.Post([aReceiver, error, errorMsg](void) { aReceiver(error, errorMsg); });
554     }
555 }
556 
ScheduleMigration(const otOperationalDatasetTlvs & aPendingOpDatasetTlvs,const AsyncResultReceiver aReceiver)557 void RcpHost::ScheduleMigration(const otOperationalDatasetTlvs &aPendingOpDatasetTlvs,
558                                 const AsyncResultReceiver       aReceiver)
559 {
560     otError              error = OT_ERROR_NONE;
561     std::string          errorMsg;
562     otOperationalDataset emptyDataset;
563 
564     VerifyOrExit(mInstance != nullptr, error = OT_ERROR_INVALID_STATE, errorMsg = "OT is not initialized");
565 
566     VerifyOrExit(mThreadEnabledState != ThreadEnabledState::kStateDisabling, error = OT_ERROR_BUSY,
567                  errorMsg = "Thread is disabling");
568     VerifyOrExit(mThreadEnabledState == ThreadEnabledState::kStateEnabled, error = OT_ERROR_INVALID_STATE,
569                  errorMsg = "Thread is disabled");
570 
571     VerifyOrExit(IsAttached(), error = OT_ERROR_INVALID_STATE, errorMsg = "Device is detached");
572 
573     // TODO: check supported channel mask
574 
575     SuccessOrExit(error    = otDatasetSendMgmtPendingSet(mInstance, &emptyDataset, aPendingOpDatasetTlvs.mTlvs,
576                                                          static_cast<uint8_t>(aPendingOpDatasetTlvs.mLength),
577                                                          SendMgmtPendingSetCallback, this),
578                   errorMsg = "Failed to send MGMT_PENDING_SET.req");
579 
580 exit:
581     if (error != OT_ERROR_NONE)
582     {
583         mTaskRunner.Post([aReceiver, error, errorMsg](void) { aReceiver(error, errorMsg); });
584     }
585     else
586     {
587         // otDatasetSendMgmtPendingSet() returns OT_ERROR_BUSY if it has already been called before but the
588         // callback hasn't been invoked. So we can guarantee that mMigrationReceiver is always nullptr here
589         assert(mScheduleMigrationReceiver == nullptr);
590         mScheduleMigrationReceiver = aReceiver;
591     }
592 }
593 
SendMgmtPendingSetCallback(otError aError,void * aContext)594 void RcpHost::SendMgmtPendingSetCallback(otError aError, void *aContext)
595 {
596     static_cast<RcpHost *>(aContext)->SendMgmtPendingSetCallback(aError);
597 }
598 
SendMgmtPendingSetCallback(otError aError)599 void RcpHost::SendMgmtPendingSetCallback(otError aError)
600 {
601     SafeInvokeAndClear(mScheduleMigrationReceiver, aError, "");
602 }
603 
SetThreadEnabled(bool aEnabled,const AsyncResultReceiver aReceiver)604 void RcpHost::SetThreadEnabled(bool aEnabled, const AsyncResultReceiver aReceiver)
605 {
606     otError     error             = OT_ERROR_NONE;
607     std::string errorMsg          = "";
608     bool        receiveResultHere = true;
609 
610     VerifyOrExit(mInstance != nullptr, error = OT_ERROR_INVALID_STATE, errorMsg = "OT is not initialized");
611     VerifyOrExit(mThreadEnabledState != ThreadEnabledState::kStateDisabling, error = OT_ERROR_BUSY,
612                  errorMsg = "Thread is disabling");
613 
614     if (aEnabled)
615     {
616         otOperationalDatasetTlvs datasetTlvs;
617 
618         if (mThreadEnabledState == ThreadEnabledState::kStateEnabled)
619         {
620             ExitNow();
621         }
622 
623         if (otDatasetGetActiveTlvs(mInstance, &datasetTlvs) != OT_ERROR_NOT_FOUND && datasetTlvs.mLength > 0 &&
624             otThreadGetDeviceRole(mInstance) == OT_DEVICE_ROLE_DISABLED)
625         {
626             SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
627             SuccessOrExit(error = otThreadSetEnabled(mInstance, true));
628         }
629         UpdateThreadEnabledState(ThreadEnabledState::kStateEnabled);
630     }
631     else
632     {
633         UpdateThreadEnabledState(ThreadEnabledState::kStateDisabling);
634 
635         ThreadDetachGracefully([this](void) { DisableThreadAfterDetach(); });
636         mSetThreadEnabledReceiver = aReceiver;
637         receiveResultHere         = false;
638     }
639 
640 exit:
641     if (receiveResultHere)
642     {
643         mTaskRunner.Post([aReceiver, error, errorMsg](void) { SafeInvoke(aReceiver, error, errorMsg); });
644     }
645 }
646 
GetChannelMasks(const ChannelMasksReceiver & aReceiver,const AsyncResultReceiver & aErrReceiver)647 void RcpHost::GetChannelMasks(const ChannelMasksReceiver &aReceiver, const AsyncResultReceiver &aErrReceiver)
648 {
649     otError  error = OT_ERROR_NONE;
650     uint32_t supportedChannelMask;
651     uint32_t preferredChannelMask;
652 
653     VerifyOrExit(mInstance != nullptr, error = OT_ERROR_INVALID_STATE);
654 
655     supportedChannelMask = otLinkGetSupportedChannelMask(mInstance);
656     preferredChannelMask = otPlatRadioGetPreferredChannelMask(mInstance);
657 
658 exit:
659     if (error == OT_ERROR_NONE)
660     {
661         mTaskRunner.Post([aReceiver, supportedChannelMask, preferredChannelMask](void) {
662             aReceiver(supportedChannelMask, preferredChannelMask);
663         });
664     }
665     else
666     {
667         mTaskRunner.Post([aErrReceiver, error](void) { aErrReceiver(error, "OT is not initialized"); });
668     }
669 }
670 
671 #if OTBR_ENABLE_POWER_CALIBRATION
SetChannelMaxPowers(const std::vector<ChannelMaxPower> & aChannelMaxPowers,const AsyncResultReceiver & aReceiver)672 void RcpHost::SetChannelMaxPowers(const std::vector<ChannelMaxPower> &aChannelMaxPowers,
673                                   const AsyncResultReceiver          &aReceiver)
674 {
675     otError     error = OT_ERROR_NONE;
676     std::string errorMsg;
677 
678     VerifyOrExit(mInstance != nullptr, error = OT_ERROR_INVALID_STATE, errorMsg = "OT is not initialized");
679 
680     for (ChannelMaxPower channelMaxPower : aChannelMaxPowers)
681     {
682         VerifyOrExit((channelMaxPower.mChannel >= OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN) &&
683                          (channelMaxPower.mChannel <= OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX),
684                      error = OT_ERROR_INVALID_ARGS, errorMsg = "The channel is invalid");
685     }
686 
687     for (ChannelMaxPower channelMaxPower : aChannelMaxPowers)
688     {
689         otbrLogInfo("Set channel max power: channel=%u, maxPower=%u", static_cast<uint32_t>(channelMaxPower.mChannel),
690                     static_cast<uint32_t>(channelMaxPower.mMaxPower));
691         SuccessOrExit(error = otPlatRadioSetChannelTargetPower(
692                           mInstance, static_cast<uint8_t>(channelMaxPower.mChannel), channelMaxPower.mMaxPower),
693                       errorMsg = "Failed to set channel max power");
694     }
695 
696 exit:
697     mTaskRunner.Post([aReceiver, error, errorMsg](void) { aReceiver(error, errorMsg); });
698 }
699 #endif // OTBR_ENABLE_POWER_CALIBRATION
700 
ThreadDetachGracefully(const DetachGracefullyCallback & aCallback)701 void RcpHost::ThreadDetachGracefully(const DetachGracefullyCallback &aCallback)
702 {
703     mDetachGracefullyCallbacks.push_back(aCallback);
704 
705     // Ignores the OT_ERROR_BUSY error if a detach has already been requested
706     OT_UNUSED_VARIABLE(otThreadDetachGracefully(mInstance, ThreadDetachGracefullyCallback, this));
707 }
708 
ThreadDetachGracefullyCallback(void * aContext)709 void RcpHost::ThreadDetachGracefullyCallback(void *aContext)
710 {
711     static_cast<RcpHost *>(aContext)->ThreadDetachGracefullyCallback();
712 }
713 
ThreadDetachGracefullyCallback(void)714 void RcpHost::ThreadDetachGracefullyCallback(void)
715 {
716     SafeInvokeAndClear(mJoinReceiver, OT_ERROR_ABORT, "Aborted by leave/disable operation");
717     SafeInvokeAndClear(mScheduleMigrationReceiver, OT_ERROR_ABORT, "Aborted by leave/disable operation");
718 
719     for (auto &callback : mDetachGracefullyCallbacks)
720     {
721         callback();
722     }
723     mDetachGracefullyCallbacks.clear();
724 }
725 
ConditionalErasePersistentInfo(bool aErase)726 void RcpHost::ConditionalErasePersistentInfo(bool aErase)
727 {
728     if (aErase)
729     {
730         OT_UNUSED_VARIABLE(otInstanceErasePersistentInfo(mInstance));
731     }
732 }
733 
DisableThreadAfterDetach(void)734 void RcpHost::DisableThreadAfterDetach(void)
735 {
736     otError     error = OT_ERROR_NONE;
737     std::string errorMsg;
738 
739     SuccessOrExit(error = otThreadSetEnabled(mInstance, false), errorMsg = "Failed to disable Thread stack");
740     SuccessOrExit(error = otIp6SetEnabled(mInstance, false), errorMsg = "Failed to disable Thread interface");
741 
742     UpdateThreadEnabledState(ThreadEnabledState::kStateDisabled);
743 
744 exit:
745     SafeInvokeAndClear(mSetThreadEnabledReceiver, error, errorMsg);
746 }
747 
SetCountryCode(const std::string & aCountryCode,const AsyncResultReceiver & aReceiver)748 void RcpHost::SetCountryCode(const std::string &aCountryCode, const AsyncResultReceiver &aReceiver)
749 {
750     static constexpr int kCountryCodeLength = 2;
751     otError              error              = OT_ERROR_NONE;
752     std::string          errorMsg;
753     uint16_t             countryCode;
754 
755     VerifyOrExit((aCountryCode.length() == kCountryCodeLength) && isalpha(aCountryCode[0]) && isalpha(aCountryCode[1]),
756                  error = OT_ERROR_INVALID_ARGS, errorMsg = "The country code is invalid");
757 
758     otbrLogInfo("Set country code: %c%c", aCountryCode[0], aCountryCode[1]);
759     VerifyOrExit(mInstance != nullptr, error = OT_ERROR_INVALID_STATE, errorMsg = "OT is not initialized");
760 
761     countryCode = static_cast<uint16_t>((aCountryCode[0] << 8) | aCountryCode[1]);
762     SuccessOrExit(error = otLinkSetRegion(mInstance, countryCode), errorMsg = "Failed to set the country code");
763 
764 exit:
765     mTaskRunner.Post([aReceiver, error, errorMsg](void) { aReceiver(error, errorMsg); });
766 }
767 
IsAttached(void)768 bool RcpHost::IsAttached(void)
769 {
770     otDeviceRole role = GetDeviceRole();
771 
772     return role == OT_DEVICE_ROLE_CHILD || role == OT_DEVICE_ROLE_ROUTER || role == OT_DEVICE_ROLE_LEADER;
773 }
774 
UpdateThreadEnabledState(ThreadEnabledState aState)775 void RcpHost::UpdateThreadEnabledState(ThreadEnabledState aState)
776 {
777     mThreadEnabledState = aState;
778 
779     for (auto &callback : mThreadEnabledStateChangedCallbacks)
780     {
781         callback(mThreadEnabledState);
782     }
783 }
784 
785 /*
786  * Provide, if required an "otPlatLog()" function
787  */
otPlatLog(otLogLevel aLogLevel,otLogRegion aLogRegion,const char * aFormat,...)788 extern "C" void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
789 {
790     OT_UNUSED_VARIABLE(aLogRegion);
791 
792     otbrLogLevel otbrLogLevel = RcpHost::ConvertToOtbrLogLevel(aLogLevel);
793 
794     va_list ap;
795     va_start(ap, aFormat);
796     otbrLogvNoFilter(otbrLogLevel, aFormat, ap);
797     va_end(ap);
798 }
799 
otPlatLogHandleLevelChanged(otLogLevel aLogLevel)800 extern "C" void otPlatLogHandleLevelChanged(otLogLevel aLogLevel)
801 {
802     otbrLogSetLevel(RcpHost::ConvertToOtbrLogLevel(aLogLevel));
803     otbrLogInfo("OpenThread log level changed to %d", aLogLevel);
804 }
805 
806 } // namespace Host
807 } // namespace otbr
808