xref: /aosp_15_r20/external/ot-br-posix/src/ncp/rcp_host.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
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 "ncp/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 Ncp {
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 {
129     VerifyOrDie(aRadioUrls.size() <= OT_PLATFORM_CONFIG_MAX_RADIO_URLS, "Too many Radio URLs!");
130 
131     memset(&mConfig, 0, sizeof(mConfig));
132 
133     mConfig.mInterfaceName         = aInterfaceName;
134     mConfig.mBackboneInterfaceName = aBackboneInterfaceName;
135     mConfig.mDryRun                = aDryRun;
136 
137     for (const char *url : aRadioUrls)
138     {
139         mConfig.mCoprocessorUrls.mUrls[mConfig.mCoprocessorUrls.mNum++] = url;
140     }
141     mConfig.mSpeedUpFactor = 1;
142 }
143 
~RcpHost(void)144 RcpHost::~RcpHost(void)
145 {
146     // Make sure OpenThread Instance was gracefully de-initialized.
147     assert(mInstance == nullptr);
148 }
149 
ConvertToOtbrLogLevel(otLogLevel aLogLevel)150 otbrLogLevel RcpHost::ConvertToOtbrLogLevel(otLogLevel aLogLevel)
151 {
152     otbrLogLevel otbrLogLevel;
153 
154     switch (aLogLevel)
155     {
156     case OT_LOG_LEVEL_NONE:
157         otbrLogLevel = OTBR_LOG_EMERG;
158         break;
159     case OT_LOG_LEVEL_CRIT:
160         otbrLogLevel = OTBR_LOG_CRIT;
161         break;
162     case OT_LOG_LEVEL_WARN:
163         otbrLogLevel = OTBR_LOG_WARNING;
164         break;
165     case OT_LOG_LEVEL_NOTE:
166         otbrLogLevel = OTBR_LOG_NOTICE;
167         break;
168     case OT_LOG_LEVEL_INFO:
169         otbrLogLevel = OTBR_LOG_INFO;
170         break;
171     case OT_LOG_LEVEL_DEBG:
172     default:
173         otbrLogLevel = OTBR_LOG_DEBUG;
174         break;
175     }
176 
177     return otbrLogLevel;
178 }
179 
180 #if OTBR_ENABLE_FEATURE_FLAGS
181 /* Converts ProtoLogLevel to otbrLogLevel */
ConvertProtoToOtbrLogLevel(ProtoLogLevel aProtoLogLevel)182 otbrLogLevel ConvertProtoToOtbrLogLevel(ProtoLogLevel aProtoLogLevel)
183 {
184     otbrLogLevel otbrLogLevel;
185 
186     switch (aProtoLogLevel)
187     {
188     case PROTO_LOG_EMERG:
189         otbrLogLevel = OTBR_LOG_EMERG;
190         break;
191     case PROTO_LOG_ALERT:
192         otbrLogLevel = OTBR_LOG_ALERT;
193         break;
194     case PROTO_LOG_CRIT:
195         otbrLogLevel = OTBR_LOG_CRIT;
196         break;
197     case PROTO_LOG_ERR:
198         otbrLogLevel = OTBR_LOG_ERR;
199         break;
200     case PROTO_LOG_WARNING:
201         otbrLogLevel = OTBR_LOG_WARNING;
202         break;
203     case PROTO_LOG_NOTICE:
204         otbrLogLevel = OTBR_LOG_NOTICE;
205         break;
206     case PROTO_LOG_INFO:
207         otbrLogLevel = OTBR_LOG_INFO;
208         break;
209     case PROTO_LOG_DEBUG:
210     default:
211         otbrLogLevel = OTBR_LOG_DEBUG;
212         break;
213     }
214 
215     return otbrLogLevel;
216 }
217 #endif
218 
SetOtbrAndOtLogLevel(otbrLogLevel aLevel)219 otError RcpHost::SetOtbrAndOtLogLevel(otbrLogLevel aLevel)
220 {
221     otError error = OT_ERROR_NONE;
222     otbrLogSetLevel(aLevel);
223     error = otLoggingSetLevel(ConvertToOtLogLevel(aLevel));
224     return error;
225 }
226 
Init(void)227 void RcpHost::Init(void)
228 {
229     otbrError  error = OTBR_ERROR_NONE;
230     otLogLevel level = ConvertToOtLogLevel(otbrLogGetLevel());
231 
232 #if OTBR_ENABLE_FEATURE_FLAGS && OTBR_ENABLE_TREL
233     FeatureFlagList featureFlagList;
234 #endif
235 
236     VerifyOrExit(otLoggingSetLevel(level) == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD);
237 
238     mInstance = otSysInit(&mConfig);
239     assert(mInstance != nullptr);
240 
241     {
242         otError result = otSetStateChangedCallback(mInstance, &RcpHost::HandleStateChanged, this);
243 
244         agent::ThreadHelper::LogOpenThreadResult("Set state callback", result);
245         VerifyOrExit(result == OT_ERROR_NONE, error = OTBR_ERROR_OPENTHREAD);
246     }
247 
248 #if OTBR_ENABLE_FEATURE_FLAGS && OTBR_ENABLE_TREL
249     // Enable/Disable trel according to feature flag default value.
250     otTrelSetEnabled(mInstance, featureFlagList.enable_trel());
251 #endif
252 
253 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
254 #if OTBR_ENABLE_SRP_SERVER_AUTO_ENABLE_MODE
255     // Let SRP server use auto-enable mode. The auto-enable mode delegates the control of SRP server to the Border
256     // Routing Manager. SRP server automatically starts when bi-directional connectivity is ready.
257     otSrpServerSetAutoEnableMode(mInstance, /* aEnabled */ true);
258 #else
259     otSrpServerSetEnabled(mInstance, /* aEnabled */ true);
260 #endif
261 #endif
262 
263 #if !OTBR_ENABLE_FEATURE_FLAGS
264     // Bring up all features when feature flags is not supported.
265 #if OTBR_ENABLE_NAT64
266     otNat64SetEnabled(mInstance, /* aEnabled */ true);
267 #endif
268 #if OTBR_ENABLE_DNS_UPSTREAM_QUERY
269     otDnssdUpstreamQuerySetEnabled(mInstance, /* aEnabled */ true);
270 #endif
271 #if OTBR_ENABLE_DHCP6_PD
272     otBorderRoutingDhcp6PdSetEnabled(mInstance, /* aEnabled */ true);
273 #endif
274 #endif // OTBR_ENABLE_FEATURE_FLAGS
275 
276     mThreadHelper = MakeUnique<otbr::agent::ThreadHelper>(mInstance, this);
277 
278     OtNetworkProperties::SetInstance(mInstance);
279 
280 exit:
281     SuccessOrDie(error, "Failed to initialize the RCP Host!");
282 }
283 
284 #if OTBR_ENABLE_FEATURE_FLAGS
ApplyFeatureFlagList(const FeatureFlagList & aFeatureFlagList)285 otError RcpHost::ApplyFeatureFlagList(const FeatureFlagList &aFeatureFlagList)
286 {
287     otError error = OT_ERROR_NONE;
288     // Save a cached copy of feature flags for debugging purpose.
289     mAppliedFeatureFlagListBytes = aFeatureFlagList.SerializeAsString();
290 
291 #if OTBR_ENABLE_NAT64
292     otNat64SetEnabled(mInstance, aFeatureFlagList.enable_nat64());
293 #endif
294 
295     if (aFeatureFlagList.enable_detailed_logging())
296     {
297         error = SetOtbrAndOtLogLevel(ConvertProtoToOtbrLogLevel(aFeatureFlagList.detailed_logging_level()));
298     }
299     else
300     {
301         error = SetOtbrAndOtLogLevel(otbrLogGetDefaultLevel());
302     }
303 
304 #if OTBR_ENABLE_TREL
305     otTrelSetEnabled(mInstance, aFeatureFlagList.enable_trel());
306 #endif
307 #if OTBR_ENABLE_DNS_UPSTREAM_QUERY
308     otDnssdUpstreamQuerySetEnabled(mInstance, aFeatureFlagList.enable_dns_upstream_query());
309 #endif
310 #if OTBR_ENABLE_DHCP6_PD
311     otBorderRoutingDhcp6PdSetEnabled(mInstance, aFeatureFlagList.enable_dhcp6_pd());
312 #endif
313 #if OTBR_ENABLE_LINK_METRICS_TELEMETRY
314     otLinkMetricsManagerSetEnabled(mInstance, aFeatureFlagList.enable_link_metrics_manager());
315 #endif
316 
317     return error;
318 }
319 #endif
320 
Deinit(void)321 void RcpHost::Deinit(void)
322 {
323     assert(mInstance != nullptr);
324 
325     otSysDeinit();
326     mInstance = nullptr;
327 
328     OtNetworkProperties::SetInstance(nullptr);
329     mThreadStateChangedCallbacks.clear();
330     mResetHandlers.clear();
331 
332     mSetThreadEnabledReceiver  = nullptr;
333     mScheduleMigrationReceiver = nullptr;
334 }
335 
HandleStateChanged(otChangedFlags aFlags)336 void RcpHost::HandleStateChanged(otChangedFlags aFlags)
337 {
338     for (auto &stateCallback : mThreadStateChangedCallbacks)
339     {
340         stateCallback(aFlags);
341     }
342 
343     mThreadHelper->StateChangedCallback(aFlags);
344 }
345 
Update(MainloopContext & aMainloop)346 void RcpHost::Update(MainloopContext &aMainloop)
347 {
348     if (otTaskletsArePending(mInstance))
349     {
350         aMainloop.mTimeout = ToTimeval(Microseconds::zero());
351     }
352 
353     otSysMainloopUpdate(mInstance, &aMainloop);
354 }
355 
Process(const MainloopContext & aMainloop)356 void RcpHost::Process(const MainloopContext &aMainloop)
357 {
358     otTaskletsProcess(mInstance);
359 
360     otSysMainloopProcess(mInstance, &aMainloop);
361 
362     if (IsAutoAttachEnabled() && mThreadHelper->TryResumeNetwork() == OT_ERROR_NONE)
363     {
364         DisableAutoAttach();
365     }
366 }
367 
IsAutoAttachEnabled(void)368 bool RcpHost::IsAutoAttachEnabled(void)
369 {
370     return mEnableAutoAttach;
371 }
372 
DisableAutoAttach(void)373 void RcpHost::DisableAutoAttach(void)
374 {
375     mEnableAutoAttach = false;
376 }
377 
PostTimerTask(Milliseconds aDelay,TaskRunner::Task<void> aTask)378 void RcpHost::PostTimerTask(Milliseconds aDelay, TaskRunner::Task<void> aTask)
379 {
380     mTaskRunner.Post(std::move(aDelay), std::move(aTask));
381 }
382 
RegisterResetHandler(std::function<void (void)> aHandler)383 void RcpHost::RegisterResetHandler(std::function<void(void)> aHandler)
384 {
385     mResetHandlers.emplace_back(std::move(aHandler));
386 }
387 
AddThreadStateChangedCallback(ThreadStateChangedCallback aCallback)388 void RcpHost::AddThreadStateChangedCallback(ThreadStateChangedCallback aCallback)
389 {
390     mThreadStateChangedCallbacks.emplace_back(std::move(aCallback));
391 }
392 
Reset(void)393 void RcpHost::Reset(void)
394 {
395     gPlatResetReason = OT_PLAT_RESET_REASON_SOFTWARE;
396 
397     otSysDeinit();
398     mInstance = nullptr;
399 
400     Init();
401     for (auto &handler : mResetHandlers)
402     {
403         handler();
404     }
405     mEnableAutoAttach = true;
406 }
407 
GetThreadVersion(void)408 const char *RcpHost::GetThreadVersion(void)
409 {
410     const char *version;
411 
412     switch (otThreadGetVersion())
413     {
414     case kThreadVersion11:
415         version = "1.1.1";
416         break;
417     case kThreadVersion12:
418         version = "1.2.0";
419         break;
420     case kThreadVersion13:
421         version = "1.3.0";
422         break;
423     case kThreadVersion14:
424         version = "1.4.0";
425         break;
426     default:
427         otbrLogEmerg("Unexpected thread version %hu", otThreadGetVersion());
428         exit(-1);
429     }
430     return version;
431 }
432 
Join(const otOperationalDatasetTlvs & aActiveOpDatasetTlvs,const AsyncResultReceiver & aReceiver)433 void RcpHost::Join(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs, const AsyncResultReceiver &aReceiver)
434 {
435     OT_UNUSED_VARIABLE(aActiveOpDatasetTlvs);
436 
437     // TODO: Implement Join under RCP mode.
438     mTaskRunner.Post([aReceiver](void) { aReceiver(OT_ERROR_NOT_IMPLEMENTED, "Not implemented!"); });
439 }
440 
Leave(const AsyncResultReceiver & aReceiver)441 void RcpHost::Leave(const AsyncResultReceiver &aReceiver)
442 {
443     // TODO: Implement Leave under RCP mode.
444     mTaskRunner.Post([aReceiver](void) { aReceiver(OT_ERROR_NOT_IMPLEMENTED, "Not implemented!"); });
445 }
446 
ScheduleMigration(const otOperationalDatasetTlvs & aPendingOpDatasetTlvs,const AsyncResultReceiver aReceiver)447 void RcpHost::ScheduleMigration(const otOperationalDatasetTlvs &aPendingOpDatasetTlvs,
448                                 const AsyncResultReceiver       aReceiver)
449 {
450     otError              error = OT_ERROR_NONE;
451     std::string          errorMsg;
452     otOperationalDataset emptyDataset;
453 
454     VerifyOrExit(mInstance != nullptr, error = OT_ERROR_INVALID_STATE, errorMsg = "OT is not initialized");
455     VerifyOrExit(IsAttached(), error = OT_ERROR_FAILED,
456                  errorMsg = "Cannot schedule migration when this device is detached");
457 
458     // TODO: check supported channel mask
459 
460     SuccessOrExit(error    = otDatasetSendMgmtPendingSet(mInstance, &emptyDataset, aPendingOpDatasetTlvs.mTlvs,
461                                                          static_cast<uint8_t>(aPendingOpDatasetTlvs.mLength),
462                                                          SendMgmtPendingSetCallback, this),
463                   errorMsg = "Failed to send MGMT_PENDING_SET.req");
464 
465 exit:
466     if (error != OT_ERROR_NONE)
467     {
468         mTaskRunner.Post([aReceiver, error, errorMsg](void) { aReceiver(error, errorMsg); });
469     }
470     else
471     {
472         // otDatasetSendMgmtPendingSet() returns OT_ERROR_BUSY if it has already been called before but the
473         // callback hasn't been invoked. So we can guarantee that mMigrationReceiver is always nullptr here
474         assert(mScheduleMigrationReceiver == nullptr);
475         mScheduleMigrationReceiver = aReceiver;
476     }
477 }
478 
SendMgmtPendingSetCallback(otError aError,void * aContext)479 void RcpHost::SendMgmtPendingSetCallback(otError aError, void *aContext)
480 {
481     static_cast<RcpHost *>(aContext)->SendMgmtPendingSetCallback(aError);
482 }
483 
SendMgmtPendingSetCallback(otError aError)484 void RcpHost::SendMgmtPendingSetCallback(otError aError)
485 {
486     SafeInvokeAndClear(mScheduleMigrationReceiver, aError, "");
487 }
488 
SetThreadEnabled(bool aEnabled,const AsyncResultReceiver aReceiver)489 void RcpHost::SetThreadEnabled(bool aEnabled, const AsyncResultReceiver aReceiver)
490 {
491     otError error             = OT_ERROR_NONE;
492     bool    receiveResultHere = true;
493 
494     VerifyOrExit(mInstance != nullptr, error = OT_ERROR_INVALID_STATE);
495     VerifyOrExit(mSetThreadEnabledReceiver == nullptr, error = OT_ERROR_BUSY);
496 
497     if (aEnabled)
498     {
499         otOperationalDatasetTlvs datasetTlvs;
500 
501         if (otDatasetGetActiveTlvs(mInstance, &datasetTlvs) != OT_ERROR_NOT_FOUND && datasetTlvs.mLength > 0 &&
502             otThreadGetDeviceRole(mInstance) == OT_DEVICE_ROLE_DISABLED)
503         {
504             SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
505             SuccessOrExit(error = otThreadSetEnabled(mInstance, true));
506         }
507     }
508     else
509     {
510         SuccessOrExit(error = otThreadDetachGracefully(mInstance, DisableThreadAfterDetach, this));
511         mSetThreadEnabledReceiver = aReceiver;
512         receiveResultHere         = false;
513     }
514 
515 exit:
516     if (receiveResultHere)
517     {
518         mTaskRunner.Post([aReceiver, error](void) { aReceiver(error, ""); });
519     }
520 }
521 
GetChannelMasks(const ChannelMasksReceiver & aReceiver,const AsyncResultReceiver & aErrReceiver)522 void RcpHost::GetChannelMasks(const ChannelMasksReceiver &aReceiver, const AsyncResultReceiver &aErrReceiver)
523 {
524     otError  error = OT_ERROR_NONE;
525     uint32_t supportedChannelMask;
526     uint32_t preferredChannelMask;
527 
528     VerifyOrExit(mInstance != nullptr, error = OT_ERROR_INVALID_STATE);
529 
530     supportedChannelMask = otLinkGetSupportedChannelMask(mInstance);
531     preferredChannelMask = otPlatRadioGetPreferredChannelMask(mInstance);
532 
533 exit:
534     if (error == OT_ERROR_NONE)
535     {
536         mTaskRunner.Post([aReceiver, supportedChannelMask, preferredChannelMask](void) {
537             aReceiver(supportedChannelMask, preferredChannelMask);
538         });
539     }
540     else
541     {
542         mTaskRunner.Post([aErrReceiver, error](void) { aErrReceiver(error, "OT is not initialized"); });
543     }
544 }
545 
SetChannelMaxPowers(const std::vector<ChannelMaxPower> & aChannelMaxPowers,const AsyncResultReceiver & aReceiver)546 void RcpHost::SetChannelMaxPowers(const std::vector<ChannelMaxPower> &aChannelMaxPowers,
547                                   const AsyncResultReceiver          &aReceiver)
548 {
549     otError     error = OT_ERROR_NONE;
550     std::string errorMsg;
551 
552     VerifyOrExit(mInstance != nullptr, error = OT_ERROR_INVALID_STATE, errorMsg = "OT is not initialized");
553 
554     for (ChannelMaxPower channelMaxPower : aChannelMaxPowers)
555     {
556         VerifyOrExit((channelMaxPower.mChannel >= OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN) &&
557                          (channelMaxPower.mChannel <= OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX),
558                      error = OT_ERROR_INVALID_ARGS, errorMsg = "The channel is invalid");
559     }
560 
561     for (ChannelMaxPower channelMaxPower : aChannelMaxPowers)
562     {
563         otbrLogInfo("Set channel max power: channel=%u, maxPower=%u", static_cast<uint32_t>(channelMaxPower.mChannel),
564                     static_cast<uint32_t>(channelMaxPower.mMaxPower));
565         SuccessOrExit(error = otPlatRadioSetChannelTargetPower(
566                           mInstance, static_cast<uint8_t>(channelMaxPower.mChannel), channelMaxPower.mMaxPower),
567                       errorMsg = "Failed to set channel max power");
568     }
569 
570 exit:
571     mTaskRunner.Post([aReceiver, error, errorMsg](void) { aReceiver(error, errorMsg); });
572 }
573 
DisableThreadAfterDetach(void * aContext)574 void RcpHost::DisableThreadAfterDetach(void *aContext)
575 {
576     static_cast<RcpHost *>(aContext)->DisableThreadAfterDetach();
577 }
578 
DisableThreadAfterDetach(void)579 void RcpHost::DisableThreadAfterDetach(void)
580 {
581     otError     error = OT_ERROR_NONE;
582     std::string errorMsg;
583 
584     SuccessOrExit(error = otThreadSetEnabled(mInstance, false), errorMsg = "Failed to disable Thread stack");
585     SuccessOrExit(error = otIp6SetEnabled(mInstance, false), errorMsg = "Failed to disable Thread interface");
586 
587 exit:
588     SafeInvokeAndClear(mSetThreadEnabledReceiver, error, errorMsg);
589 }
590 
SetCountryCode(const std::string & aCountryCode,const AsyncResultReceiver & aReceiver)591 void RcpHost::SetCountryCode(const std::string &aCountryCode, const AsyncResultReceiver &aReceiver)
592 {
593     static constexpr int kCountryCodeLength = 2;
594     otError              error              = OT_ERROR_NONE;
595     std::string          errorMsg;
596     uint16_t             countryCode;
597 
598     VerifyOrExit((aCountryCode.length() == kCountryCodeLength) && isalpha(aCountryCode[0]) && isalpha(aCountryCode[1]),
599                  error = OT_ERROR_INVALID_ARGS, errorMsg = "The country code is invalid");
600 
601     otbrLogInfo("Set country code: %c%c", aCountryCode[0], aCountryCode[1]);
602     VerifyOrExit(mInstance != nullptr, error = OT_ERROR_INVALID_STATE, errorMsg = "OT is not initialized");
603 
604     countryCode = static_cast<uint16_t>((aCountryCode[0] << 8) | aCountryCode[1]);
605     SuccessOrExit(error = otLinkSetRegion(mInstance, countryCode), errorMsg = "Failed to set the country code");
606 
607 exit:
608     mTaskRunner.Post([aReceiver, error, errorMsg](void) { aReceiver(error, errorMsg); });
609 }
610 
IsAttached(void)611 bool RcpHost::IsAttached(void)
612 {
613     otDeviceRole role = GetDeviceRole();
614 
615     return role == OT_DEVICE_ROLE_CHILD || role == OT_DEVICE_ROLE_ROUTER || role == OT_DEVICE_ROLE_LEADER;
616 }
617 
618 /*
619  * Provide, if required an "otPlatLog()" function
620  */
otPlatLog(otLogLevel aLogLevel,otLogRegion aLogRegion,const char * aFormat,...)621 extern "C" void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
622 {
623     OT_UNUSED_VARIABLE(aLogRegion);
624 
625     otbrLogLevel otbrLogLevel = RcpHost::ConvertToOtbrLogLevel(aLogLevel);
626 
627     va_list ap;
628     va_start(ap, aFormat);
629     otbrLogvNoFilter(otbrLogLevel, aFormat, ap);
630     va_end(ap);
631 }
632 
otPlatLogHandleLevelChanged(otLogLevel aLogLevel)633 extern "C" void otPlatLogHandleLevelChanged(otLogLevel aLogLevel)
634 {
635     otbrLogSetLevel(RcpHost::ConvertToOtbrLogLevel(aLogLevel));
636     otbrLogInfo("OpenThread log level changed to %d", aLogLevel);
637 }
638 
639 } // namespace Ncp
640 } // namespace otbr
641