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" AND
17  *    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  *    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  *    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20  *    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  *    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  *    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  *    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  *    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 /**
29  * @file
30  *   This file implements full thread device specified Spinel interface to the OpenThread stack.
31  */
32 
33 #include "ncp_base.hpp"
34 #include <openthread/config.h>
35 
36 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
37 #include <openthread/backbone_router_ftd.h>
38 #endif
39 #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE
40 #include <openthread/channel_manager.h>
41 #endif
42 #include <openthread/child_supervision.h>
43 #include <openthread/dataset.h>
44 #include <openthread/dataset_ftd.h>
45 #include <openthread/diag.h>
46 #include <openthread/icmp6.h>
47 #include <openthread/ncp.h>
48 #include <openthread/thread_ftd.h>
49 #include <openthread/platform/misc.h>
50 
51 #include "common/code_utils.hpp"
52 #include "common/debug.hpp"
53 #include "common/instance.hpp"
54 #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
55 #include "meshcop/commissioner.hpp"
56 #endif
57 
58 #if OPENTHREAD_FTD
59 namespace ot {
60 namespace Ncp {
61 
EncodeChildInfo(const otChildInfo & aChildInfo)62 otError NcpBase::EncodeChildInfo(const otChildInfo &aChildInfo)
63 {
64     otError error = OT_ERROR_NONE;
65     uint8_t modeFlags;
66 
67     modeFlags =
68         LinkFlagsToFlagByte(aChildInfo.mRxOnWhenIdle, aChildInfo.mFullThreadDevice, aChildInfo.mFullNetworkData);
69 
70     SuccessOrExit(error = mEncoder.WriteEui64(aChildInfo.mExtAddress));
71     SuccessOrExit(error = mEncoder.WriteUint16(aChildInfo.mRloc16));
72     SuccessOrExit(error = mEncoder.WriteUint32(aChildInfo.mTimeout));
73     SuccessOrExit(error = mEncoder.WriteUint32(aChildInfo.mAge));
74     SuccessOrExit(error = mEncoder.WriteUint8(aChildInfo.mNetworkDataVersion));
75     SuccessOrExit(error = mEncoder.WriteUint8(aChildInfo.mLinkQualityIn));
76     SuccessOrExit(error = mEncoder.WriteInt8(aChildInfo.mAverageRssi));
77     SuccessOrExit(error = mEncoder.WriteUint8(modeFlags));
78     SuccessOrExit(error = mEncoder.WriteInt8(aChildInfo.mLastRssi));
79 
80 exit:
81     return error;
82 }
83 
84 // ----------------------------------------------------------------------------
85 // MARK: Property/Status Changed
86 // ----------------------------------------------------------------------------
87 
88 #if OPENTHREAD_CONFIG_MLE_PARENT_RESPONSE_CALLBACK_API_ENABLE
HandleParentResponseInfo(otThreadParentResponseInfo * aInfo,void * aContext)89 void NcpBase::HandleParentResponseInfo(otThreadParentResponseInfo *aInfo, void *aContext)
90 {
91     VerifyOrExit(aInfo && aContext);
92 
93     static_cast<NcpBase *>(aContext)->HandleParentResponseInfo(*aInfo);
94 
95 exit:
96     return;
97 }
98 
HandleParentResponseInfo(const otThreadParentResponseInfo & aInfo)99 void NcpBase::HandleParentResponseInfo(const otThreadParentResponseInfo &aInfo)
100 {
101     VerifyOrExit(!mChangedPropsSet.IsPropertyFiltered(SPINEL_PROP_PARENT_RESPONSE_INFO));
102 
103     SuccessOrExit(mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_PROP_VALUE_IS,
104                                       SPINEL_PROP_PARENT_RESPONSE_INFO));
105 
106     SuccessOrExit(mEncoder.WriteEui64(aInfo.mExtAddr));
107     SuccessOrExit(mEncoder.WriteUint16(aInfo.mRloc16));
108     SuccessOrExit(mEncoder.WriteInt8(aInfo.mRssi));
109     SuccessOrExit(mEncoder.WriteInt8(aInfo.mPriority));
110     SuccessOrExit(mEncoder.WriteUint8(aInfo.mLinkQuality3));
111     SuccessOrExit(mEncoder.WriteUint8(aInfo.mLinkQuality2));
112     SuccessOrExit(mEncoder.WriteUint8(aInfo.mLinkQuality1));
113     SuccessOrExit(mEncoder.WriteBool(aInfo.mIsAttached));
114 
115     SuccessOrExit(mEncoder.EndFrame());
116 
117 exit:
118     return;
119 }
120 #endif
121 
HandleNeighborTableChanged(otNeighborTableEvent aEvent,const otNeighborTableEntryInfo * aEntry)122 void NcpBase::HandleNeighborTableChanged(otNeighborTableEvent aEvent, const otNeighborTableEntryInfo *aEntry)
123 {
124     GetNcpInstance()->HandleNeighborTableChanged(aEvent, *aEntry);
125 }
126 
HandleNeighborTableChanged(otNeighborTableEvent aEvent,const otNeighborTableEntryInfo & aEntry)127 void NcpBase::HandleNeighborTableChanged(otNeighborTableEvent aEvent, const otNeighborTableEntryInfo &aEntry)
128 {
129     otError           error   = OT_ERROR_NONE;
130     unsigned int      command = SPINEL_CMD_PROP_VALUE_REMOVED;
131     spinel_prop_key_t property;
132 
133     switch (aEvent)
134     {
135     case OT_NEIGHBOR_TABLE_EVENT_CHILD_ADDED:
136         command = SPINEL_CMD_PROP_VALUE_INSERTED;
137 
138         OT_FALL_THROUGH;
139 
140     case OT_NEIGHBOR_TABLE_EVENT_CHILD_REMOVED:
141         property = SPINEL_PROP_THREAD_CHILD_TABLE;
142         VerifyOrExit(!aEntry.mInfo.mChild.mIsStateRestoring);
143         break;
144 
145     case OT_NEIGHBOR_TABLE_EVENT_ROUTER_ADDED:
146         command = SPINEL_CMD_PROP_VALUE_INSERTED;
147 
148         OT_FALL_THROUGH;
149 
150     case OT_NEIGHBOR_TABLE_EVENT_ROUTER_REMOVED:
151         property = SPINEL_PROP_THREAD_NEIGHBOR_TABLE;
152         break;
153 
154     default:
155         ExitNow();
156     }
157 
158     VerifyOrExit(!mChangedPropsSet.IsPropertyFiltered(property));
159 
160     SuccessOrExit(error = mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, command, property));
161 
162     if (property == SPINEL_PROP_THREAD_CHILD_TABLE)
163     {
164         SuccessOrExit(error = EncodeChildInfo(aEntry.mInfo.mChild));
165     }
166     else
167     {
168         SuccessOrExit(error = EncodeNeighborInfo(aEntry.mInfo.mRouter));
169     }
170 
171     SuccessOrExit(error = mEncoder.EndFrame());
172 
173 exit:
174 
175     // If the frame can not be added (out of NCP buffer space), we remember
176     // to send an async `LAST_STATUS(NOMEM)` when buffer space becomes
177     // available. Also `mShouldEmitChildTableUpdate` flag is set to `true` so
178     // that the entire child table is later emitted as `VALUE_IS` spinel frame
179     // update from `ProcessThreadChangedFlags()`.
180 
181     if (error != OT_ERROR_NONE)
182     {
183         if (property == SPINEL_PROP_THREAD_CHILD_TABLE)
184         {
185             mShouldEmitChildTableUpdate = true;
186         }
187 
188         mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM);
189         mUpdateChangedPropsTask.Post();
190     }
191 }
192 
193 // ----------------------------------------------------------------------------
194 // MARK: Individual Property Handlers
195 // ----------------------------------------------------------------------------
196 
HandlePropertyGet(void)197 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_LOCAL_LEADER_WEIGHT>(void)
198 {
199     return mEncoder.WriteUint8(otThreadGetLocalLeaderWeight(mInstance));
200 }
201 
HandlePropertyGet(void)202 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_LEADER_WEIGHT>(void)
203 {
204     return mEncoder.WriteUint8(otThreadGetLeaderWeight(mInstance));
205 }
206 
HandlePropertyGet(void)207 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_CHILD_TABLE>(void)
208 {
209     otError     error = OT_ERROR_NONE;
210     otChildInfo childInfo;
211     uint16_t    maxChildren;
212 
213     maxChildren = otThreadGetMaxAllowedChildren(mInstance);
214 
215     for (uint16_t index = 0; index < maxChildren; index++)
216     {
217         if ((otThreadGetChildInfoByIndex(mInstance, index, &childInfo) != OT_ERROR_NONE) || childInfo.mIsStateRestoring)
218         {
219             continue;
220         }
221 
222         SuccessOrExit(error = mEncoder.OpenStruct());
223         SuccessOrExit(error = EncodeChildInfo(childInfo));
224         SuccessOrExit(error = mEncoder.CloseStruct());
225     }
226 
227 exit:
228     return error;
229 }
230 
HandlePropertyGet(void)231 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ROUTER_TABLE>(void)
232 {
233     otError      error = OT_ERROR_NONE;
234     otRouterInfo routerInfo;
235     uint8_t      maxRouterId;
236 
237     maxRouterId = otThreadGetMaxRouterId(mInstance);
238 
239     for (uint8_t routerId = 0; routerId <= maxRouterId; routerId++)
240     {
241         if ((otThreadGetRouterInfo(mInstance, routerId, &routerInfo) != OT_ERROR_NONE) || !routerInfo.mAllocated)
242         {
243             continue;
244         }
245 
246         SuccessOrExit(error = mEncoder.OpenStruct());
247 
248         SuccessOrExit(error = mEncoder.WriteEui64(routerInfo.mExtAddress));
249         SuccessOrExit(error = mEncoder.WriteUint16(routerInfo.mRloc16));
250         SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mRouterId));
251         SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mNextHop));
252         SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mPathCost));
253         SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mLinkQualityIn));
254         SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mLinkQualityOut));
255         SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mAge));
256         SuccessOrExit(error = mEncoder.WriteBool(routerInfo.mLinkEstablished));
257 
258         SuccessOrExit(error = mEncoder.CloseStruct());
259     }
260 
261 exit:
262     return error;
263 }
264 
HandlePropertyGet(void)265 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_CHILD_TABLE_ADDRESSES>(void)
266 {
267     otError                   error = OT_ERROR_NONE;
268     otChildInfo               childInfo;
269     uint16_t                  maxChildren;
270     otIp6Address              ip6Address;
271     otChildIp6AddressIterator iterator = OT_CHILD_IP6_ADDRESS_ITERATOR_INIT;
272 
273     maxChildren = otThreadGetMaxAllowedChildren(mInstance);
274 
275     for (uint16_t childIndex = 0; childIndex < maxChildren; childIndex++)
276     {
277         if ((otThreadGetChildInfoByIndex(mInstance, childIndex, &childInfo) != OT_ERROR_NONE) ||
278             childInfo.mIsStateRestoring)
279         {
280             continue;
281         }
282 
283         SuccessOrExit(error = mEncoder.OpenStruct());
284 
285         SuccessOrExit(error = mEncoder.WriteEui64(childInfo.mExtAddress));
286         SuccessOrExit(error = mEncoder.WriteUint16(childInfo.mRloc16));
287 
288         iterator = OT_CHILD_IP6_ADDRESS_ITERATOR_INIT;
289 
290         while (otThreadGetChildNextIp6Address(mInstance, childIndex, &iterator, &ip6Address) == OT_ERROR_NONE)
291         {
292             SuccessOrExit(error = mEncoder.WriteIp6Address(ip6Address));
293         }
294 
295         SuccessOrExit(error = mEncoder.CloseStruct());
296     }
297 
298 exit:
299     return error;
300 }
301 
HandlePropertyGet(void)302 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ROUTER_ROLE_ENABLED>(void)
303 {
304     return mEncoder.WriteBool(otThreadIsRouterEligible(mInstance));
305 }
306 
HandlePropertySet(void)307 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_ROUTER_ROLE_ENABLED>(void)
308 {
309     bool    eligible;
310     otError error = OT_ERROR_NONE;
311 
312     SuccessOrExit(error = mDecoder.ReadBool(eligible));
313 
314     error = otThreadSetRouterEligible(mInstance, eligible);
315 
316 exit:
317     return error;
318 }
319 
HandlePropertyGet(void)320 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_MAX_RETRY_NUMBER_INDIRECT>(void)
321 {
322     return mEncoder.WriteUint8(otLinkGetMaxFrameRetriesIndirect(mInstance));
323 }
324 
HandlePropertySet(void)325 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_MAX_RETRY_NUMBER_INDIRECT>(void)
326 {
327     uint8_t maxFrameRetriesIndirect;
328     otError error = OT_ERROR_NONE;
329 
330     SuccessOrExit(error = mDecoder.ReadUint8(maxFrameRetriesIndirect));
331     otLinkSetMaxFrameRetriesIndirect(mInstance, maxFrameRetriesIndirect);
332 
333 exit:
334     return error;
335 }
336 
337 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
HandlePropertyGet(void)338 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_DOMAIN_NAME>(void)
339 {
340     return mEncoder.WriteUtf8(otThreadGetDomainName(mInstance));
341 }
342 
HandlePropertySet(void)343 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_DOMAIN_NAME>(void)
344 {
345     otError     error = OT_ERROR_NONE;
346     const char *domainName;
347 
348     SuccessOrExit(error = mDecoder.ReadUtf8(domainName));
349 
350     error = otThreadSetDomainName(mInstance, domainName);
351 
352 exit:
353     return error;
354 }
355 #endif
356 
357 #if OPENTHREAD_CONFIG_DUA_ENABLE
HandlePropertyGet(void)358 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_DUA_ID>(void)
359 {
360     const otIp6InterfaceIdentifier *iid   = otThreadGetFixedDuaInterfaceIdentifier(mInstance);
361     otError                         error = OT_ERROR_NONE;
362 
363     if (iid == nullptr)
364     {
365         // send empty response
366     }
367     else
368     {
369         for (uint8_t i : iid->mFields.m8)
370         {
371             SuccessOrExit(error = mEncoder.WriteUint8(i));
372         }
373     }
374 
375 exit:
376     return error;
377 }
378 
HandlePropertySet(void)379 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_DUA_ID>(void)
380 {
381     otError error = OT_ERROR_NONE;
382 
383     if (mDecoder.GetRemainingLength() == 0)
384     {
385         SuccessOrExit(error = otThreadSetFixedDuaInterfaceIdentifier(mInstance, nullptr));
386     }
387     else
388     {
389         otIp6InterfaceIdentifier iid;
390 
391         for (uint8_t &i : iid.mFields.m8)
392         {
393             SuccessOrExit(error = mDecoder.ReadUint8(i));
394         }
395 
396         SuccessOrExit(error = otThreadSetFixedDuaInterfaceIdentifier(mInstance, &iid));
397     }
398 
399 exit:
400     return error;
401 }
402 #endif // OPENTHREAD_CONFIG_DUA_ENABLE
403 
404 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
HandlePropertyGet(void)405 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_STATE>(void)
406 {
407     uint8_t state = SPINEL_THREAD_BACKBONE_ROUTER_STATE_DISABLED;
408 
409     switch (otBackboneRouterGetState(mInstance))
410     {
411     case OT_BACKBONE_ROUTER_STATE_DISABLED:
412         state = SPINEL_THREAD_BACKBONE_ROUTER_STATE_DISABLED;
413         break;
414 
415     case OT_BACKBONE_ROUTER_STATE_SECONDARY:
416         state = SPINEL_THREAD_BACKBONE_ROUTER_STATE_SECONDARY;
417         break;
418 
419     case OT_BACKBONE_ROUTER_STATE_PRIMARY:
420         state = SPINEL_THREAD_BACKBONE_ROUTER_STATE_PRIMARY;
421         break;
422     }
423 
424     return mEncoder.WriteUint8(state);
425 }
426 
HandlePropertySet(void)427 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_STATE>(void)
428 {
429     uint8_t state;
430     otError error = OT_ERROR_NONE;
431 
432     SuccessOrExit(error = mDecoder.ReadUint8(state));
433 
434     if (state)
435     {
436         otBackboneRouterSetEnabled(mInstance, true);
437     }
438     else
439     {
440         otBackboneRouterSetEnabled(mInstance, false);
441     }
442 
443 exit:
444     return error;
445 }
446 
HandlePropertyGet(void)447 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_CONFIG>(void)
448 {
449     otError                error = OT_ERROR_NONE;
450     otBackboneRouterConfig bbrConfig;
451 
452     otBackboneRouterGetConfig(mInstance, &bbrConfig);
453 
454     SuccessOrExit(error = mEncoder.WriteUint16(bbrConfig.mReregistrationDelay));
455     SuccessOrExit(error = mEncoder.WriteUint32(bbrConfig.mMlrTimeout));
456     SuccessOrExit(error = mEncoder.WriteUint8(bbrConfig.mSequenceNumber));
457 
458 exit:
459     return error;
460 }
461 
HandlePropertySet(void)462 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_CONFIG>(void)
463 {
464     otError                error = OT_ERROR_NONE;
465     otBackboneRouterConfig bbrConfig;
466 
467     SuccessOrExit(error = mDecoder.ReadUint16(bbrConfig.mReregistrationDelay));
468     SuccessOrExit(error = mDecoder.ReadUint32(bbrConfig.mMlrTimeout));
469     SuccessOrExit(error = mDecoder.ReadUint8(bbrConfig.mSequenceNumber));
470 
471     SuccessOrExit(error = otBackboneRouterSetConfig(mInstance, &bbrConfig));
472 
473 exit:
474     return error;
475 }
476 
HandlePropertySet(void)477 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_REGISTER>(void)
478 {
479     return otBackboneRouterRegister(mInstance);
480 }
481 
HandlePropertyGet(void)482 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_REGISTRATION_JITTER>(void)
483 {
484     uint8_t jitter = otBackboneRouterGetRegistrationJitter(mInstance);
485 
486     return mEncoder.WriteUint8(jitter);
487 }
488 
HandlePropertySet(void)489 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_REGISTRATION_JITTER>(void)
490 {
491     otError error = OT_ERROR_NONE;
492     uint8_t jitter;
493 
494     SuccessOrExit(error = mDecoder.ReadUint8(jitter));
495 
496     otBackboneRouterSetRegistrationJitter(mInstance, jitter);
497 
498 exit:
499     return error;
500 }
501 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
502 
HandlePropertyGet(void)503 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_PSKC>(void)
504 {
505     Pskc pskc;
506 
507     otThreadGetPskc(mInstance, &pskc);
508 
509     return mEncoder.WriteData(pskc.m8, sizeof(spinel_net_pskc_t));
510 }
511 
HandlePropertySet(void)512 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_PSKC>(void)
513 {
514     const uint8_t *ptr = nullptr;
515     uint16_t       len;
516     otError        error = OT_ERROR_NONE;
517 
518     SuccessOrExit(error = mDecoder.ReadData(ptr, len));
519 
520     VerifyOrExit(len == sizeof(spinel_net_pskc_t), error = OT_ERROR_PARSE);
521 
522     error = otThreadSetPskc(mInstance, reinterpret_cast<const otPskc *>(ptr));
523 
524 exit:
525     return error;
526 }
527 
528 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
HandlePropertySet(void)529 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_PARTITION_ID>(void)
530 {
531     uint32_t partitionId = 0;
532     otError  error       = OT_ERROR_NONE;
533 
534     SuccessOrExit(error = mDecoder.ReadUint32(partitionId));
535 
536     otThreadSetPreferredLeaderPartitionId(mInstance, partitionId);
537 
538 exit:
539     return error;
540 }
541 #endif
542 
HandlePropertyGet(void)543 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_CHILD_COUNT_MAX>(void)
544 {
545     return mEncoder.WriteUint8(static_cast<uint8_t>(otThreadGetMaxAllowedChildren(mInstance)));
546 }
547 
HandlePropertySet(void)548 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_CHILD_COUNT_MAX>(void)
549 {
550     uint8_t maxChildren = 0;
551     otError error       = OT_ERROR_NONE;
552 
553     SuccessOrExit(error = mDecoder.ReadUint8(maxChildren));
554 
555     error = otThreadSetMaxAllowedChildren(mInstance, maxChildren);
556 
557 exit:
558     return error;
559 }
560 
HandlePropertyGet(void)561 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ROUTER_UPGRADE_THRESHOLD>(void)
562 {
563     return mEncoder.WriteUint8(otThreadGetRouterUpgradeThreshold(mInstance));
564 }
565 
HandlePropertySet(void)566 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_ROUTER_UPGRADE_THRESHOLD>(void)
567 {
568     uint8_t threshold = 0;
569     otError error     = OT_ERROR_NONE;
570 
571     SuccessOrExit(error = mDecoder.ReadUint8(threshold));
572 
573     otThreadSetRouterUpgradeThreshold(mInstance, threshold);
574 
575 exit:
576     return error;
577 }
578 
HandlePropertyGet(void)579 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ROUTER_DOWNGRADE_THRESHOLD>(void)
580 {
581     return mEncoder.WriteUint8(otThreadGetRouterDowngradeThreshold(mInstance));
582 }
583 
HandlePropertySet(void)584 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_ROUTER_DOWNGRADE_THRESHOLD>(void)
585 {
586     uint8_t threshold = 0;
587     otError error     = OT_ERROR_NONE;
588 
589     SuccessOrExit(error = mDecoder.ReadUint8(threshold));
590 
591     otThreadSetRouterDowngradeThreshold(mInstance, threshold);
592 
593 exit:
594     return error;
595 }
596 
HandlePropertyGet(void)597 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ROUTER_SELECTION_JITTER>(void)
598 {
599     return mEncoder.WriteUint8(otThreadGetRouterSelectionJitter(mInstance));
600 }
601 
HandlePropertySet(void)602 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_ROUTER_SELECTION_JITTER>(void)
603 {
604     uint8_t jitter = 0;
605     otError error  = OT_ERROR_NONE;
606 
607     SuccessOrExit(error = mDecoder.ReadUint8(jitter));
608 
609     otThreadSetRouterSelectionJitter(mInstance, jitter);
610 
611 exit:
612     return error;
613 }
614 
HandlePropertyGet(void)615 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_CONTEXT_REUSE_DELAY>(void)
616 {
617     return mEncoder.WriteUint32(otThreadGetContextIdReuseDelay(mInstance));
618 }
619 
HandlePropertySet(void)620 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_CONTEXT_REUSE_DELAY>(void)
621 {
622     uint32_t delay = 0;
623     otError  error = OT_ERROR_NONE;
624 
625     SuccessOrExit(error = mDecoder.ReadUint32(delay));
626 
627     otThreadSetContextIdReuseDelay(mInstance, delay);
628 
629 exit:
630     return error;
631 }
632 
HandlePropertyGet(void)633 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_NETWORK_ID_TIMEOUT>(void)
634 {
635     return mEncoder.WriteUint8(otThreadGetNetworkIdTimeout(mInstance));
636 }
637 
HandlePropertySet(void)638 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_NETWORK_ID_TIMEOUT>(void)
639 {
640     uint8_t timeout = 0;
641     otError error   = OT_ERROR_NONE;
642 
643     SuccessOrExit(error = mDecoder.ReadUint8(timeout));
644 
645     otThreadSetNetworkIdTimeout(mInstance, timeout);
646 
647 exit:
648     return error;
649 }
650 
HandlePropertyGet(void)651 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_NEW_DATASET>(void)
652 {
653     otError              error;
654     otOperationalDataset dataset;
655 
656     error = otDatasetCreateNewNetwork(mInstance, &dataset);
657 
658     if (error == OT_ERROR_NONE)
659     {
660         error = EncodeOperationalDataset(dataset);
661     }
662     else
663     {
664         error = mEncoder.OverwriteWithLastStatusError(ThreadErrorToSpinelStatus(error));
665     }
666 
667     return error;
668 }
669 
670 #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
671 
HandlePropertyGet(void)672 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MESHCOP_COMMISSIONER_STATE>(void)
673 {
674     uint8_t state = SPINEL_MESHCOP_COMMISSIONER_STATE_DISABLED;
675 
676     switch (otCommissionerGetState(mInstance))
677     {
678     case OT_COMMISSIONER_STATE_DISABLED:
679         state = SPINEL_MESHCOP_COMMISSIONER_STATE_DISABLED;
680         break;
681 
682     case OT_COMMISSIONER_STATE_PETITION:
683         state = SPINEL_MESHCOP_COMMISSIONER_STATE_PETITION;
684         break;
685 
686     case OT_COMMISSIONER_STATE_ACTIVE:
687         state = SPINEL_MESHCOP_COMMISSIONER_STATE_ACTIVE;
688         break;
689     }
690 
691     return mEncoder.WriteUint8(state);
692 }
693 
HandlePropertySet(void)694 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_STATE>(void)
695 {
696     uint8_t state;
697     otError error = OT_ERROR_NONE;
698 
699     SuccessOrExit(error = mDecoder.ReadUint8(state));
700 
701     switch (state)
702     {
703     case SPINEL_MESHCOP_COMMISSIONER_STATE_DISABLED:
704         error = otCommissionerStop(mInstance);
705         break;
706 
707     case SPINEL_MESHCOP_COMMISSIONER_STATE_ACTIVE:
708         error = otCommissionerStart(mInstance, nullptr, nullptr, nullptr);
709         break;
710 
711     default:
712         error = OT_ERROR_INVALID_ARGS;
713         break;
714     }
715 
716 exit:
717     return error;
718 }
719 
HandlePropertyGet(void)720 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MESHCOP_COMMISSIONER_JOINERS>(void)
721 {
722     otError      error = OT_ERROR_NONE;
723     uint16_t     iter  = 0;
724     otJoinerInfo joinerInfo;
725 
726     while (otCommissionerGetNextJoinerInfo(mInstance, &iter, &joinerInfo) == OT_ERROR_NONE)
727     {
728         SuccessOrExit(error = mEncoder.OpenStruct());
729 
730         SuccessOrExit(error = mEncoder.OpenStruct()); // Joiner Id (any, EUI64 or a Joiner Discerner) struct
731 
732         switch (joinerInfo.mType)
733         {
734         case OT_JOINER_INFO_TYPE_ANY:
735             break;
736 
737         case OT_JOINER_INFO_TYPE_EUI64:
738             SuccessOrExit(error = mEncoder.WriteEui64(joinerInfo.mSharedId.mEui64));
739             break;
740 
741         case OT_JOINER_INFO_TYPE_DISCERNER:
742             SuccessOrExit(error = mEncoder.WriteUint8(joinerInfo.mSharedId.mDiscerner.mLength));
743             SuccessOrExit(error = mEncoder.WriteUint64(joinerInfo.mSharedId.mDiscerner.mValue));
744             break;
745         }
746 
747         SuccessOrExit(error = mEncoder.CloseStruct());
748 
749         SuccessOrExit(error = mEncoder.WriteUint32(joinerInfo.mExpirationTime));
750         SuccessOrExit(error = mEncoder.WriteUtf8(joinerInfo.mPskd.m8));
751 
752         SuccessOrExit(error = mEncoder.CloseStruct());
753     }
754 
755 exit:
756     return error;
757 }
758 
HandlePropertyInsert(void)759 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_MESHCOP_COMMISSIONER_JOINERS>(void)
760 {
761     otError             error = OT_ERROR_NONE;
762     otJoinerDiscerner   discerner;
763     bool                withDiscerner = false;
764     const otExtAddress *eui64;
765     uint32_t            timeout;
766     const char         *psk;
767 
768     SuccessOrExit(error = mDecoder.OpenStruct());
769 
770     switch (mDecoder.GetRemainingLengthInStruct())
771     {
772     case 0:
773         // Empty struct indicates any joiner
774         eui64 = nullptr;
775         break;
776 
777     case sizeof(spinel_eui64_t):
778         SuccessOrExit(error = mDecoder.ReadEui64(eui64));
779         break;
780 
781     default:
782         SuccessOrExit(error = mDecoder.ReadUint8(discerner.mLength));
783         SuccessOrExit(error = mDecoder.ReadUint64(discerner.mValue));
784         withDiscerner = true;
785         break;
786     }
787 
788     SuccessOrExit(error = mDecoder.CloseStruct());
789 
790     SuccessOrExit(error = mDecoder.ReadUint32(timeout));
791     SuccessOrExit(error = mDecoder.ReadUtf8(psk));
792 
793     if (withDiscerner)
794     {
795         error = otCommissionerAddJoinerWithDiscerner(mInstance, &discerner, psk, timeout);
796     }
797     else
798     {
799         error = otCommissionerAddJoiner(mInstance, eui64, psk, timeout);
800     }
801 
802 exit:
803     return error;
804 }
805 
HandlePropertyRemove(void)806 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_MESHCOP_COMMISSIONER_JOINERS>(void)
807 {
808     otError             error = OT_ERROR_NONE;
809     otJoinerDiscerner   discerner;
810     bool                withDiscerner = false;
811     const otExtAddress *eui64;
812 
813     SuccessOrExit(error = mDecoder.OpenStruct());
814 
815     switch (mDecoder.GetRemainingLengthInStruct())
816     {
817     case 0:
818         // Empty struct indicates any joiner
819         eui64 = nullptr;
820         break;
821 
822     case sizeof(spinel_eui64_t):
823         SuccessOrExit(error = mDecoder.ReadEui64(eui64));
824         break;
825 
826     default:
827         SuccessOrExit(error = mDecoder.ReadUint8(discerner.mLength));
828         SuccessOrExit(error = mDecoder.ReadUint64(discerner.mValue));
829         withDiscerner = true;
830         break;
831     }
832 
833     SuccessOrExit(error = mDecoder.CloseStruct());
834 
835     if (withDiscerner)
836     {
837         error = otCommissionerRemoveJoinerWithDiscerner(mInstance, &discerner);
838     }
839     else
840     {
841         error = otCommissionerRemoveJoiner(mInstance, eui64);
842     }
843 
844 exit:
845     return error;
846 }
847 
HandlePropertyGet(void)848 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MESHCOP_COMMISSIONER_PROVISIONING_URL>(void)
849 {
850     return mEncoder.WriteUtf8(otCommissionerGetProvisioningUrl(mInstance));
851 }
852 
HandlePropertySet(void)853 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_PROVISIONING_URL>(void)
854 {
855     otError     error = OT_ERROR_NONE;
856     const char *url;
857 
858     SuccessOrExit(error = mDecoder.ReadUtf8(url));
859 
860     error = otCommissionerSetProvisioningUrl(mInstance, url);
861 
862 exit:
863     return error;
864 }
865 
HandlePropertyGet(void)866 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MESHCOP_COMMISSIONER_SESSION_ID>(void)
867 {
868     return mEncoder.WriteUint16(otCommissionerGetSessionId(mInstance));
869 }
870 
HandlePropertySet(void)871 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_ANNOUNCE_BEGIN>(void)
872 {
873     otError             error = OT_ERROR_NONE;
874     uint32_t            channelMask;
875     uint8_t             count;
876     uint16_t            period;
877     const otIp6Address *address;
878 
879     SuccessOrExit(error = mDecoder.ReadUint32(channelMask));
880     SuccessOrExit(error = mDecoder.ReadUint8(count));
881     SuccessOrExit(error = mDecoder.ReadUint16(period));
882     SuccessOrExit(error = mDecoder.ReadIp6Address(address));
883 
884     error = otCommissionerAnnounceBegin(mInstance, channelMask, count, period, address);
885 
886 exit:
887     return error;
888 }
889 
HandlePropertySet(void)890 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_ENERGY_SCAN>(void)
891 {
892     otError             error = OT_ERROR_NONE;
893     uint32_t            channelMask;
894     uint8_t             count;
895     uint16_t            period;
896     uint16_t            scanDuration;
897     const otIp6Address *address;
898 
899     SuccessOrExit(error = mDecoder.ReadUint32(channelMask));
900     SuccessOrExit(error = mDecoder.ReadUint8(count));
901     SuccessOrExit(error = mDecoder.ReadUint16(period));
902     SuccessOrExit(error = mDecoder.ReadUint16(scanDuration));
903     SuccessOrExit(error = mDecoder.ReadIp6Address(address));
904 
905     error = otCommissionerEnergyScan(mInstance, channelMask, count, period, scanDuration, address,
906                                      &NcpBase::HandleCommissionerEnergyReport_Jump, this);
907 
908 exit:
909     return error;
910 }
911 
HandleCommissionerEnergyReport_Jump(uint32_t aChannelMask,const uint8_t * aEnergyData,uint8_t aLength,void * aContext)912 void NcpBase::HandleCommissionerEnergyReport_Jump(uint32_t       aChannelMask,
913                                                   const uint8_t *aEnergyData,
914                                                   uint8_t        aLength,
915                                                   void          *aContext)
916 {
917     static_cast<NcpBase *>(aContext)->HandleCommissionerEnergyReport(aChannelMask, aEnergyData, aLength);
918 }
919 
HandleCommissionerEnergyReport(uint32_t aChannelMask,const uint8_t * aEnergyData,uint8_t aLength)920 void NcpBase::HandleCommissionerEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyData, uint8_t aLength)
921 {
922     otError error = OT_ERROR_NONE;
923 
924     SuccessOrExit(error = mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_PROP_VALUE_INSERTED,
925                                               SPINEL_PROP_MESHCOP_COMMISSIONER_ENERGY_SCAN_RESULT));
926     SuccessOrExit(error = mEncoder.WriteUint32(aChannelMask));
927     SuccessOrExit(error = mEncoder.WriteDataWithLen(aEnergyData, aLength));
928     SuccessOrExit(error = mEncoder.EndFrame());
929 
930 exit:
931 
932     if (error != OT_ERROR_NONE)
933     {
934         mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM);
935         mUpdateChangedPropsTask.Post();
936     }
937 }
938 
HandlePropertySet(void)939 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_PAN_ID_QUERY>(void)
940 {
941     otError             error = OT_ERROR_NONE;
942     uint16_t            panId;
943     uint32_t            channelMask;
944     const otIp6Address *address;
945 
946     SuccessOrExit(error = mDecoder.ReadUint16(panId));
947     SuccessOrExit(error = mDecoder.ReadUint32(channelMask));
948     SuccessOrExit(error = mDecoder.ReadIp6Address(address));
949 
950     error = otCommissionerPanIdQuery(mInstance, panId, channelMask, address,
951                                      &NcpBase::HandleCommissionerPanIdConflict_Jump, this);
952 
953 exit:
954     return error;
955 }
956 
HandleCommissionerPanIdConflict_Jump(uint16_t aPanId,uint32_t aChannelMask,void * aContext)957 void NcpBase::HandleCommissionerPanIdConflict_Jump(uint16_t aPanId, uint32_t aChannelMask, void *aContext)
958 {
959     static_cast<NcpBase *>(aContext)->HandleCommissionerPanIdConflict(aPanId, aChannelMask);
960 }
961 
HandleCommissionerPanIdConflict(uint16_t aPanId,uint32_t aChannelMask)962 void NcpBase::HandleCommissionerPanIdConflict(uint16_t aPanId, uint32_t aChannelMask)
963 {
964     otError error = OT_ERROR_NONE;
965 
966     SuccessOrExit(error = mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_PROP_VALUE_INSERTED,
967                                               SPINEL_PROP_MESHCOP_COMMISSIONER_PAN_ID_CONFLICT_RESULT));
968 
969     SuccessOrExit(error = mEncoder.WriteUint16(aPanId));
970     SuccessOrExit(error = mEncoder.WriteUint32(aChannelMask));
971     SuccessOrExit(error = mEncoder.EndFrame());
972 
973 exit:
974 
975     if (error != OT_ERROR_NONE)
976     {
977         mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM);
978         mUpdateChangedPropsTask.Post();
979     }
980 }
981 
HandlePropertySet(void)982 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_MGMT_GET>(void)
983 {
984     otError        error = OT_ERROR_NONE;
985     const uint8_t *tlvs;
986     uint16_t       length;
987 
988     SuccessOrExit(error = mDecoder.ReadDataWithLen(tlvs, length));
989     VerifyOrExit(length <= 255, error = OT_ERROR_INVALID_ARGS);
990 
991     error = otCommissionerSendMgmtGet(mInstance, tlvs, static_cast<uint8_t>(length));
992 
993 exit:
994     return error;
995 }
996 
HandlePropertySet(void)997 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_MGMT_SET>(void)
998 {
999     otError                error = OT_ERROR_NONE;
1000     const uint8_t         *tlvs;
1001     uint16_t               length;
1002     otCommissioningDataset dataset;
1003 
1004     SuccessOrExit(error = mDecoder.ReadDataWithLen(tlvs, length));
1005     VerifyOrExit(length <= 255, error = OT_ERROR_INVALID_ARGS);
1006 
1007     memset(&dataset, 0, sizeof(otCommissioningDataset));
1008     error = otCommissionerSendMgmtSet(mInstance, &dataset, tlvs, static_cast<uint8_t>(length));
1009 
1010 exit:
1011     return error;
1012 }
1013 
HandlePropertySet_SPINEL_PROP_MESHCOP_COMMISSIONER_GENERATE_PSKC(uint8_t aHeader)1014 otError NcpBase::HandlePropertySet_SPINEL_PROP_MESHCOP_COMMISSIONER_GENERATE_PSKC(uint8_t aHeader)
1015 {
1016     otError        error = OT_ERROR_NONE;
1017     const char    *passPhrase;
1018     const char    *networkName;
1019     const uint8_t *extPanIdData;
1020     uint16_t       length;
1021     otPskc         pskc;
1022 
1023     SuccessOrExit(error = mDecoder.ReadUtf8(passPhrase));
1024     SuccessOrExit(error = mDecoder.ReadUtf8(networkName));
1025     SuccessOrExit(error = mDecoder.ReadDataWithLen(extPanIdData, length));
1026     VerifyOrExit(length == sizeof(spinel_net_xpanid_t), error = OT_ERROR_PARSE);
1027 
1028     SuccessOrExit(error = otDatasetGeneratePskc(passPhrase, reinterpret_cast<const otNetworkName *>(networkName),
1029                                                 reinterpret_cast<const otExtendedPanId *>(extPanIdData), &pskc));
1030 
1031     SuccessOrExit(
1032         error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_MESHCOP_COMMISSIONER_GENERATE_PSKC));
1033     SuccessOrExit(error = mEncoder.WriteData(pskc.m8, sizeof(pskc)));
1034     SuccessOrExit(error = mEncoder.EndFrame());
1035 
1036 exit:
1037     return error;
1038 }
1039 
1040 // SPINEL_PROP_THREAD_COMMISSIONER_ENABLED is replaced by SPINEL_PROP_MESHCOP_COMMISSIONER_STATE. Please use the new
1041 // property. The old property/implementation remains for backward compatibility.
1042 
HandlePropertyGet(void)1043 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_COMMISSIONER_ENABLED>(void)
1044 {
1045     return mEncoder.WriteBool(otCommissionerGetState(mInstance) == OT_COMMISSIONER_STATE_ACTIVE);
1046 }
1047 
HandlePropertySet_SPINEL_PROP_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader)1048 otError NcpBase::HandlePropertySet_SPINEL_PROP_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader)
1049 {
1050     bool    enabled = false;
1051     otError error   = OT_ERROR_NONE;
1052 
1053     SuccessOrExit(error = mDecoder.ReadBool(enabled));
1054 
1055     if (!enabled)
1056     {
1057         error = otCommissionerStop(mInstance);
1058     }
1059     else
1060     {
1061         error = otCommissionerStart(mInstance, nullptr, nullptr, nullptr);
1062     }
1063 
1064 exit:
1065     return PrepareLastStatusResponse(aHeader, ThreadErrorToSpinelStatus(error));
1066 }
1067 
1068 // SPINEL_PROP_THREAD_JOINERS is replaced by SPINEL_PROP_MESHCOP_COMMISSIONER_JOINERS. Please us the new property.
1069 // The old property/implementation remains for backward compatibility.
1070 
HandlePropertyInsert(void)1071 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_THREAD_JOINERS>(void)
1072 {
1073     otError             error         = OT_ERROR_NONE;
1074     const otExtAddress *eui64         = nullptr;
1075     const char         *pskd          = nullptr;
1076     uint32_t            joinerTimeout = 0;
1077 
1078     SuccessOrExit(error = mDecoder.ReadUtf8(pskd));
1079     SuccessOrExit(error = mDecoder.ReadUint32(joinerTimeout));
1080 
1081     if (mDecoder.ReadEui64(eui64) != OT_ERROR_NONE)
1082     {
1083         eui64 = nullptr;
1084     }
1085 
1086     error = otCommissionerAddJoiner(mInstance, eui64, pskd, joinerTimeout);
1087 
1088 exit:
1089     return error;
1090 }
1091 #endif // OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
1092 
HandlePropertySet(void)1093 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_LOCAL_LEADER_WEIGHT>(void)
1094 {
1095     uint8_t weight;
1096     otError error = OT_ERROR_NONE;
1097 
1098     SuccessOrExit(error = mDecoder.ReadUint8(weight));
1099 
1100     otThreadSetLocalLeaderWeight(mInstance, weight);
1101 
1102 exit:
1103     return error;
1104 }
1105 
1106 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
1107 
HandlePropertyGet(void)1108 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_STEERING_DATA>(void)
1109 {
1110     return mEncoder.WriteEui64(mSteeringDataAddress);
1111 }
1112 
HandlePropertySet(void)1113 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_STEERING_DATA>(void)
1114 {
1115     otError error = OT_ERROR_NONE;
1116 
1117     SuccessOrExit(error = mDecoder.ReadEui64(mSteeringDataAddress));
1118 
1119     otThreadSetSteeringData(mInstance, &mSteeringDataAddress);
1120 
1121 exit:
1122     return error;
1123 }
1124 #endif // #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
1125 
HandlePropertyGet(void)1126 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_PREFERRED_ROUTER_ID>(void)
1127 {
1128     return mEncoder.WriteUint8(mPreferredRouteId);
1129 }
1130 
HandlePropertySet(void)1131 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_PREFERRED_ROUTER_ID>(void)
1132 {
1133     otError error = OT_ERROR_NONE;
1134 
1135     SuccessOrExit(error = mDecoder.ReadUint8(mPreferredRouteId));
1136 
1137     SuccessOrExit(error = otThreadSetPreferredRouterId(mInstance, mPreferredRouteId));
1138 
1139 exit:
1140     return error;
1141 }
1142 
HandlePropertyRemove(void)1143 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_THREAD_ACTIVE_ROUTER_IDS>(void)
1144 {
1145     otError error = OT_ERROR_NONE;
1146     uint8_t routerId;
1147 
1148     SuccessOrExit(error = mDecoder.ReadUint8(routerId));
1149 
1150     error = otThreadReleaseRouterId(mInstance, routerId);
1151 
1152     // `INVALID_STATE` is returned when router ID was not allocated (i.e. not in the list)
1153     // in such a case, the "remove" operation can be considered successful.
1154 
1155     if (error == OT_ERROR_INVALID_STATE)
1156     {
1157         error = OT_ERROR_NONE;
1158     }
1159 
1160 exit:
1161     return error;
1162 }
1163 
HandlePropertyGet(void)1164 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ADDRESS_CACHE_TABLE>(void)
1165 {
1166     otError              error = OT_ERROR_NONE;
1167     otCacheEntryIterator iterator;
1168     otCacheEntryInfo     entry;
1169 
1170     memset(&iterator, 0, sizeof(iterator));
1171 
1172     for (uint8_t index = 0;; index++)
1173     {
1174         SuccessOrExit(otThreadGetNextCacheEntry(mInstance, &entry, &iterator));
1175 
1176         SuccessOrExit(error = mEncoder.OpenStruct());
1177         SuccessOrExit(error = mEncoder.WriteIp6Address(entry.mTarget));
1178         SuccessOrExit(error = mEncoder.WriteUint16(entry.mRloc16));
1179         SuccessOrExit(error = mEncoder.WriteUint8(index));
1180 
1181         switch (entry.mState)
1182         {
1183         case OT_CACHE_ENTRY_STATE_CACHED:
1184             SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_ADDRESS_CACHE_ENTRY_STATE_CACHED));
1185             break;
1186         case OT_CACHE_ENTRY_STATE_SNOOPED:
1187             SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_ADDRESS_CACHE_ENTRY_STATE_SNOOPED));
1188             break;
1189         case OT_CACHE_ENTRY_STATE_QUERY:
1190             SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_ADDRESS_CACHE_ENTRY_STATE_QUERY));
1191             break;
1192         case OT_CACHE_ENTRY_STATE_RETRY_QUERY:
1193             SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_ADDRESS_CACHE_ENTRY_STATE_RETRY_QUERY));
1194             break;
1195         }
1196 
1197         SuccessOrExit(error = mEncoder.OpenStruct());
1198 
1199         if (entry.mState == OT_CACHE_ENTRY_STATE_CACHED)
1200         {
1201             SuccessOrExit(error = mEncoder.WriteBool(entry.mValidLastTrans));
1202             SuccessOrExit(error = mEncoder.WriteUint32(entry.mLastTransTime));
1203             SuccessOrExit(error = mEncoder.WriteIp6Address(entry.mMeshLocalEid));
1204         }
1205 
1206         SuccessOrExit(error = mEncoder.CloseStruct());
1207 
1208         SuccessOrExit(error = mEncoder.OpenStruct());
1209 
1210         if (entry.mState != OT_CACHE_ENTRY_STATE_CACHED)
1211         {
1212             SuccessOrExit(error = mEncoder.WriteBool(entry.mCanEvict));
1213             SuccessOrExit(error = mEncoder.WriteUint16(entry.mRampDown ? 0 : entry.mTimeout));
1214             SuccessOrExit(error = mEncoder.WriteUint16(entry.mRetryDelay));
1215         }
1216 
1217         SuccessOrExit(error = mEncoder.CloseStruct());
1218 
1219         SuccessOrExit(error = mEncoder.CloseStruct());
1220     }
1221 
1222 exit:
1223     return error;
1224 }
1225 
HandlePropertyGet(void)1226 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHILD_SUPERVISION_INTERVAL>(void)
1227 {
1228     return mEncoder.WriteUint16(otChildSupervisionGetInterval(mInstance));
1229 }
1230 
HandlePropertySet(void)1231 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHILD_SUPERVISION_INTERVAL>(void)
1232 {
1233     otError  error = OT_ERROR_NONE;
1234     uint16_t interval;
1235 
1236     SuccessOrExit(error = mDecoder.ReadUint16(interval));
1237     otChildSupervisionSetInterval(mInstance, interval);
1238 
1239 exit:
1240     return error;
1241 }
1242 
1243 #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE
1244 
HandlePropertyGet(void)1245 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL>(void)
1246 {
1247     return mEncoder.WriteUint8(otChannelManagerGetRequestedChannel(mInstance));
1248 }
1249 
HandlePropertySet(void)1250 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL>(void)
1251 {
1252     uint8_t channel;
1253     otError error = OT_ERROR_NONE;
1254 
1255     SuccessOrExit(error = mDecoder.ReadUint8(channel));
1256 
1257     otChannelManagerRequestChannelChange(mInstance, channel);
1258 
1259 exit:
1260     return error;
1261 }
1262 
HandlePropertyGet(void)1263 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MANAGER_DELAY>(void)
1264 {
1265     return mEncoder.WriteUint16(otChannelManagerGetDelay(mInstance));
1266 }
1267 
HandlePropertySet(void)1268 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHANNEL_MANAGER_DELAY>(void)
1269 {
1270     uint16_t delay;
1271     otError  error = OT_ERROR_NONE;
1272 
1273     SuccessOrExit(error = mDecoder.ReadUint16(delay));
1274 
1275     error = otChannelManagerSetDelay(mInstance, delay);
1276 
1277 exit:
1278     return error;
1279 }
1280 
HandlePropertyGet(void)1281 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MANAGER_SUPPORTED_CHANNELS>(void)
1282 {
1283     return EncodeChannelMask(otChannelManagerGetSupportedChannels(mInstance));
1284 }
1285 
HandlePropertySet(void)1286 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHANNEL_MANAGER_SUPPORTED_CHANNELS>(void)
1287 {
1288     uint32_t channelMask = 0;
1289     otError  error       = OT_ERROR_NONE;
1290 
1291     SuccessOrExit(error = DecodeChannelMask(channelMask));
1292     otChannelManagerSetSupportedChannels(mInstance, channelMask);
1293 
1294 exit:
1295     return error;
1296 }
1297 
HandlePropertyGet(void)1298 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MANAGER_FAVORED_CHANNELS>(void)
1299 {
1300     return EncodeChannelMask(otChannelManagerGetFavoredChannels(mInstance));
1301 }
1302 
HandlePropertySet(void)1303 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHANNEL_MANAGER_FAVORED_CHANNELS>(void)
1304 {
1305     uint32_t channelMask = 0;
1306     otError  error       = OT_ERROR_NONE;
1307 
1308     SuccessOrExit(error = DecodeChannelMask(channelMask));
1309     otChannelManagerSetFavoredChannels(mInstance, channelMask);
1310 
1311 exit:
1312     return error;
1313 }
1314 
HandlePropertyGet(void)1315 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MANAGER_CHANNEL_SELECT>(void)
1316 {
1317     return mEncoder.WriteBool(false);
1318 }
1319 
HandlePropertySet(void)1320 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHANNEL_MANAGER_CHANNEL_SELECT>(void)
1321 {
1322     bool    skipQualityCheck = false;
1323     otError error            = OT_ERROR_NONE;
1324 
1325     SuccessOrExit(error = mDecoder.ReadBool(skipQualityCheck));
1326     error = otChannelManagerRequestChannelSelect(mInstance, skipQualityCheck);
1327 
1328 exit:
1329     return error;
1330 }
1331 
HandlePropertyGet(void)1332 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_ENABLED>(void)
1333 {
1334     return mEncoder.WriteBool(otChannelManagerGetAutoChannelSelectionEnabled(mInstance));
1335 }
1336 
HandlePropertySet(void)1337 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_ENABLED>(void)
1338 {
1339     bool    enabled = false;
1340     otError error   = OT_ERROR_NONE;
1341 
1342     SuccessOrExit(error = mDecoder.ReadBool(enabled));
1343     otChannelManagerSetAutoChannelSelectionEnabled(mInstance, enabled);
1344 
1345 exit:
1346     return error;
1347 }
1348 
HandlePropertyGet(void)1349 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL>(void)
1350 {
1351     return mEncoder.WriteUint32(otChannelManagerGetAutoChannelSelectionInterval(mInstance));
1352 }
1353 
HandlePropertySet(void)1354 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL>(void)
1355 {
1356     uint32_t interval;
1357     otError  error = OT_ERROR_NONE;
1358 
1359     SuccessOrExit(error = mDecoder.ReadUint32(interval));
1360     error = otChannelManagerSetAutoChannelSelectionInterval(mInstance, interval);
1361 
1362 exit:
1363     return error;
1364 }
1365 
1366 #endif // OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE
1367 
1368 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
HandlePropertyGet(void)1369 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_TIME_SYNC_PERIOD>(void)
1370 {
1371     return mEncoder.WriteUint16(otNetworkTimeGetSyncPeriod(mInstance));
1372 }
1373 
HandlePropertySet(void)1374 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_TIME_SYNC_PERIOD>(void)
1375 {
1376     otError  error = OT_ERROR_NONE;
1377     uint16_t timeSyncPeriod;
1378 
1379     SuccessOrExit(error = mDecoder.ReadUint16(timeSyncPeriod));
1380 
1381     SuccessOrExit(error = otNetworkTimeSetSyncPeriod(mInstance, timeSyncPeriod));
1382 
1383 exit:
1384     return error;
1385 }
1386 
HandlePropertyGet(void)1387 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_TIME_SYNC_XTAL_THRESHOLD>(void)
1388 {
1389     return mEncoder.WriteUint16(otNetworkTimeGetXtalThreshold(mInstance));
1390 }
1391 
HandlePropertySet(void)1392 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_TIME_SYNC_XTAL_THRESHOLD>(void)
1393 {
1394     otError  error = OT_ERROR_NONE;
1395     uint16_t xtalThreshold;
1396 
1397     SuccessOrExit(error = mDecoder.ReadUint16(xtalThreshold));
1398 
1399     SuccessOrExit(error = otNetworkTimeSetXtalThreshold(mInstance, xtalThreshold));
1400 
1401 exit:
1402     return error;
1403 }
1404 #endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1405 
1406 } // namespace Ncp
1407 } // namespace ot
1408 
1409 #endif // OPENTHREAD_FTD
1410