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