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 #if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
43 #include <openthread/child_supervision.h>
44 #endif
45 #include <openthread/dataset.h>
46 #include <openthread/dataset_ftd.h>
47 #include <openthread/diag.h>
48 #include <openthread/icmp6.h>
49 #include <openthread/ncp.h>
50 #include <openthread/thread_ftd.h>
51 #include <openthread/platform/misc.h>
52 
53 #include "common/code_utils.hpp"
54 #include "common/debug.hpp"
55 #include "common/instance.hpp"
56 #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
57 #include "meshcop/commissioner.hpp"
58 #endif
59 
60 #if OPENTHREAD_FTD
61 namespace ot {
62 namespace Ncp {
63 
EncodeChildInfo(const otChildInfo & aChildInfo)64 otError NcpBase::EncodeChildInfo(const otChildInfo &aChildInfo)
65 {
66     otError error = OT_ERROR_NONE;
67     uint8_t modeFlags;
68 
69     modeFlags =
70         LinkFlagsToFlagByte(aChildInfo.mRxOnWhenIdle, aChildInfo.mFullThreadDevice, aChildInfo.mFullNetworkData);
71 
72     SuccessOrExit(error = mEncoder.WriteEui64(aChildInfo.mExtAddress));
73     SuccessOrExit(error = mEncoder.WriteUint16(aChildInfo.mRloc16));
74     SuccessOrExit(error = mEncoder.WriteUint32(aChildInfo.mTimeout));
75     SuccessOrExit(error = mEncoder.WriteUint32(aChildInfo.mAge));
76     SuccessOrExit(error = mEncoder.WriteUint8(aChildInfo.mNetworkDataVersion));
77     SuccessOrExit(error = mEncoder.WriteUint8(aChildInfo.mLinkQualityIn));
78     SuccessOrExit(error = mEncoder.WriteInt8(aChildInfo.mAverageRssi));
79     SuccessOrExit(error = mEncoder.WriteUint8(modeFlags));
80     SuccessOrExit(error = mEncoder.WriteInt8(aChildInfo.mLastRssi));
81 
82 exit:
83     return error;
84 }
85 
86 // ----------------------------------------------------------------------------
87 // MARK: Property/Status Changed
88 // ----------------------------------------------------------------------------
89 
HandleParentResponseInfo(otThreadParentResponseInfo * aInfo,void * aContext)90 void NcpBase::HandleParentResponseInfo(otThreadParentResponseInfo *aInfo, void *aContext)
91 {
92     VerifyOrExit(aInfo && aContext);
93 
94     static_cast<NcpBase *>(aContext)->HandleParentResponseInfo(*aInfo);
95 
96 exit:
97     return;
98 }
99 
HandleParentResponseInfo(const otThreadParentResponseInfo & aInfo)100 void NcpBase::HandleParentResponseInfo(const otThreadParentResponseInfo &aInfo)
101 {
102     VerifyOrExit(!mChangedPropsSet.IsPropertyFiltered(SPINEL_PROP_PARENT_RESPONSE_INFO));
103 
104     SuccessOrExit(mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_PROP_VALUE_IS,
105                                       SPINEL_PROP_PARENT_RESPONSE_INFO));
106 
107     SuccessOrExit(mEncoder.WriteEui64(aInfo.mExtAddr));
108     SuccessOrExit(mEncoder.WriteUint16(aInfo.mRloc16));
109     SuccessOrExit(mEncoder.WriteInt8(aInfo.mRssi));
110     SuccessOrExit(mEncoder.WriteInt8(aInfo.mPriority));
111     SuccessOrExit(mEncoder.WriteUint8(aInfo.mLinkQuality3));
112     SuccessOrExit(mEncoder.WriteUint8(aInfo.mLinkQuality2));
113     SuccessOrExit(mEncoder.WriteUint8(aInfo.mLinkQuality1));
114     SuccessOrExit(mEncoder.WriteBool(aInfo.mIsAttached));
115 
116     SuccessOrExit(mEncoder.EndFrame());
117 
118 exit:
119     return;
120 }
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 (size_t i = 0; i < sizeof(otIp6InterfaceIdentifier); i++)
370         {
371             SuccessOrExit(error = mEncoder.WriteUint8(iid->mFields.m8[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 (size_t i = 0; i < sizeof(otIp6InterfaceIdentifier); i++)
392         {
393             SuccessOrExit(error = mDecoder.ReadUint8(iid.mFields.m8[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     return mEncoder.WriteData(otThreadGetPskc(mInstance)->m8, sizeof(spinel_net_pskc_t));
506 }
507 
HandlePropertySet(void)508 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_PSKC>(void)
509 {
510     const uint8_t *ptr = nullptr;
511     uint16_t       len;
512     otError        error = OT_ERROR_NONE;
513 
514     SuccessOrExit(error = mDecoder.ReadData(ptr, len));
515 
516     VerifyOrExit(len == sizeof(spinel_net_pskc_t), error = OT_ERROR_PARSE);
517 
518     error = otThreadSetPskc(mInstance, reinterpret_cast<const otPskc *>(ptr));
519 
520 exit:
521     return error;
522 }
523 
524 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
HandlePropertySet(void)525 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_PARTITION_ID>(void)
526 {
527     uint32_t partitionId = 0;
528     otError  error       = OT_ERROR_NONE;
529 
530     SuccessOrExit(error = mDecoder.ReadUint32(partitionId));
531 
532     otThreadSetPreferredLeaderPartitionId(mInstance, partitionId);
533 
534 exit:
535     return error;
536 }
537 #endif
538 
HandlePropertyGet(void)539 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_CHILD_COUNT_MAX>(void)
540 {
541     return mEncoder.WriteUint8(static_cast<uint8_t>(otThreadGetMaxAllowedChildren(mInstance)));
542 }
543 
HandlePropertySet(void)544 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_CHILD_COUNT_MAX>(void)
545 {
546     uint8_t maxChildren = 0;
547     otError error       = OT_ERROR_NONE;
548 
549     SuccessOrExit(error = mDecoder.ReadUint8(maxChildren));
550 
551     error = otThreadSetMaxAllowedChildren(mInstance, maxChildren);
552 
553 exit:
554     return error;
555 }
556 
HandlePropertyGet(void)557 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ROUTER_UPGRADE_THRESHOLD>(void)
558 {
559     return mEncoder.WriteUint8(otThreadGetRouterUpgradeThreshold(mInstance));
560 }
561 
HandlePropertySet(void)562 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_ROUTER_UPGRADE_THRESHOLD>(void)
563 {
564     uint8_t threshold = 0;
565     otError error     = OT_ERROR_NONE;
566 
567     SuccessOrExit(error = mDecoder.ReadUint8(threshold));
568 
569     otThreadSetRouterUpgradeThreshold(mInstance, threshold);
570 
571 exit:
572     return error;
573 }
574 
HandlePropertyGet(void)575 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ROUTER_DOWNGRADE_THRESHOLD>(void)
576 {
577     return mEncoder.WriteUint8(otThreadGetRouterDowngradeThreshold(mInstance));
578 }
579 
HandlePropertySet(void)580 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_ROUTER_DOWNGRADE_THRESHOLD>(void)
581 {
582     uint8_t threshold = 0;
583     otError error     = OT_ERROR_NONE;
584 
585     SuccessOrExit(error = mDecoder.ReadUint8(threshold));
586 
587     otThreadSetRouterDowngradeThreshold(mInstance, threshold);
588 
589 exit:
590     return error;
591 }
592 
HandlePropertyGet(void)593 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ROUTER_SELECTION_JITTER>(void)
594 {
595     return mEncoder.WriteUint8(otThreadGetRouterSelectionJitter(mInstance));
596 }
597 
HandlePropertySet(void)598 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_ROUTER_SELECTION_JITTER>(void)
599 {
600     uint8_t jitter = 0;
601     otError error  = OT_ERROR_NONE;
602 
603     SuccessOrExit(error = mDecoder.ReadUint8(jitter));
604 
605     otThreadSetRouterSelectionJitter(mInstance, jitter);
606 
607 exit:
608     return error;
609 }
610 
HandlePropertyGet(void)611 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_CONTEXT_REUSE_DELAY>(void)
612 {
613     return mEncoder.WriteUint32(otThreadGetContextIdReuseDelay(mInstance));
614 }
615 
HandlePropertySet(void)616 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_CONTEXT_REUSE_DELAY>(void)
617 {
618     uint32_t delay = 0;
619     otError  error = OT_ERROR_NONE;
620 
621     SuccessOrExit(error = mDecoder.ReadUint32(delay));
622 
623     otThreadSetContextIdReuseDelay(mInstance, delay);
624 
625 exit:
626     return error;
627 }
628 
HandlePropertyGet(void)629 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_NETWORK_ID_TIMEOUT>(void)
630 {
631     return mEncoder.WriteUint8(otThreadGetNetworkIdTimeout(mInstance));
632 }
633 
HandlePropertySet(void)634 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_NETWORK_ID_TIMEOUT>(void)
635 {
636     uint8_t timeout = 0;
637     otError error   = OT_ERROR_NONE;
638 
639     SuccessOrExit(error = mDecoder.ReadUint8(timeout));
640 
641     otThreadSetNetworkIdTimeout(mInstance, timeout);
642 
643 exit:
644     return error;
645 }
646 
HandlePropertyGet(void)647 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_NEW_DATASET>(void)
648 {
649     otError              error;
650     otOperationalDataset dataset;
651 
652     error = otDatasetCreateNewNetwork(mInstance, &dataset);
653 
654     if (error == OT_ERROR_NONE)
655     {
656         error = EncodeOperationalDataset(dataset);
657     }
658     else
659     {
660         error = mEncoder.OverwriteWithLastStatusError(ThreadErrorToSpinelStatus(error));
661     }
662 
663     return error;
664 }
665 
666 #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
667 
HandlePropertyGet(void)668 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MESHCOP_COMMISSIONER_STATE>(void)
669 {
670     uint8_t state = SPINEL_MESHCOP_COMMISSIONER_STATE_DISABLED;
671 
672     switch (otCommissionerGetState(mInstance))
673     {
674     case OT_COMMISSIONER_STATE_DISABLED:
675         state = SPINEL_MESHCOP_COMMISSIONER_STATE_DISABLED;
676         break;
677 
678     case OT_COMMISSIONER_STATE_PETITION:
679         state = SPINEL_MESHCOP_COMMISSIONER_STATE_PETITION;
680         break;
681 
682     case OT_COMMISSIONER_STATE_ACTIVE:
683         state = SPINEL_MESHCOP_COMMISSIONER_STATE_ACTIVE;
684         break;
685     }
686 
687     return mEncoder.WriteUint8(state);
688 }
689 
HandlePropertySet(void)690 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_STATE>(void)
691 {
692     uint8_t state;
693     otError error = OT_ERROR_NONE;
694 
695     SuccessOrExit(error = mDecoder.ReadUint8(state));
696 
697     switch (state)
698     {
699     case SPINEL_MESHCOP_COMMISSIONER_STATE_DISABLED:
700         error = otCommissionerStop(mInstance);
701         break;
702 
703     case SPINEL_MESHCOP_COMMISSIONER_STATE_ACTIVE:
704         error = otCommissionerStart(mInstance, nullptr, nullptr, nullptr);
705         break;
706 
707     default:
708         error = OT_ERROR_INVALID_ARGS;
709         break;
710     }
711 
712 exit:
713     return error;
714 }
715 
HandlePropertyGet(void)716 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MESHCOP_COMMISSIONER_JOINERS>(void)
717 {
718     otError      error = OT_ERROR_NONE;
719     uint16_t     iter  = 0;
720     otJoinerInfo joinerInfo;
721 
722     while (otCommissionerGetNextJoinerInfo(mInstance, &iter, &joinerInfo) == OT_ERROR_NONE)
723     {
724         SuccessOrExit(error = mEncoder.OpenStruct());
725 
726         SuccessOrExit(error = mEncoder.OpenStruct()); // Joiner Id (any, EUI64 or a Joiner Discerner) struct
727 
728         switch (joinerInfo.mType)
729         {
730         case OT_JOINER_INFO_TYPE_ANY:
731             break;
732 
733         case OT_JOINER_INFO_TYPE_EUI64:
734             SuccessOrExit(error = mEncoder.WriteEui64(joinerInfo.mSharedId.mEui64));
735             break;
736 
737         case OT_JOINER_INFO_TYPE_DISCERNER:
738             SuccessOrExit(error = mEncoder.WriteUint8(joinerInfo.mSharedId.mDiscerner.mLength));
739             SuccessOrExit(error = mEncoder.WriteUint64(joinerInfo.mSharedId.mDiscerner.mValue));
740             break;
741         }
742 
743         SuccessOrExit(error = mEncoder.CloseStruct());
744 
745         SuccessOrExit(error = mEncoder.WriteUint32(joinerInfo.mExpirationTime));
746         SuccessOrExit(error = mEncoder.WriteUtf8(joinerInfo.mPskd.m8));
747 
748         SuccessOrExit(error = mEncoder.CloseStruct());
749     }
750 
751 exit:
752     return error;
753 }
754 
HandlePropertyInsert(void)755 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_MESHCOP_COMMISSIONER_JOINERS>(void)
756 {
757     otError             error = OT_ERROR_NONE;
758     otJoinerDiscerner   discerner;
759     bool                withDiscerner = false;
760     const otExtAddress *eui64;
761     uint32_t            timeout;
762     const char *        psk;
763 
764     SuccessOrExit(error = mDecoder.OpenStruct());
765 
766     switch (mDecoder.GetRemainingLengthInStruct())
767     {
768     case 0:
769         // Empty struct indicates any joiner
770         eui64 = nullptr;
771         break;
772 
773     case sizeof(spinel_eui64_t):
774         SuccessOrExit(error = mDecoder.ReadEui64(eui64));
775         break;
776 
777     default:
778         SuccessOrExit(error = mDecoder.ReadUint8(discerner.mLength));
779         SuccessOrExit(error = mDecoder.ReadUint64(discerner.mValue));
780         withDiscerner = true;
781         break;
782     }
783 
784     SuccessOrExit(error = mDecoder.CloseStruct());
785 
786     SuccessOrExit(error = mDecoder.ReadUint32(timeout));
787     SuccessOrExit(error = mDecoder.ReadUtf8(psk));
788 
789     if (withDiscerner)
790     {
791         error = otCommissionerAddJoinerWithDiscerner(mInstance, &discerner, psk, timeout);
792     }
793     else
794     {
795         error = otCommissionerAddJoiner(mInstance, eui64, psk, timeout);
796     }
797 
798 exit:
799     return error;
800 }
801 
HandlePropertyRemove(void)802 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_MESHCOP_COMMISSIONER_JOINERS>(void)
803 {
804     otError             error = OT_ERROR_NONE;
805     otJoinerDiscerner   discerner;
806     bool                withDiscerner = false;
807     const otExtAddress *eui64;
808 
809     SuccessOrExit(error = mDecoder.OpenStruct());
810 
811     switch (mDecoder.GetRemainingLengthInStruct())
812     {
813     case 0:
814         // Empty struct indicates any joiner
815         eui64 = nullptr;
816         break;
817 
818     case sizeof(spinel_eui64_t):
819         SuccessOrExit(error = mDecoder.ReadEui64(eui64));
820         break;
821 
822     default:
823         SuccessOrExit(error = mDecoder.ReadUint8(discerner.mLength));
824         SuccessOrExit(error = mDecoder.ReadUint64(discerner.mValue));
825         withDiscerner = true;
826         break;
827     }
828 
829     SuccessOrExit(error = mDecoder.CloseStruct());
830 
831     if (withDiscerner)
832     {
833         error = otCommissionerRemoveJoinerWithDiscerner(mInstance, &discerner);
834     }
835     else
836     {
837         error = otCommissionerRemoveJoiner(mInstance, eui64);
838     }
839 
840 exit:
841     return error;
842 }
843 
HandlePropertyGet(void)844 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MESHCOP_COMMISSIONER_PROVISIONING_URL>(void)
845 {
846     return mEncoder.WriteUtf8(otCommissionerGetProvisioningUrl(mInstance));
847 }
848 
HandlePropertySet(void)849 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_PROVISIONING_URL>(void)
850 {
851     otError     error = OT_ERROR_NONE;
852     const char *url;
853 
854     SuccessOrExit(error = mDecoder.ReadUtf8(url));
855 
856     error = otCommissionerSetProvisioningUrl(mInstance, url);
857 
858 exit:
859     return error;
860 }
861 
HandlePropertyGet(void)862 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MESHCOP_COMMISSIONER_SESSION_ID>(void)
863 {
864     return mEncoder.WriteUint16(otCommissionerGetSessionId(mInstance));
865 }
866 
HandlePropertySet(void)867 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_ANNOUNCE_BEGIN>(void)
868 {
869     otError             error = OT_ERROR_NONE;
870     uint32_t            channelMask;
871     uint8_t             count;
872     uint16_t            period;
873     const otIp6Address *address;
874 
875     SuccessOrExit(error = mDecoder.ReadUint32(channelMask));
876     SuccessOrExit(error = mDecoder.ReadUint8(count));
877     SuccessOrExit(error = mDecoder.ReadUint16(period));
878     SuccessOrExit(error = mDecoder.ReadIp6Address(address));
879 
880     error = otCommissionerAnnounceBegin(mInstance, channelMask, count, period, address);
881 
882 exit:
883     return error;
884 }
885 
HandlePropertySet(void)886 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_ENERGY_SCAN>(void)
887 {
888     otError             error = OT_ERROR_NONE;
889     uint32_t            channelMask;
890     uint8_t             count;
891     uint16_t            period;
892     uint16_t            scanDuration;
893     const otIp6Address *address;
894 
895     SuccessOrExit(error = mDecoder.ReadUint32(channelMask));
896     SuccessOrExit(error = mDecoder.ReadUint8(count));
897     SuccessOrExit(error = mDecoder.ReadUint16(period));
898     SuccessOrExit(error = mDecoder.ReadUint16(scanDuration));
899     SuccessOrExit(error = mDecoder.ReadIp6Address(address));
900 
901     error = otCommissionerEnergyScan(mInstance, channelMask, count, period, scanDuration, address,
902                                      &NcpBase::HandleCommissionerEnergyReport_Jump, this);
903 
904 exit:
905     return error;
906 }
907 
HandleCommissionerEnergyReport_Jump(uint32_t aChannelMask,const uint8_t * aEnergyData,uint8_t aLength,void * aContext)908 void NcpBase::HandleCommissionerEnergyReport_Jump(uint32_t       aChannelMask,
909                                                   const uint8_t *aEnergyData,
910                                                   uint8_t        aLength,
911                                                   void *         aContext)
912 {
913     static_cast<NcpBase *>(aContext)->HandleCommissionerEnergyReport(aChannelMask, aEnergyData, aLength);
914 }
915 
HandleCommissionerEnergyReport(uint32_t aChannelMask,const uint8_t * aEnergyData,uint8_t aLength)916 void NcpBase::HandleCommissionerEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyData, uint8_t aLength)
917 {
918     otError error = OT_ERROR_NONE;
919 
920     SuccessOrExit(error = mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_PROP_VALUE_INSERTED,
921                                               SPINEL_PROP_MESHCOP_COMMISSIONER_ENERGY_SCAN_RESULT));
922     SuccessOrExit(error = mEncoder.WriteUint32(aChannelMask));
923     SuccessOrExit(error = mEncoder.WriteDataWithLen(aEnergyData, aLength));
924     SuccessOrExit(error = mEncoder.EndFrame());
925 
926 exit:
927 
928     if (error != OT_ERROR_NONE)
929     {
930         mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM);
931         mUpdateChangedPropsTask.Post();
932     }
933 }
934 
HandlePropertySet(void)935 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_PAN_ID_QUERY>(void)
936 {
937     otError             error = OT_ERROR_NONE;
938     uint16_t            panId;
939     uint32_t            channelMask;
940     const otIp6Address *address;
941 
942     SuccessOrExit(error = mDecoder.ReadUint16(panId));
943     SuccessOrExit(error = mDecoder.ReadUint32(channelMask));
944     SuccessOrExit(error = mDecoder.ReadIp6Address(address));
945 
946     error = otCommissionerPanIdQuery(mInstance, panId, channelMask, address,
947                                      &NcpBase::HandleCommissionerPanIdConflict_Jump, this);
948 
949 exit:
950     return error;
951 }
952 
HandleCommissionerPanIdConflict_Jump(uint16_t aPanId,uint32_t aChannelMask,void * aContext)953 void NcpBase::HandleCommissionerPanIdConflict_Jump(uint16_t aPanId, uint32_t aChannelMask, void *aContext)
954 {
955     static_cast<NcpBase *>(aContext)->HandleCommissionerPanIdConflict(aPanId, aChannelMask);
956 }
957 
HandleCommissionerPanIdConflict(uint16_t aPanId,uint32_t aChannelMask)958 void NcpBase::HandleCommissionerPanIdConflict(uint16_t aPanId, uint32_t aChannelMask)
959 {
960     otError error = OT_ERROR_NONE;
961 
962     SuccessOrExit(error = mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_PROP_VALUE_INSERTED,
963                                               SPINEL_PROP_MESHCOP_COMMISSIONER_PAN_ID_CONFLICT_RESULT));
964 
965     SuccessOrExit(error = mEncoder.WriteUint16(aPanId));
966     SuccessOrExit(error = mEncoder.WriteUint32(aChannelMask));
967     SuccessOrExit(error = mEncoder.EndFrame());
968 
969 exit:
970 
971     if (error != OT_ERROR_NONE)
972     {
973         mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM);
974         mUpdateChangedPropsTask.Post();
975     }
976 }
977 
HandlePropertySet(void)978 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_MGMT_GET>(void)
979 {
980     otError        error = OT_ERROR_NONE;
981     const uint8_t *tlvs;
982     uint16_t       length;
983 
984     SuccessOrExit(error = mDecoder.ReadDataWithLen(tlvs, length));
985     VerifyOrExit(length <= 255, error = OT_ERROR_INVALID_ARGS);
986 
987     error = otCommissionerSendMgmtGet(mInstance, tlvs, static_cast<uint8_t>(length));
988 
989 exit:
990     return error;
991 }
992 
HandlePropertySet(void)993 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_MGMT_SET>(void)
994 {
995     otError                error = OT_ERROR_NONE;
996     const uint8_t *        tlvs;
997     uint16_t               length;
998     otCommissioningDataset dataset;
999 
1000     SuccessOrExit(error = mDecoder.ReadDataWithLen(tlvs, length));
1001     VerifyOrExit(length <= 255, error = OT_ERROR_INVALID_ARGS);
1002 
1003     memset(&dataset, 0, sizeof(otCommissioningDataset));
1004     error = otCommissionerSendMgmtSet(mInstance, &dataset, tlvs, static_cast<uint8_t>(length));
1005 
1006 exit:
1007     return error;
1008 }
1009 
HandlePropertySet_SPINEL_PROP_MESHCOP_COMMISSIONER_GENERATE_PSKC(uint8_t aHeader)1010 otError NcpBase::HandlePropertySet_SPINEL_PROP_MESHCOP_COMMISSIONER_GENERATE_PSKC(uint8_t aHeader)
1011 {
1012     otError        error = OT_ERROR_NONE;
1013     const char *   passPhrase;
1014     const char *   networkName;
1015     const uint8_t *extPanIdData;
1016     uint16_t       length;
1017     otPskc         pskc;
1018 
1019     SuccessOrExit(error = mDecoder.ReadUtf8(passPhrase));
1020     SuccessOrExit(error = mDecoder.ReadUtf8(networkName));
1021     SuccessOrExit(error = mDecoder.ReadDataWithLen(extPanIdData, length));
1022     VerifyOrExit(length == sizeof(spinel_net_xpanid_t), error = OT_ERROR_PARSE);
1023 
1024     SuccessOrExit(error = otDatasetGeneratePskc(passPhrase, reinterpret_cast<const otNetworkName *>(networkName),
1025                                                 reinterpret_cast<const otExtendedPanId *>(extPanIdData), &pskc));
1026 
1027     SuccessOrExit(
1028         error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_MESHCOP_COMMISSIONER_GENERATE_PSKC));
1029     SuccessOrExit(error = mEncoder.WriteData(pskc.m8, sizeof(pskc)));
1030     SuccessOrExit(error = mEncoder.EndFrame());
1031 
1032 exit:
1033     return error;
1034 }
1035 
1036 // SPINEL_PROP_THREAD_COMMISSIONER_ENABLED is replaced by SPINEL_PROP_MESHCOP_COMMISSIONER_STATE. Please use the new
1037 // property. The old property/implementation remains for backward compatibility.
1038 
HandlePropertyGet(void)1039 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_COMMISSIONER_ENABLED>(void)
1040 {
1041     return mEncoder.WriteBool(otCommissionerGetState(mInstance) == OT_COMMISSIONER_STATE_ACTIVE);
1042 }
1043 
HandlePropertySet_SPINEL_PROP_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader)1044 otError NcpBase::HandlePropertySet_SPINEL_PROP_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader)
1045 {
1046     bool    enabled = false;
1047     otError error   = OT_ERROR_NONE;
1048 
1049     SuccessOrExit(error = mDecoder.ReadBool(enabled));
1050 
1051     if (!enabled)
1052     {
1053         error = otCommissionerStop(mInstance);
1054     }
1055     else
1056     {
1057         error = otCommissionerStart(mInstance, nullptr, nullptr, nullptr);
1058     }
1059 
1060 exit:
1061     return PrepareLastStatusResponse(aHeader, ThreadErrorToSpinelStatus(error));
1062 }
1063 
1064 // SPINEL_PROP_THREAD_JOINERS is replaced by SPINEL_PROP_MESHCOP_COMMISSIONER_JOINERS. Please us the new property.
1065 // The old property/implementation remains for backward compatibility.
1066 
HandlePropertyInsert(void)1067 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_THREAD_JOINERS>(void)
1068 {
1069     otError             error         = OT_ERROR_NONE;
1070     const otExtAddress *eui64         = nullptr;
1071     const char *        pskd          = nullptr;
1072     uint32_t            joinerTimeout = 0;
1073 
1074     SuccessOrExit(error = mDecoder.ReadUtf8(pskd));
1075     SuccessOrExit(error = mDecoder.ReadUint32(joinerTimeout));
1076 
1077     if (mDecoder.ReadEui64(eui64) != OT_ERROR_NONE)
1078     {
1079         eui64 = nullptr;
1080     }
1081 
1082     error = otCommissionerAddJoiner(mInstance, eui64, pskd, joinerTimeout);
1083 
1084 exit:
1085     return error;
1086 }
1087 #endif // OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
1088 
HandlePropertySet(void)1089 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_LOCAL_LEADER_WEIGHT>(void)
1090 {
1091     uint8_t weight;
1092     otError error = OT_ERROR_NONE;
1093 
1094     SuccessOrExit(error = mDecoder.ReadUint8(weight));
1095 
1096     otThreadSetLocalLeaderWeight(mInstance, weight);
1097 
1098 exit:
1099     return error;
1100 }
1101 
1102 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
1103 
HandlePropertyGet(void)1104 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_STEERING_DATA>(void)
1105 {
1106     return mEncoder.WriteEui64(mSteeringDataAddress);
1107 }
1108 
HandlePropertySet(void)1109 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_STEERING_DATA>(void)
1110 {
1111     otError error = OT_ERROR_NONE;
1112 
1113     SuccessOrExit(error = mDecoder.ReadEui64(mSteeringDataAddress));
1114 
1115     otThreadSetSteeringData(mInstance, &mSteeringDataAddress);
1116 
1117 exit:
1118     return error;
1119 }
1120 #endif // #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
1121 
HandlePropertyGet(void)1122 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_PREFERRED_ROUTER_ID>(void)
1123 {
1124     return mEncoder.WriteUint8(mPreferredRouteId);
1125 }
1126 
HandlePropertySet(void)1127 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_PREFERRED_ROUTER_ID>(void)
1128 {
1129     otError error = OT_ERROR_NONE;
1130 
1131     SuccessOrExit(error = mDecoder.ReadUint8(mPreferredRouteId));
1132 
1133     SuccessOrExit(error = otThreadSetPreferredRouterId(mInstance, mPreferredRouteId));
1134 
1135 exit:
1136     return error;
1137 }
1138 
HandlePropertyRemove(void)1139 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_THREAD_ACTIVE_ROUTER_IDS>(void)
1140 {
1141     otError error = OT_ERROR_NONE;
1142     uint8_t routerId;
1143 
1144     SuccessOrExit(error = mDecoder.ReadUint8(routerId));
1145 
1146     error = otThreadReleaseRouterId(mInstance, routerId);
1147 
1148     // `INVALID_STATE` is returned when router ID was not allocated (i.e. not in the list)
1149     // in such a case, the "remove" operation can be considered successful.
1150 
1151     if (error == OT_ERROR_INVALID_STATE)
1152     {
1153         error = OT_ERROR_NONE;
1154     }
1155 
1156 exit:
1157     return error;
1158 }
1159 
HandlePropertyGet(void)1160 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ADDRESS_CACHE_TABLE>(void)
1161 {
1162     otError              error = OT_ERROR_NONE;
1163     otCacheEntryIterator iterator;
1164     otCacheEntryInfo     entry;
1165 
1166     memset(&iterator, 0, sizeof(iterator));
1167 
1168     for (uint8_t index = 0;; index++)
1169     {
1170         SuccessOrExit(otThreadGetNextCacheEntry(mInstance, &entry, &iterator));
1171 
1172         SuccessOrExit(error = mEncoder.OpenStruct());
1173         SuccessOrExit(error = mEncoder.WriteIp6Address(entry.mTarget));
1174         SuccessOrExit(error = mEncoder.WriteUint16(entry.mRloc16));
1175         SuccessOrExit(error = mEncoder.WriteUint8(index));
1176 
1177         switch (entry.mState)
1178         {
1179         case OT_CACHE_ENTRY_STATE_CACHED:
1180             SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_ADDRESS_CACHE_ENTRY_STATE_CACHED));
1181             break;
1182         case OT_CACHE_ENTRY_STATE_SNOOPED:
1183             SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_ADDRESS_CACHE_ENTRY_STATE_SNOOPED));
1184             break;
1185         case OT_CACHE_ENTRY_STATE_QUERY:
1186             SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_ADDRESS_CACHE_ENTRY_STATE_QUERY));
1187             break;
1188         case OT_CACHE_ENTRY_STATE_RETRY_QUERY:
1189             SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_ADDRESS_CACHE_ENTRY_STATE_RETRY_QUERY));
1190             break;
1191         }
1192 
1193         SuccessOrExit(error = mEncoder.OpenStruct());
1194 
1195         if (entry.mState == OT_CACHE_ENTRY_STATE_CACHED)
1196         {
1197             SuccessOrExit(error = mEncoder.WriteBool(entry.mValidLastTrans));
1198             SuccessOrExit(error = mEncoder.WriteUint32(entry.mLastTransTime));
1199             SuccessOrExit(error = mEncoder.WriteIp6Address(entry.mMeshLocalEid));
1200         }
1201 
1202         SuccessOrExit(error = mEncoder.CloseStruct());
1203 
1204         SuccessOrExit(error = mEncoder.OpenStruct());
1205 
1206         if (entry.mState != OT_CACHE_ENTRY_STATE_CACHED)
1207         {
1208             SuccessOrExit(error = mEncoder.WriteBool(entry.mCanEvict));
1209             SuccessOrExit(error = mEncoder.WriteUint16(entry.mTimeout));
1210             SuccessOrExit(error = mEncoder.WriteUint16(entry.mRetryDelay));
1211         }
1212 
1213         SuccessOrExit(error = mEncoder.CloseStruct());
1214 
1215         SuccessOrExit(error = mEncoder.CloseStruct());
1216     }
1217 
1218 exit:
1219     return error;
1220 }
1221 
1222 #if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
1223 
HandlePropertyGet(void)1224 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHILD_SUPERVISION_INTERVAL>(void)
1225 {
1226     return mEncoder.WriteUint16(otChildSupervisionGetInterval(mInstance));
1227 }
1228 
HandlePropertySet(void)1229 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHILD_SUPERVISION_INTERVAL>(void)
1230 {
1231     otError  error = OT_ERROR_NONE;
1232     uint16_t interval;
1233 
1234     SuccessOrExit(error = mDecoder.ReadUint16(interval));
1235     otChildSupervisionSetInterval(mInstance, interval);
1236 
1237 exit:
1238     return error;
1239 }
1240 
1241 #endif // OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
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