1 /*
2  *  Copyright (c) 2016-2017, 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 (FTD only).
32  */
33 
34 #include "openthread-core-config.h"
35 
36 #if OPENTHREAD_FTD
37 
38 #include <openthread/thread_ftd.h>
39 
40 #include "common/as_core_type.hpp"
41 #include "common/locator_getters.hpp"
42 
43 using namespace ot;
44 
otThreadGetMaxAllowedChildren(otInstance * aInstance)45 uint16_t otThreadGetMaxAllowedChildren(otInstance *aInstance)
46 {
47     return AsCoreType(aInstance).Get<ChildTable>().GetMaxChildrenAllowed();
48 }
49 
otThreadSetMaxAllowedChildren(otInstance * aInstance,uint16_t aMaxChildren)50 otError otThreadSetMaxAllowedChildren(otInstance *aInstance, uint16_t aMaxChildren)
51 {
52     return AsCoreType(aInstance).Get<ChildTable>().SetMaxChildrenAllowed(aMaxChildren);
53 }
54 
otThreadGetMaxChildIpAddresses(otInstance * aInstance)55 uint8_t otThreadGetMaxChildIpAddresses(otInstance *aInstance)
56 {
57     return AsCoreType(aInstance).Get<Mle::MleRouter>().GetMaxChildIpAddresses();
58 }
59 
60 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
otThreadSetMaxChildIpAddresses(otInstance * aInstance,uint8_t aMaxIpAddresses)61 otError otThreadSetMaxChildIpAddresses(otInstance *aInstance, uint8_t aMaxIpAddresses)
62 {
63     return AsCoreType(aInstance).Get<Mle::MleRouter>().SetMaxChildIpAddresses(aMaxIpAddresses);
64 }
65 #endif
66 
otThreadIsRouterEligible(otInstance * aInstance)67 bool otThreadIsRouterEligible(otInstance *aInstance)
68 {
69     return AsCoreType(aInstance).Get<Mle::MleRouter>().IsRouterEligible();
70 }
71 
otThreadSetRouterEligible(otInstance * aInstance,bool aEligible)72 otError otThreadSetRouterEligible(otInstance *aInstance, bool aEligible)
73 {
74     return AsCoreType(aInstance).Get<Mle::MleRouter>().SetRouterEligible(aEligible);
75 }
76 
otThreadSetPreferredRouterId(otInstance * aInstance,uint8_t aRouterId)77 otError otThreadSetPreferredRouterId(otInstance *aInstance, uint8_t aRouterId)
78 {
79     return AsCoreType(aInstance).Get<Mle::MleRouter>().SetPreferredRouterId(aRouterId);
80 }
81 
82 #if OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE
otThreadGetDeviceProperties(otInstance * aInstance)83 const otDeviceProperties *otThreadGetDeviceProperties(otInstance *aInstance)
84 {
85     return &AsCoreType(aInstance).Get<Mle::MleRouter>().GetDeviceProperties();
86 }
87 
otThreadSetDeviceProperties(otInstance * aInstance,const otDeviceProperties * aDeviceProperties)88 void otThreadSetDeviceProperties(otInstance *aInstance, const otDeviceProperties *aDeviceProperties)
89 {
90     AsCoreType(aInstance).Get<Mle::MleRouter>().SetDeviceProperties(AsCoreType(aDeviceProperties));
91 }
92 #endif
93 
otThreadGetLocalLeaderWeight(otInstance * aInstance)94 uint8_t otThreadGetLocalLeaderWeight(otInstance *aInstance)
95 {
96     return AsCoreType(aInstance).Get<Mle::MleRouter>().GetLeaderWeight();
97 }
98 
otThreadSetLocalLeaderWeight(otInstance * aInstance,uint8_t aWeight)99 void otThreadSetLocalLeaderWeight(otInstance *aInstance, uint8_t aWeight)
100 {
101     AsCoreType(aInstance).Get<Mle::MleRouter>().SetLeaderWeight(aWeight);
102 }
103 
104 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
otThreadGetPreferredLeaderPartitionId(otInstance * aInstance)105 uint32_t otThreadGetPreferredLeaderPartitionId(otInstance *aInstance)
106 {
107     return AsCoreType(aInstance).Get<Mle::MleRouter>().GetPreferredLeaderPartitionId();
108 }
109 
otThreadSetPreferredLeaderPartitionId(otInstance * aInstance,uint32_t aPartitionId)110 void otThreadSetPreferredLeaderPartitionId(otInstance *aInstance, uint32_t aPartitionId)
111 {
112     AsCoreType(aInstance).Get<Mle::MleRouter>().SetPreferredLeaderPartitionId(aPartitionId);
113 }
114 #endif
115 
otThreadGetJoinerUdpPort(otInstance * aInstance)116 uint16_t otThreadGetJoinerUdpPort(otInstance *aInstance)
117 {
118     return AsCoreType(aInstance).Get<MeshCoP::JoinerRouter>().GetJoinerUdpPort();
119 }
120 
otThreadSetJoinerUdpPort(otInstance * aInstance,uint16_t aJoinerUdpPort)121 otError otThreadSetJoinerUdpPort(otInstance *aInstance, uint16_t aJoinerUdpPort)
122 {
123     AsCoreType(aInstance).Get<MeshCoP::JoinerRouter>().SetJoinerUdpPort(aJoinerUdpPort);
124 
125     return kErrorNone;
126 }
127 
otThreadGetContextIdReuseDelay(otInstance * aInstance)128 uint32_t otThreadGetContextIdReuseDelay(otInstance *aInstance)
129 {
130     return AsCoreType(aInstance).Get<NetworkData::Leader>().GetContextIdReuseDelay();
131 }
132 
otThreadSetContextIdReuseDelay(otInstance * aInstance,uint32_t aDelay)133 void otThreadSetContextIdReuseDelay(otInstance *aInstance, uint32_t aDelay)
134 {
135     AsCoreType(aInstance).Get<NetworkData::Leader>().SetContextIdReuseDelay(aDelay);
136 }
137 
otThreadGetNetworkIdTimeout(otInstance * aInstance)138 uint8_t otThreadGetNetworkIdTimeout(otInstance *aInstance)
139 {
140     return AsCoreType(aInstance).Get<Mle::MleRouter>().GetNetworkIdTimeout();
141 }
142 
otThreadSetNetworkIdTimeout(otInstance * aInstance,uint8_t aTimeout)143 void otThreadSetNetworkIdTimeout(otInstance *aInstance, uint8_t aTimeout)
144 {
145     AsCoreType(aInstance).Get<Mle::MleRouter>().SetNetworkIdTimeout(aTimeout);
146 }
147 
otThreadGetRouterUpgradeThreshold(otInstance * aInstance)148 uint8_t otThreadGetRouterUpgradeThreshold(otInstance *aInstance)
149 {
150     return AsCoreType(aInstance).Get<Mle::MleRouter>().GetRouterUpgradeThreshold();
151 }
152 
otThreadSetRouterUpgradeThreshold(otInstance * aInstance,uint8_t aThreshold)153 void otThreadSetRouterUpgradeThreshold(otInstance *aInstance, uint8_t aThreshold)
154 {
155     AsCoreType(aInstance).Get<Mle::MleRouter>().SetRouterUpgradeThreshold(aThreshold);
156 }
157 
otThreadGetChildRouterLinks(otInstance * aInstance)158 uint8_t otThreadGetChildRouterLinks(otInstance *aInstance)
159 {
160     return AsCoreType(aInstance).Get<Mle::MleRouter>().GetChildRouterLinks();
161 }
162 
otThreadSetChildRouterLinks(otInstance * aInstance,uint8_t aChildRouterLinks)163 otError otThreadSetChildRouterLinks(otInstance *aInstance, uint8_t aChildRouterLinks)
164 {
165     return AsCoreType(aInstance).Get<Mle::MleRouter>().SetChildRouterLinks(aChildRouterLinks);
166 }
167 
otThreadReleaseRouterId(otInstance * aInstance,uint8_t aRouterId)168 otError otThreadReleaseRouterId(otInstance *aInstance, uint8_t aRouterId)
169 {
170     Error error = kErrorNone;
171 
172     VerifyOrExit(aRouterId <= Mle::kMaxRouterId, error = kErrorInvalidArgs);
173 
174     error = AsCoreType(aInstance).Get<RouterTable>().Release(aRouterId);
175 
176 exit:
177     return error;
178 }
179 
otThreadBecomeRouter(otInstance * aInstance)180 otError otThreadBecomeRouter(otInstance *aInstance)
181 {
182     Error error = kErrorInvalidState;
183 
184     switch (AsCoreType(aInstance).Get<Mle::MleRouter>().GetRole())
185     {
186     case Mle::kRoleDisabled:
187     case Mle::kRoleDetached:
188         break;
189 
190     case Mle::kRoleChild:
191         error = AsCoreType(aInstance).Get<Mle::MleRouter>().BecomeRouter(ThreadStatusTlv::kHaveChildIdRequest);
192         break;
193 
194     case Mle::kRoleRouter:
195     case Mle::kRoleLeader:
196         error = kErrorNone;
197         break;
198     }
199 
200     return error;
201 }
202 
otThreadBecomeLeader(otInstance * aInstance)203 otError otThreadBecomeLeader(otInstance *aInstance)
204 {
205     return AsCoreType(aInstance).Get<Mle::MleRouter>().BecomeLeader(/* aCheckWeight */ true);
206 }
207 
otThreadGetRouterDowngradeThreshold(otInstance * aInstance)208 uint8_t otThreadGetRouterDowngradeThreshold(otInstance *aInstance)
209 {
210     return AsCoreType(aInstance).Get<Mle::MleRouter>().GetRouterDowngradeThreshold();
211 }
212 
otThreadSetRouterDowngradeThreshold(otInstance * aInstance,uint8_t aThreshold)213 void otThreadSetRouterDowngradeThreshold(otInstance *aInstance, uint8_t aThreshold)
214 {
215     AsCoreType(aInstance).Get<Mle::MleRouter>().SetRouterDowngradeThreshold(aThreshold);
216 }
217 
otThreadGetRouterSelectionJitter(otInstance * aInstance)218 uint8_t otThreadGetRouterSelectionJitter(otInstance *aInstance)
219 {
220     return AsCoreType(aInstance).Get<Mle::MleRouter>().GetRouterSelectionJitter();
221 }
222 
otThreadSetRouterSelectionJitter(otInstance * aInstance,uint8_t aRouterJitter)223 void otThreadSetRouterSelectionJitter(otInstance *aInstance, uint8_t aRouterJitter)
224 {
225     AsCoreType(aInstance).Get<Mle::MleRouter>().SetRouterSelectionJitter(aRouterJitter);
226 }
227 
otThreadGetChildInfoById(otInstance * aInstance,uint16_t aChildId,otChildInfo * aChildInfo)228 otError otThreadGetChildInfoById(otInstance *aInstance, uint16_t aChildId, otChildInfo *aChildInfo)
229 {
230     return AsCoreType(aInstance).Get<ChildTable>().GetChildInfoById(aChildId, AsCoreType(aChildInfo));
231 }
232 
otThreadGetChildInfoByIndex(otInstance * aInstance,uint16_t aChildIndex,otChildInfo * aChildInfo)233 otError otThreadGetChildInfoByIndex(otInstance *aInstance, uint16_t aChildIndex, otChildInfo *aChildInfo)
234 {
235     return AsCoreType(aInstance).Get<ChildTable>().GetChildInfoByIndex(aChildIndex, AsCoreType(aChildInfo));
236 }
237 
otThreadGetChildNextIp6Address(otInstance * aInstance,uint16_t aChildIndex,otChildIp6AddressIterator * aIterator,otIp6Address * aAddress)238 otError otThreadGetChildNextIp6Address(otInstance                *aInstance,
239                                        uint16_t                   aChildIndex,
240                                        otChildIp6AddressIterator *aIterator,
241                                        otIp6Address              *aAddress)
242 {
243     Error        error = kErrorNone;
244     const Child *child;
245 
246     AssertPointerIsNotNull(aIterator);
247     AssertPointerIsNotNull(aAddress);
248 
249     child = AsCoreType(aInstance).Get<ChildTable>().GetChildAtIndex(aChildIndex);
250     VerifyOrExit(child != nullptr, error = kErrorInvalidArgs);
251     VerifyOrExit(child->IsStateValidOrRestoring(), error = kErrorInvalidArgs);
252 
253     error = child->GetNextIp6Address(*aIterator, AsCoreType(aAddress));
254 
255 exit:
256     return error;
257 }
258 
otThreadGetRouterIdSequence(otInstance * aInstance)259 uint8_t otThreadGetRouterIdSequence(otInstance *aInstance)
260 {
261     return AsCoreType(aInstance).Get<RouterTable>().GetRouterIdSequence();
262 }
263 
otThreadGetMaxRouterId(otInstance * aInstance)264 uint8_t otThreadGetMaxRouterId(otInstance *aInstance)
265 {
266     OT_UNUSED_VARIABLE(aInstance);
267     return Mle::kMaxRouterId;
268 }
269 
otThreadGetRouterInfo(otInstance * aInstance,uint16_t aRouterId,otRouterInfo * aRouterInfo)270 otError otThreadGetRouterInfo(otInstance *aInstance, uint16_t aRouterId, otRouterInfo *aRouterInfo)
271 {
272     return AsCoreType(aInstance).Get<RouterTable>().GetRouterInfo(aRouterId, AsCoreType(aRouterInfo));
273 }
274 
otThreadGetNextCacheEntry(otInstance * aInstance,otCacheEntryInfo * aEntryInfo,otCacheEntryIterator * aIterator)275 otError otThreadGetNextCacheEntry(otInstance *aInstance, otCacheEntryInfo *aEntryInfo, otCacheEntryIterator *aIterator)
276 {
277     return AsCoreType(aInstance).Get<AddressResolver>().GetNextCacheEntry(AsCoreType(aEntryInfo),
278                                                                           AsCoreType(aIterator));
279 }
280 
281 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
otThreadSetSteeringData(otInstance * aInstance,const otExtAddress * aExtAddress)282 void otThreadSetSteeringData(otInstance *aInstance, const otExtAddress *aExtAddress)
283 {
284     AsCoreType(aInstance).Get<Mle::MleRouter>().SetSteeringData(AsCoreTypePtr(aExtAddress));
285 }
286 #endif
287 
otThreadGetPskc(otInstance * aInstance,otPskc * aPskc)288 void otThreadGetPskc(otInstance *aInstance, otPskc *aPskc)
289 {
290     AsCoreType(aInstance).Get<KeyManager>().GetPskc(AsCoreType(aPskc));
291 }
292 
293 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
otThreadGetPskcRef(otInstance * aInstance)294 otPskcRef otThreadGetPskcRef(otInstance *aInstance) { return AsCoreType(aInstance).Get<KeyManager>().GetPskcRef(); }
295 #endif
296 
otThreadSetPskc(otInstance * aInstance,const otPskc * aPskc)297 otError otThreadSetPskc(otInstance *aInstance, const otPskc *aPskc)
298 {
299     Error error = kErrorNone;
300 
301     VerifyOrExit(AsCoreType(aInstance).Get<Mle::MleRouter>().IsDisabled(), error = kErrorInvalidState);
302 
303     AsCoreType(aInstance).Get<KeyManager>().SetPskc(AsCoreType(aPskc));
304     AsCoreType(aInstance).Get<MeshCoP::ActiveDatasetManager>().Clear();
305     AsCoreType(aInstance).Get<MeshCoP::PendingDatasetManager>().Clear();
306 
307 exit:
308     return error;
309 }
310 
311 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
otThreadSetPskcRef(otInstance * aInstance,otPskcRef aKeyRef)312 otError otThreadSetPskcRef(otInstance *aInstance, otPskcRef aKeyRef)
313 {
314     Error     error    = kErrorNone;
315     Instance &instance = AsCoreType(aInstance);
316 
317     VerifyOrExit(aKeyRef != 0, error = kErrorInvalidArgs);
318     VerifyOrExit(instance.Get<Mle::MleRouter>().IsDisabled(), error = kErrorInvalidState);
319 
320     instance.Get<KeyManager>().SetPskcRef(aKeyRef);
321     instance.Get<MeshCoP::ActiveDatasetManager>().Clear();
322     instance.Get<MeshCoP::PendingDatasetManager>().Clear();
323 
324 exit:
325     return error;
326 }
327 #endif
328 
otThreadGetParentPriority(otInstance * aInstance)329 int8_t otThreadGetParentPriority(otInstance *aInstance)
330 {
331     return AsCoreType(aInstance).Get<Mle::MleRouter>().GetAssignParentPriority();
332 }
333 
otThreadSetParentPriority(otInstance * aInstance,int8_t aParentPriority)334 otError otThreadSetParentPriority(otInstance *aInstance, int8_t aParentPriority)
335 {
336     return AsCoreType(aInstance).Get<Mle::MleRouter>().SetAssignParentPriority(aParentPriority);
337 }
338 
otThreadRegisterNeighborTableCallback(otInstance * aInstance,otNeighborTableCallback aCallback)339 void otThreadRegisterNeighborTableCallback(otInstance *aInstance, otNeighborTableCallback aCallback)
340 {
341     AsCoreType(aInstance).Get<NeighborTable>().RegisterCallback(aCallback);
342 }
343 
otThreadSetDiscoveryRequestCallback(otInstance * aInstance,otThreadDiscoveryRequestCallback aCallback,void * aContext)344 void otThreadSetDiscoveryRequestCallback(otInstance                      *aInstance,
345                                          otThreadDiscoveryRequestCallback aCallback,
346                                          void                            *aContext)
347 {
348     AsCoreType(aInstance).Get<Mle::MleRouter>().SetDiscoveryRequestCallback(aCallback, aContext);
349 }
350 
351 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
352 
otThreadSendAddressNotification(otInstance * aInstance,otIp6Address * aDestination,otIp6Address * aTarget,otIp6InterfaceIdentifier * aMlIid)353 void otThreadSendAddressNotification(otInstance               *aInstance,
354                                      otIp6Address             *aDestination,
355                                      otIp6Address             *aTarget,
356                                      otIp6InterfaceIdentifier *aMlIid)
357 {
358     AsCoreType(aInstance).Get<AddressResolver>().SendAddressQueryResponse(AsCoreType(aTarget), AsCoreType(aMlIid),
359                                                                           nullptr, AsCoreType(aDestination));
360 }
361 
362 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
otThreadSendProactiveBackboneNotification(otInstance * aInstance,otIp6Address * aTarget,otIp6InterfaceIdentifier * aMlIid,uint32_t aTimeSinceLastTransaction)363 otError otThreadSendProactiveBackboneNotification(otInstance               *aInstance,
364                                                   otIp6Address             *aTarget,
365                                                   otIp6InterfaceIdentifier *aMlIid,
366                                                   uint32_t                  aTimeSinceLastTransaction)
367 {
368     return AsCoreType(aInstance).Get<BackboneRouter::Manager>().SendProactiveBackboneNotification(
369         AsCoreType(aTarget), AsCoreType(aMlIid), aTimeSinceLastTransaction);
370 }
371 #endif
372 
otThreadSetCcmEnabled(otInstance * aInstance,bool aEnabled)373 void otThreadSetCcmEnabled(otInstance *aInstance, bool aEnabled)
374 {
375     AsCoreType(aInstance).Get<Mle::MleRouter>().SetCcmEnabled(aEnabled);
376 }
377 
otThreadSetThreadVersionCheckEnabled(otInstance * aInstance,bool aEnabled)378 void otThreadSetThreadVersionCheckEnabled(otInstance *aInstance, bool aEnabled)
379 {
380     AsCoreType(aInstance).Get<Mle::MleRouter>().SetThreadVersionCheckEnabled(aEnabled);
381 }
382 
otThreadSetTmfOriginFilterEnabled(otInstance * aInstance,bool aEnabled)383 void otThreadSetTmfOriginFilterEnabled(otInstance *aInstance, bool aEnabled)
384 {
385     AsCoreType(aInstance).Get<Ip6::Ip6>().SetTmfOriginFilterEnabled(aEnabled);
386 }
387 
otThreadIsTmfOriginFilterEnabled(otInstance * aInstance)388 bool otThreadIsTmfOriginFilterEnabled(otInstance *aInstance)
389 {
390     return AsCoreType(aInstance).Get<Ip6::Ip6>().IsTmfOriginFilterEnabled();
391 }
392 
otThreadGetRouterIdRange(otInstance * aInstance,uint8_t * aMinRouterId,uint8_t * aMaxRouterId)393 void otThreadGetRouterIdRange(otInstance *aInstance, uint8_t *aMinRouterId, uint8_t *aMaxRouterId)
394 {
395     AssertPointerIsNotNull(aMinRouterId);
396     AssertPointerIsNotNull(aMaxRouterId);
397 
398     AsCoreType(aInstance).Get<RouterTable>().GetRouterIdRange(*aMinRouterId, *aMaxRouterId);
399 }
400 
otThreadSetRouterIdRange(otInstance * aInstance,uint8_t aMinRouterId,uint8_t aMaxRouterId)401 otError otThreadSetRouterIdRange(otInstance *aInstance, uint8_t aMinRouterId, uint8_t aMaxRouterId)
402 {
403     return AsCoreType(aInstance).Get<RouterTable>().SetRouterIdRange(aMinRouterId, aMaxRouterId);
404 }
405 
otThreadGetAdvertisementTrickleIntervalMax(otInstance * aInstance)406 uint32_t otThreadGetAdvertisementTrickleIntervalMax(otInstance *aInstance)
407 {
408     return AsCoreType(aInstance).Get<Mle::MleRouter>().GetAdvertisementTrickleIntervalMax();
409 }
410 
411 #endif // OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
412 
otThreadIsRouterIdAllocated(otInstance * aInstance,uint8_t aRouterId)413 bool otThreadIsRouterIdAllocated(otInstance *aInstance, uint8_t aRouterId)
414 {
415     return AsCoreType(aInstance).Get<RouterTable>().IsAllocated(aRouterId);
416 }
417 
otThreadGetNextHopAndPathCost(otInstance * aInstance,uint16_t aDestRloc16,uint16_t * aNextHopRloc16,uint8_t * aPathCost)418 void otThreadGetNextHopAndPathCost(otInstance *aInstance,
419                                    uint16_t    aDestRloc16,
420                                    uint16_t   *aNextHopRloc16,
421                                    uint8_t    *aPathCost)
422 {
423     uint8_t  pathcost;
424     uint16_t nextHopRloc16;
425 
426     AsCoreType(aInstance).Get<RouterTable>().GetNextHopAndPathCost(
427         aDestRloc16, (aNextHopRloc16 != nullptr) ? *aNextHopRloc16 : nextHopRloc16,
428         (aPathCost != nullptr) ? *aPathCost : pathcost);
429 }
430 
431 #endif // OPENTHREAD_FTD
432