1 /*
2 * Copyright (c) 2016, 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 /**
30 * @file
31 * This file implements the OpenThread Thread API (for both FTD and MTD).
32 */
33
34 #include "openthread-core-config.h"
35
36 #if OPENTHREAD_FTD || OPENTHREAD_MTD
37
38 #include <openthread/thread.h>
39
40 #include "common/as_core_type.hpp"
41 #include "common/debug.hpp"
42 #include "common/locator_getters.hpp"
43 #include "common/uptime.hpp"
44 #include "thread/version.hpp"
45
46 using namespace ot;
47
otThreadGetChildTimeout(otInstance * aInstance)48 uint32_t otThreadGetChildTimeout(otInstance *aInstance)
49 {
50 return AsCoreType(aInstance).Get<Mle::MleRouter>().GetTimeout();
51 }
52
otThreadSetChildTimeout(otInstance * aInstance,uint32_t aTimeout)53 void otThreadSetChildTimeout(otInstance *aInstance, uint32_t aTimeout)
54 {
55 AsCoreType(aInstance).Get<Mle::MleRouter>().SetTimeout(aTimeout);
56 }
57
otThreadGetExtendedPanId(otInstance * aInstance)58 const otExtendedPanId *otThreadGetExtendedPanId(otInstance *aInstance)
59 {
60 return &AsCoreType(aInstance).Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId();
61 }
62
otThreadSetExtendedPanId(otInstance * aInstance,const otExtendedPanId * aExtendedPanId)63 otError otThreadSetExtendedPanId(otInstance *aInstance, const otExtendedPanId *aExtendedPanId)
64 {
65 Error error = kErrorNone;
66 Instance &instance = AsCoreType(aInstance);
67 const MeshCoP::ExtendedPanId &extPanId = AsCoreType(aExtendedPanId);
68
69 VerifyOrExit(instance.Get<Mle::MleRouter>().IsDisabled(), error = kErrorInvalidState);
70
71 instance.Get<MeshCoP::ExtendedPanIdManager>().SetExtPanId(extPanId);
72
73 instance.Get<MeshCoP::ActiveDatasetManager>().Clear();
74 instance.Get<MeshCoP::PendingDatasetManager>().Clear();
75
76 exit:
77 return error;
78 }
79
otThreadGetLeaderRloc(otInstance * aInstance,otIp6Address * aLeaderRloc)80 otError otThreadGetLeaderRloc(otInstance *aInstance, otIp6Address *aLeaderRloc)
81 {
82 return AsCoreType(aInstance).Get<Mle::MleRouter>().GetLeaderAddress(AsCoreType(aLeaderRloc));
83 }
84
otThreadGetLinkMode(otInstance * aInstance)85 otLinkModeConfig otThreadGetLinkMode(otInstance *aInstance)
86 {
87 otLinkModeConfig config;
88
89 AsCoreType(aInstance).Get<Mle::MleRouter>().GetDeviceMode().Get(config);
90
91 return config;
92 }
93
otThreadSetLinkMode(otInstance * aInstance,otLinkModeConfig aConfig)94 otError otThreadSetLinkMode(otInstance *aInstance, otLinkModeConfig aConfig)
95 {
96 return AsCoreType(aInstance).Get<Mle::MleRouter>().SetDeviceMode(Mle::DeviceMode(aConfig));
97 }
98
otThreadGetNetworkKey(otInstance * aInstance,otNetworkKey * aNetworkKey)99 void otThreadGetNetworkKey(otInstance *aInstance, otNetworkKey *aNetworkKey)
100 {
101 AsCoreType(aInstance).Get<KeyManager>().GetNetworkKey(AsCoreType(aNetworkKey));
102 }
103
104 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
otThreadGetNetworkKeyRef(otInstance * aInstance)105 otNetworkKeyRef otThreadGetNetworkKeyRef(otInstance *aInstance)
106 {
107 return AsCoreType(aInstance).Get<KeyManager>().GetNetworkKeyRef();
108 }
109 #endif
110
otThreadSetNetworkKey(otInstance * aInstance,const otNetworkKey * aKey)111 otError otThreadSetNetworkKey(otInstance *aInstance, const otNetworkKey *aKey)
112 {
113 Error error = kErrorNone;
114 Instance &instance = AsCoreType(aInstance);
115
116 VerifyOrExit(instance.Get<Mle::MleRouter>().IsDisabled(), error = kErrorInvalidState);
117
118 instance.Get<KeyManager>().SetNetworkKey(AsCoreType(aKey));
119
120 instance.Get<MeshCoP::ActiveDatasetManager>().Clear();
121 instance.Get<MeshCoP::PendingDatasetManager>().Clear();
122
123 exit:
124 return error;
125 }
126
127 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
otThreadSetNetworkKeyRef(otInstance * aInstance,otNetworkKeyRef aKeyRef)128 otError otThreadSetNetworkKeyRef(otInstance *aInstance, otNetworkKeyRef aKeyRef)
129 {
130 Error error = kErrorNone;
131 Instance &instance = AsCoreType(aInstance);
132
133 VerifyOrExit(aKeyRef != 0, error = kErrorInvalidArgs);
134
135 VerifyOrExit(instance.Get<Mle::MleRouter>().IsDisabled(), error = kErrorInvalidState);
136
137 instance.Get<KeyManager>().SetNetworkKeyRef((aKeyRef));
138 instance.Get<MeshCoP::ActiveDatasetManager>().Clear();
139 instance.Get<MeshCoP::PendingDatasetManager>().Clear();
140
141 exit:
142 return error;
143 }
144 #endif
145
otThreadGetRloc(otInstance * aInstance)146 const otIp6Address *otThreadGetRloc(otInstance *aInstance)
147 {
148 return &AsCoreType(aInstance).Get<Mle::MleRouter>().GetMeshLocal16();
149 }
150
otThreadGetMeshLocalEid(otInstance * aInstance)151 const otIp6Address *otThreadGetMeshLocalEid(otInstance *aInstance)
152 {
153 return &AsCoreType(aInstance).Get<Mle::MleRouter>().GetMeshLocal64();
154 }
155
otThreadGetMeshLocalPrefix(otInstance * aInstance)156 const otMeshLocalPrefix *otThreadGetMeshLocalPrefix(otInstance *aInstance)
157 {
158 return &AsCoreType(aInstance).Get<Mle::MleRouter>().GetMeshLocalPrefix();
159 }
160
otThreadSetMeshLocalPrefix(otInstance * aInstance,const otMeshLocalPrefix * aMeshLocalPrefix)161 otError otThreadSetMeshLocalPrefix(otInstance *aInstance, const otMeshLocalPrefix *aMeshLocalPrefix)
162 {
163 Error error = kErrorNone;
164
165 VerifyOrExit(AsCoreType(aInstance).Get<Mle::MleRouter>().IsDisabled(), error = kErrorInvalidState);
166
167 AsCoreType(aInstance).Get<Mle::MleRouter>().SetMeshLocalPrefix(AsCoreType(aMeshLocalPrefix));
168 AsCoreType(aInstance).Get<MeshCoP::ActiveDatasetManager>().Clear();
169 AsCoreType(aInstance).Get<MeshCoP::PendingDatasetManager>().Clear();
170
171 exit:
172 return error;
173 }
174
otThreadGetLinkLocalIp6Address(otInstance * aInstance)175 const otIp6Address *otThreadGetLinkLocalIp6Address(otInstance *aInstance)
176 {
177 return &AsCoreType(aInstance).Get<Mle::MleRouter>().GetLinkLocalAddress();
178 }
179
otThreadGetLinkLocalAllThreadNodesMulticastAddress(otInstance * aInstance)180 const otIp6Address *otThreadGetLinkLocalAllThreadNodesMulticastAddress(otInstance *aInstance)
181 {
182 return &AsCoreType(aInstance).Get<Mle::MleRouter>().GetLinkLocalAllThreadNodesAddress();
183 }
184
otThreadGetRealmLocalAllThreadNodesMulticastAddress(otInstance * aInstance)185 const otIp6Address *otThreadGetRealmLocalAllThreadNodesMulticastAddress(otInstance *aInstance)
186 {
187 return &AsCoreType(aInstance).Get<Mle::MleRouter>().GetRealmLocalAllThreadNodesAddress();
188 }
189
otThreadGetServiceAloc(otInstance * aInstance,uint8_t aServiceId,otIp6Address * aServiceAloc)190 otError otThreadGetServiceAloc(otInstance *aInstance, uint8_t aServiceId, otIp6Address *aServiceAloc)
191 {
192 return AsCoreType(aInstance).Get<Mle::MleRouter>().GetServiceAloc(aServiceId, AsCoreType(aServiceAloc));
193 }
194
otThreadGetNetworkName(otInstance * aInstance)195 const char *otThreadGetNetworkName(otInstance *aInstance)
196 {
197 return AsCoreType(aInstance).Get<MeshCoP::NetworkNameManager>().GetNetworkName().GetAsCString();
198 }
199
otThreadSetNetworkName(otInstance * aInstance,const char * aNetworkName)200 otError otThreadSetNetworkName(otInstance *aInstance, const char *aNetworkName)
201 {
202 Error error = kErrorNone;
203
204 VerifyOrExit(AsCoreType(aInstance).Get<Mle::MleRouter>().IsDisabled(), error = kErrorInvalidState);
205
206 #if !OPENTHREAD_CONFIG_ALLOW_EMPTY_NETWORK_NAME
207 // Thread interfaces support a zero length name internally for backwards compatibility, but new names
208 // must be at least one valid character long.
209 VerifyOrExit(nullptr != aNetworkName && aNetworkName[0] != '\0', error = kErrorInvalidArgs);
210 #endif
211
212 error = AsCoreType(aInstance).Get<MeshCoP::NetworkNameManager>().SetNetworkName(aNetworkName);
213 AsCoreType(aInstance).Get<MeshCoP::ActiveDatasetManager>().Clear();
214 AsCoreType(aInstance).Get<MeshCoP::PendingDatasetManager>().Clear();
215
216 exit:
217 return error;
218 }
219
220 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
otThreadGetDomainName(otInstance * aInstance)221 const char *otThreadGetDomainName(otInstance *aInstance)
222 {
223 return AsCoreType(aInstance).Get<MeshCoP::NetworkNameManager>().GetDomainName().GetAsCString();
224 }
225
otThreadSetDomainName(otInstance * aInstance,const char * aDomainName)226 otError otThreadSetDomainName(otInstance *aInstance, const char *aDomainName)
227 {
228 Error error = kErrorNone;
229
230 VerifyOrExit(AsCoreType(aInstance).Get<Mle::MleRouter>().IsDisabled(), error = kErrorInvalidState);
231
232 error = AsCoreType(aInstance).Get<MeshCoP::NetworkNameManager>().SetDomainName(aDomainName);
233
234 exit:
235 return error;
236 }
237
238 #if OPENTHREAD_CONFIG_DUA_ENABLE
otThreadSetFixedDuaInterfaceIdentifier(otInstance * aInstance,const otIp6InterfaceIdentifier * aIid)239 otError otThreadSetFixedDuaInterfaceIdentifier(otInstance *aInstance, const otIp6InterfaceIdentifier *aIid)
240 {
241 Error error = kErrorNone;
242
243 if (aIid)
244 {
245 error = AsCoreType(aInstance).Get<DuaManager>().SetFixedDuaInterfaceIdentifier(AsCoreType(aIid));
246 }
247 else
248 {
249 AsCoreType(aInstance).Get<DuaManager>().ClearFixedDuaInterfaceIdentifier();
250 }
251
252 return error;
253 }
254
otThreadGetFixedDuaInterfaceIdentifier(otInstance * aInstance)255 const otIp6InterfaceIdentifier *otThreadGetFixedDuaInterfaceIdentifier(otInstance *aInstance)
256 {
257 Instance &instance = AsCoreType(aInstance);
258 const otIp6InterfaceIdentifier *iid = nullptr;
259
260 if (instance.Get<DuaManager>().IsFixedDuaInterfaceIdentifierSet())
261 {
262 iid = &instance.Get<DuaManager>().GetFixedDuaInterfaceIdentifier();
263 }
264
265 return iid;
266 }
267 #endif // OPENTHREAD_CONFIG_DUA_ENABLE
268
269 #endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
270
otThreadGetKeySequenceCounter(otInstance * aInstance)271 uint32_t otThreadGetKeySequenceCounter(otInstance *aInstance)
272 {
273 return AsCoreType(aInstance).Get<KeyManager>().GetCurrentKeySequence();
274 }
275
otThreadSetKeySequenceCounter(otInstance * aInstance,uint32_t aKeySequenceCounter)276 void otThreadSetKeySequenceCounter(otInstance *aInstance, uint32_t aKeySequenceCounter)
277 {
278 AsCoreType(aInstance).Get<KeyManager>().SetCurrentKeySequence(aKeySequenceCounter);
279 }
280
otThreadGetKeySwitchGuardTime(otInstance * aInstance)281 uint32_t otThreadGetKeySwitchGuardTime(otInstance *aInstance)
282 {
283 return AsCoreType(aInstance).Get<KeyManager>().GetKeySwitchGuardTime();
284 }
285
otThreadSetKeySwitchGuardTime(otInstance * aInstance,uint32_t aKeySwitchGuardTime)286 void otThreadSetKeySwitchGuardTime(otInstance *aInstance, uint32_t aKeySwitchGuardTime)
287 {
288 AsCoreType(aInstance).Get<KeyManager>().SetKeySwitchGuardTime(aKeySwitchGuardTime);
289 }
290
otThreadBecomeDetached(otInstance * aInstance)291 otError otThreadBecomeDetached(otInstance *aInstance)
292 {
293 return AsCoreType(aInstance).Get<Mle::MleRouter>().BecomeDetached();
294 }
295
otThreadBecomeChild(otInstance * aInstance)296 otError otThreadBecomeChild(otInstance *aInstance) { return AsCoreType(aInstance).Get<Mle::MleRouter>().BecomeChild(); }
297
otThreadGetNextNeighborInfo(otInstance * aInstance,otNeighborInfoIterator * aIterator,otNeighborInfo * aInfo)298 otError otThreadGetNextNeighborInfo(otInstance *aInstance, otNeighborInfoIterator *aIterator, otNeighborInfo *aInfo)
299 {
300 AssertPointerIsNotNull(aIterator);
301
302 return AsCoreType(aInstance).Get<NeighborTable>().GetNextNeighborInfo(*aIterator, AsCoreType(aInfo));
303 }
304
otThreadGetDeviceRole(otInstance * aInstance)305 otDeviceRole otThreadGetDeviceRole(otInstance *aInstance)
306 {
307 return MapEnum(AsCoreType(aInstance).Get<Mle::MleRouter>().GetRole());
308 }
309
otThreadDeviceRoleToString(otDeviceRole aRole)310 const char *otThreadDeviceRoleToString(otDeviceRole aRole) { return Mle::RoleToString(MapEnum(aRole)); }
311
otThreadGetLeaderData(otInstance * aInstance,otLeaderData * aLeaderData)312 otError otThreadGetLeaderData(otInstance *aInstance, otLeaderData *aLeaderData)
313 {
314 Error error = kErrorNone;
315
316 AssertPointerIsNotNull(aLeaderData);
317
318 VerifyOrExit(AsCoreType(aInstance).Get<Mle::MleRouter>().IsAttached(), error = kErrorDetached);
319 *aLeaderData = AsCoreType(aInstance).Get<Mle::MleRouter>().GetLeaderData();
320
321 exit:
322 return error;
323 }
324
otThreadGetLeaderRouterId(otInstance * aInstance)325 uint8_t otThreadGetLeaderRouterId(otInstance *aInstance)
326 {
327 return AsCoreType(aInstance).Get<Mle::MleRouter>().GetLeaderId();
328 }
329
otThreadGetLeaderWeight(otInstance * aInstance)330 uint8_t otThreadGetLeaderWeight(otInstance *aInstance)
331 {
332 return AsCoreType(aInstance).Get<Mle::MleRouter>().GetLeaderData().GetWeighting();
333 }
334
otThreadGetPartitionId(otInstance * aInstance)335 uint32_t otThreadGetPartitionId(otInstance *aInstance)
336 {
337 return AsCoreType(aInstance).Get<Mle::MleRouter>().GetLeaderData().GetPartitionId();
338 }
339
otThreadGetRloc16(otInstance * aInstance)340 uint16_t otThreadGetRloc16(otInstance *aInstance) { return AsCoreType(aInstance).Get<Mle::MleRouter>().GetRloc16(); }
341
otThreadGetParentInfo(otInstance * aInstance,otRouterInfo * aParentInfo)342 otError otThreadGetParentInfo(otInstance *aInstance, otRouterInfo *aParentInfo)
343 {
344 return AsCoreType(aInstance).Get<Mle::Mle>().GetParentInfo(AsCoreType(aParentInfo));
345 }
346
otThreadGetParentAverageRssi(otInstance * aInstance,int8_t * aParentRssi)347 otError otThreadGetParentAverageRssi(otInstance *aInstance, int8_t *aParentRssi)
348 {
349 Error error = kErrorNone;
350
351 AssertPointerIsNotNull(aParentRssi);
352
353 *aParentRssi = AsCoreType(aInstance).Get<Mle::MleRouter>().GetParent().GetLinkInfo().GetAverageRss();
354
355 VerifyOrExit(*aParentRssi != Radio::kInvalidRssi, error = kErrorFailed);
356
357 exit:
358 return error;
359 }
360
otThreadGetParentLastRssi(otInstance * aInstance,int8_t * aLastRssi)361 otError otThreadGetParentLastRssi(otInstance *aInstance, int8_t *aLastRssi)
362 {
363 Error error = kErrorNone;
364
365 AssertPointerIsNotNull(aLastRssi);
366
367 *aLastRssi = AsCoreType(aInstance).Get<Mle::MleRouter>().GetParent().GetLinkInfo().GetLastRss();
368
369 VerifyOrExit(*aLastRssi != Radio::kInvalidRssi, error = kErrorFailed);
370
371 exit:
372 return error;
373 }
374
otThreadSearchForBetterParent(otInstance * aInstance)375 otError otThreadSearchForBetterParent(otInstance *aInstance)
376 {
377 return AsCoreType(aInstance).Get<Mle::Mle>().SearchForBetterParent();
378 }
379
otThreadSetEnabled(otInstance * aInstance,bool aEnabled)380 otError otThreadSetEnabled(otInstance *aInstance, bool aEnabled)
381 {
382 Error error = kErrorNone;
383
384 if (aEnabled)
385 {
386 error = AsCoreType(aInstance).Get<Mle::MleRouter>().Start();
387 }
388 else
389 {
390 AsCoreType(aInstance).Get<Mle::MleRouter>().Stop();
391 }
392
393 return error;
394 }
395
otThreadGetVersion(void)396 uint16_t otThreadGetVersion(void) { return kThreadVersion; }
397
otThreadIsSingleton(otInstance * aInstance)398 bool otThreadIsSingleton(otInstance *aInstance) { return AsCoreType(aInstance).Get<Mle::MleRouter>().IsSingleton(); }
399
otThreadDiscover(otInstance * aInstance,uint32_t aScanChannels,uint16_t aPanId,bool aJoiner,bool aEnableEui64Filtering,otHandleActiveScanResult aCallback,void * aCallbackContext)400 otError otThreadDiscover(otInstance *aInstance,
401 uint32_t aScanChannels,
402 uint16_t aPanId,
403 bool aJoiner,
404 bool aEnableEui64Filtering,
405 otHandleActiveScanResult aCallback,
406 void *aCallbackContext)
407 {
408 return AsCoreType(aInstance).Get<Mle::DiscoverScanner>().Discover(
409 Mac::ChannelMask(aScanChannels), aPanId, aJoiner, aEnableEui64Filtering,
410 /* aFilterIndexes (use hash of factory EUI64) */ nullptr, aCallback, aCallbackContext);
411 }
412
otThreadSetJoinerAdvertisement(otInstance * aInstance,uint32_t aOui,const uint8_t * aAdvData,uint8_t aAdvDataLength)413 otError otThreadSetJoinerAdvertisement(otInstance *aInstance,
414 uint32_t aOui,
415 const uint8_t *aAdvData,
416 uint8_t aAdvDataLength)
417 {
418 return AsCoreType(aInstance).Get<Mle::DiscoverScanner>().SetJoinerAdvertisement(aOui, aAdvData, aAdvDataLength);
419 }
420
otThreadIsDiscoverInProgress(otInstance * aInstance)421 bool otThreadIsDiscoverInProgress(otInstance *aInstance)
422 {
423 return AsCoreType(aInstance).Get<Mle::DiscoverScanner>().IsInProgress();
424 }
425
otThreadGetIp6Counters(otInstance * aInstance)426 const otIpCounters *otThreadGetIp6Counters(otInstance *aInstance)
427 {
428 return &AsCoreType(aInstance).Get<MeshForwarder>().GetCounters();
429 }
430
otThreadResetIp6Counters(otInstance * aInstance)431 void otThreadResetIp6Counters(otInstance *aInstance) { AsCoreType(aInstance).Get<MeshForwarder>().ResetCounters(); }
432
otThreadGetMleCounters(otInstance * aInstance)433 const otMleCounters *otThreadGetMleCounters(otInstance *aInstance)
434 {
435 return &AsCoreType(aInstance).Get<Mle::MleRouter>().GetCounters();
436 }
437
otThreadResetMleCounters(otInstance * aInstance)438 void otThreadResetMleCounters(otInstance *aInstance) { AsCoreType(aInstance).Get<Mle::MleRouter>().ResetCounters(); }
439
440 #if OPENTHREAD_CONFIG_MLE_PARENT_RESPONSE_CALLBACK_API_ENABLE
otThreadRegisterParentResponseCallback(otInstance * aInstance,otThreadParentResponseCallback aCallback,void * aContext)441 void otThreadRegisterParentResponseCallback(otInstance *aInstance,
442 otThreadParentResponseCallback aCallback,
443 void *aContext)
444 {
445 AsCoreType(aInstance).Get<Mle::MleRouter>().RegisterParentResponseStatsCallback(aCallback, aContext);
446 }
447 #endif
448
449 #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE
otThreadLocateAnycastDestination(otInstance * aInstance,const otIp6Address * aAnycastAddress,otThreadAnycastLocatorCallback aCallback,void * aContext)450 otError otThreadLocateAnycastDestination(otInstance *aInstance,
451 const otIp6Address *aAnycastAddress,
452 otThreadAnycastLocatorCallback aCallback,
453 void *aContext)
454 {
455 return AsCoreType(aInstance).Get<AnycastLocator>().Locate(AsCoreType(aAnycastAddress), aCallback, aContext);
456 }
457
otThreadIsAnycastLocateInProgress(otInstance * aInstance)458 bool otThreadIsAnycastLocateInProgress(otInstance *aInstance)
459 {
460 return AsCoreType(aInstance).Get<AnycastLocator>().IsInProgress();
461 }
462 #endif
463
otThreadDetachGracefully(otInstance * aInstance,otDetachGracefullyCallback aCallback,void * aContext)464 otError otThreadDetachGracefully(otInstance *aInstance, otDetachGracefullyCallback aCallback, void *aContext)
465 {
466 return AsCoreType(aInstance).Get<Mle::MleRouter>().DetachGracefully(aCallback, aContext);
467 }
468
469 #endif // OPENTHREAD_FTD || OPENTHREAD_MTD
470
471 #if OPENTHREAD_CONFIG_UPTIME_ENABLE
otConvertDurationInSecondsToString(uint32_t aDuration,char * aBuffer,uint16_t aSize)472 void otConvertDurationInSecondsToString(uint32_t aDuration, char *aBuffer, uint16_t aSize)
473 {
474 StringWriter writer(aBuffer, aSize);
475
476 Uptime::UptimeToString(Uptime::SecToMsec(aDuration), writer, /* aIncludeMsec */ false);
477 }
478 #endif
479