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