• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "instance/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 // OPENTHREAD_CONFIG_MLE_PARENT_RESPONSE_CALLBACK_API_ENABLE
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 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
194 
HandleBorderAgentMeshCoPServiceChanged(void * aContext)195 void NcpBase::HandleBorderAgentMeshCoPServiceChanged(void *aContext)
196 {
197     static_cast<NcpBase *>(aContext)->HandleBorderAgentMeshCoPServiceChanged();
198 }
199 
HandleBorderAgentMeshCoPServiceChanged(void)200 void NcpBase::HandleBorderAgentMeshCoPServiceChanged(void)
201 {
202     mChangedPropsSet.AddProperty(SPINEL_PROP_BORDER_AGENT_MESHCOP_SERVICE_STATE);
203     mUpdateChangedPropsTask.Post();
204 }
205 
206 #endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
207 
208 // ----------------------------------------------------------------------------
209 // MARK: Individual Property Handlers
210 // ----------------------------------------------------------------------------
211 
HandlePropertyGet(void)212 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_LOCAL_LEADER_WEIGHT>(void)
213 {
214     return mEncoder.WriteUint8(otThreadGetLocalLeaderWeight(mInstance));
215 }
216 
HandlePropertyGet(void)217 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_LEADER_WEIGHT>(void)
218 {
219     return mEncoder.WriteUint8(otThreadGetLeaderWeight(mInstance));
220 }
221 
HandlePropertyGet(void)222 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_CHILD_TABLE>(void)
223 {
224     otError     error = OT_ERROR_NONE;
225     otChildInfo childInfo;
226     uint16_t    maxChildren;
227 
228     maxChildren = otThreadGetMaxAllowedChildren(mInstance);
229 
230     for (uint16_t index = 0; index < maxChildren; index++)
231     {
232         if ((otThreadGetChildInfoByIndex(mInstance, index, &childInfo) != OT_ERROR_NONE) || childInfo.mIsStateRestoring)
233         {
234             continue;
235         }
236 
237         SuccessOrExit(error = mEncoder.OpenStruct());
238         SuccessOrExit(error = EncodeChildInfo(childInfo));
239         SuccessOrExit(error = mEncoder.CloseStruct());
240     }
241 
242 exit:
243     return error;
244 }
245 
HandlePropertyGet(void)246 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ROUTER_TABLE>(void)
247 {
248     otError      error = OT_ERROR_NONE;
249     otRouterInfo routerInfo;
250     uint8_t      maxRouterId;
251 
252     maxRouterId = otThreadGetMaxRouterId(mInstance);
253 
254     for (uint8_t routerId = 0; routerId <= maxRouterId; routerId++)
255     {
256         if ((otThreadGetRouterInfo(mInstance, routerId, &routerInfo) != OT_ERROR_NONE) || !routerInfo.mAllocated)
257         {
258             continue;
259         }
260 
261         SuccessOrExit(error = mEncoder.OpenStruct());
262 
263         SuccessOrExit(error = mEncoder.WriteEui64(routerInfo.mExtAddress));
264         SuccessOrExit(error = mEncoder.WriteUint16(routerInfo.mRloc16));
265         SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mRouterId));
266         SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mNextHop));
267         SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mPathCost));
268         SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mLinkQualityIn));
269         SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mLinkQualityOut));
270         SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mAge));
271         SuccessOrExit(error = mEncoder.WriteBool(routerInfo.mLinkEstablished));
272 
273         SuccessOrExit(error = mEncoder.CloseStruct());
274     }
275 
276 exit:
277     return error;
278 }
279 
HandlePropertyGet(void)280 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_CHILD_TABLE_ADDRESSES>(void)
281 {
282     otError                   error = OT_ERROR_NONE;
283     otChildInfo               childInfo;
284     uint16_t                  maxChildren;
285     otIp6Address              ip6Address;
286     otChildIp6AddressIterator iterator = OT_CHILD_IP6_ADDRESS_ITERATOR_INIT;
287 
288     maxChildren = otThreadGetMaxAllowedChildren(mInstance);
289 
290     for (uint16_t childIndex = 0; childIndex < maxChildren; childIndex++)
291     {
292         if ((otThreadGetChildInfoByIndex(mInstance, childIndex, &childInfo) != OT_ERROR_NONE) ||
293             childInfo.mIsStateRestoring)
294         {
295             continue;
296         }
297 
298         SuccessOrExit(error = mEncoder.OpenStruct());
299 
300         SuccessOrExit(error = mEncoder.WriteEui64(childInfo.mExtAddress));
301         SuccessOrExit(error = mEncoder.WriteUint16(childInfo.mRloc16));
302 
303         iterator = OT_CHILD_IP6_ADDRESS_ITERATOR_INIT;
304 
305         while (otThreadGetChildNextIp6Address(mInstance, childIndex, &iterator, &ip6Address) == OT_ERROR_NONE)
306         {
307             SuccessOrExit(error = mEncoder.WriteIp6Address(ip6Address));
308         }
309 
310         SuccessOrExit(error = mEncoder.CloseStruct());
311     }
312 
313 exit:
314     return error;
315 }
316 
HandlePropertyGet(void)317 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ROUTER_ROLE_ENABLED>(void)
318 {
319     return mEncoder.WriteBool(otThreadIsRouterEligible(mInstance));
320 }
321 
HandlePropertySet(void)322 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_ROUTER_ROLE_ENABLED>(void)
323 {
324     bool    eligible;
325     otError error = OT_ERROR_NONE;
326 
327     SuccessOrExit(error = mDecoder.ReadBool(eligible));
328 
329     error = otThreadSetRouterEligible(mInstance, eligible);
330 
331 exit:
332     return error;
333 }
334 
HandlePropertyGet(void)335 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_MAX_RETRY_NUMBER_INDIRECT>(void)
336 {
337     return mEncoder.WriteUint8(otLinkGetMaxFrameRetriesIndirect(mInstance));
338 }
339 
HandlePropertySet(void)340 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_MAX_RETRY_NUMBER_INDIRECT>(void)
341 {
342     uint8_t maxFrameRetriesIndirect;
343     otError error = OT_ERROR_NONE;
344 
345     SuccessOrExit(error = mDecoder.ReadUint8(maxFrameRetriesIndirect));
346     otLinkSetMaxFrameRetriesIndirect(mInstance, maxFrameRetriesIndirect);
347 
348 exit:
349     return error;
350 }
351 
352 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
HandlePropertyGet(void)353 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_DOMAIN_NAME>(void)
354 {
355     return mEncoder.WriteUtf8(otThreadGetDomainName(mInstance));
356 }
357 
HandlePropertySet(void)358 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_DOMAIN_NAME>(void)
359 {
360     otError     error = OT_ERROR_NONE;
361     const char *domainName;
362 
363     SuccessOrExit(error = mDecoder.ReadUtf8(domainName));
364 
365     error = otThreadSetDomainName(mInstance, domainName);
366 
367 exit:
368     return error;
369 }
370 #endif
371 
372 #if OPENTHREAD_CONFIG_DUA_ENABLE
HandlePropertyGet(void)373 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_DUA_ID>(void)
374 {
375     const otIp6InterfaceIdentifier *iid   = otThreadGetFixedDuaInterfaceIdentifier(mInstance);
376     otError                         error = OT_ERROR_NONE;
377 
378     if (iid == nullptr)
379     {
380         // send empty response
381     }
382     else
383     {
384         for (uint8_t i : iid->mFields.m8)
385         {
386             SuccessOrExit(error = mEncoder.WriteUint8(i));
387         }
388     }
389 
390 exit:
391     return error;
392 }
393 
HandlePropertySet(void)394 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_DUA_ID>(void)
395 {
396     otError error = OT_ERROR_NONE;
397 
398     if (mDecoder.GetRemainingLength() == 0)
399     {
400         SuccessOrExit(error = otThreadSetFixedDuaInterfaceIdentifier(mInstance, nullptr));
401     }
402     else
403     {
404         otIp6InterfaceIdentifier iid;
405 
406         for (uint8_t &i : iid.mFields.m8)
407         {
408             SuccessOrExit(error = mDecoder.ReadUint8(i));
409         }
410 
411         SuccessOrExit(error = otThreadSetFixedDuaInterfaceIdentifier(mInstance, &iid));
412     }
413 
414 exit:
415     return error;
416 }
417 #endif // OPENTHREAD_CONFIG_DUA_ENABLE
418 
419 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
HandlePropertyGet(void)420 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_STATE>(void)
421 {
422     uint8_t state = SPINEL_THREAD_BACKBONE_ROUTER_STATE_DISABLED;
423 
424     switch (otBackboneRouterGetState(mInstance))
425     {
426     case OT_BACKBONE_ROUTER_STATE_DISABLED:
427         state = SPINEL_THREAD_BACKBONE_ROUTER_STATE_DISABLED;
428         break;
429 
430     case OT_BACKBONE_ROUTER_STATE_SECONDARY:
431         state = SPINEL_THREAD_BACKBONE_ROUTER_STATE_SECONDARY;
432         break;
433 
434     case OT_BACKBONE_ROUTER_STATE_PRIMARY:
435         state = SPINEL_THREAD_BACKBONE_ROUTER_STATE_PRIMARY;
436         break;
437     }
438 
439     return mEncoder.WriteUint8(state);
440 }
441 
HandlePropertySet(void)442 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_STATE>(void)
443 {
444     uint8_t state;
445     otError error = OT_ERROR_NONE;
446 
447     SuccessOrExit(error = mDecoder.ReadUint8(state));
448 
449     if (state)
450     {
451         otBackboneRouterSetEnabled(mInstance, true);
452     }
453     else
454     {
455         otBackboneRouterSetEnabled(mInstance, false);
456     }
457 
458 exit:
459     return error;
460 }
461 
HandlePropertyGet(void)462 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_CONFIG>(void)
463 {
464     otError                error = OT_ERROR_NONE;
465     otBackboneRouterConfig bbrConfig;
466 
467     otBackboneRouterGetConfig(mInstance, &bbrConfig);
468 
469     SuccessOrExit(error = mEncoder.WriteUint16(bbrConfig.mReregistrationDelay));
470     SuccessOrExit(error = mEncoder.WriteUint32(bbrConfig.mMlrTimeout));
471     SuccessOrExit(error = mEncoder.WriteUint8(bbrConfig.mSequenceNumber));
472 
473 exit:
474     return error;
475 }
476 
HandlePropertySet(void)477 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_CONFIG>(void)
478 {
479     otError                error = OT_ERROR_NONE;
480     otBackboneRouterConfig bbrConfig;
481 
482     SuccessOrExit(error = mDecoder.ReadUint16(bbrConfig.mReregistrationDelay));
483     SuccessOrExit(error = mDecoder.ReadUint32(bbrConfig.mMlrTimeout));
484     SuccessOrExit(error = mDecoder.ReadUint8(bbrConfig.mSequenceNumber));
485 
486     SuccessOrExit(error = otBackboneRouterSetConfig(mInstance, &bbrConfig));
487 
488 exit:
489     return error;
490 }
491 
HandlePropertySet(void)492 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_REGISTER>(void)
493 {
494     return otBackboneRouterRegister(mInstance);
495 }
496 
HandlePropertyGet(void)497 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_REGISTRATION_JITTER>(void)
498 {
499     uint8_t jitter = otBackboneRouterGetRegistrationJitter(mInstance);
500 
501     return mEncoder.WriteUint8(jitter);
502 }
503 
HandlePropertySet(void)504 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_REGISTRATION_JITTER>(void)
505 {
506     otError error = OT_ERROR_NONE;
507     uint8_t jitter;
508 
509     SuccessOrExit(error = mDecoder.ReadUint8(jitter));
510 
511     otBackboneRouterSetRegistrationJitter(mInstance, jitter);
512 
513 exit:
514     return error;
515 }
516 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
517 
HandlePropertyGet(void)518 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_PSKC>(void)
519 {
520     Pskc pskc;
521 
522     otThreadGetPskc(mInstance, &pskc);
523 
524     return mEncoder.WriteData(pskc.m8, sizeof(spinel_net_pskc_t));
525 }
526 
HandlePropertySet(void)527 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_PSKC>(void)
528 {
529     const uint8_t *ptr = nullptr;
530     uint16_t       len;
531     otError        error = OT_ERROR_NONE;
532 
533     SuccessOrExit(error = mDecoder.ReadData(ptr, len));
534 
535     VerifyOrExit(len == sizeof(spinel_net_pskc_t), error = OT_ERROR_PARSE);
536 
537     error = otThreadSetPskc(mInstance, reinterpret_cast<const otPskc *>(ptr));
538 
539 exit:
540     return error;
541 }
542 
543 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
HandlePropertySet(void)544 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_PARTITION_ID>(void)
545 {
546     uint32_t partitionId = 0;
547     otError  error       = OT_ERROR_NONE;
548 
549     SuccessOrExit(error = mDecoder.ReadUint32(partitionId));
550 
551     otThreadSetPreferredLeaderPartitionId(mInstance, partitionId);
552 
553 exit:
554     return error;
555 }
556 #endif
557 
HandlePropertyGet(void)558 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_CHILD_COUNT_MAX>(void)
559 {
560     return mEncoder.WriteUint8(static_cast<uint8_t>(otThreadGetMaxAllowedChildren(mInstance)));
561 }
562 
HandlePropertySet(void)563 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_CHILD_COUNT_MAX>(void)
564 {
565     uint8_t maxChildren = 0;
566     otError error       = OT_ERROR_NONE;
567 
568     SuccessOrExit(error = mDecoder.ReadUint8(maxChildren));
569 
570     error = otThreadSetMaxAllowedChildren(mInstance, maxChildren);
571 
572 exit:
573     return error;
574 }
575 
HandlePropertyGet(void)576 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ROUTER_UPGRADE_THRESHOLD>(void)
577 {
578     return mEncoder.WriteUint8(otThreadGetRouterUpgradeThreshold(mInstance));
579 }
580 
HandlePropertySet(void)581 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_ROUTER_UPGRADE_THRESHOLD>(void)
582 {
583     uint8_t threshold = 0;
584     otError error     = OT_ERROR_NONE;
585 
586     SuccessOrExit(error = mDecoder.ReadUint8(threshold));
587 
588     otThreadSetRouterUpgradeThreshold(mInstance, threshold);
589 
590 exit:
591     return error;
592 }
593 
HandlePropertyGet(void)594 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ROUTER_DOWNGRADE_THRESHOLD>(void)
595 {
596     return mEncoder.WriteUint8(otThreadGetRouterDowngradeThreshold(mInstance));
597 }
598 
HandlePropertySet(void)599 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_ROUTER_DOWNGRADE_THRESHOLD>(void)
600 {
601     uint8_t threshold = 0;
602     otError error     = OT_ERROR_NONE;
603 
604     SuccessOrExit(error = mDecoder.ReadUint8(threshold));
605 
606     otThreadSetRouterDowngradeThreshold(mInstance, threshold);
607 
608 exit:
609     return error;
610 }
611 
HandlePropertyGet(void)612 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ROUTER_SELECTION_JITTER>(void)
613 {
614     return mEncoder.WriteUint8(otThreadGetRouterSelectionJitter(mInstance));
615 }
616 
HandlePropertySet(void)617 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_ROUTER_SELECTION_JITTER>(void)
618 {
619     uint8_t jitter = 0;
620     otError error  = OT_ERROR_NONE;
621 
622     SuccessOrExit(error = mDecoder.ReadUint8(jitter));
623 
624     otThreadSetRouterSelectionJitter(mInstance, jitter);
625 
626 exit:
627     return error;
628 }
629 
HandlePropertyGet(void)630 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_CONTEXT_REUSE_DELAY>(void)
631 {
632     return mEncoder.WriteUint32(otThreadGetContextIdReuseDelay(mInstance));
633 }
634 
HandlePropertySet(void)635 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_CONTEXT_REUSE_DELAY>(void)
636 {
637     uint32_t delay = 0;
638     otError  error = OT_ERROR_NONE;
639 
640     SuccessOrExit(error = mDecoder.ReadUint32(delay));
641 
642     otThreadSetContextIdReuseDelay(mInstance, delay);
643 
644 exit:
645     return error;
646 }
647 
HandlePropertyGet(void)648 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_NETWORK_ID_TIMEOUT>(void)
649 {
650     return mEncoder.WriteUint8(otThreadGetNetworkIdTimeout(mInstance));
651 }
652 
HandlePropertySet(void)653 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_NETWORK_ID_TIMEOUT>(void)
654 {
655     uint8_t timeout = 0;
656     otError error   = OT_ERROR_NONE;
657 
658     SuccessOrExit(error = mDecoder.ReadUint8(timeout));
659 
660     otThreadSetNetworkIdTimeout(mInstance, timeout);
661 
662 exit:
663     return error;
664 }
665 
HandlePropertyGet(void)666 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_NEW_DATASET>(void)
667 {
668     otError              error;
669     otOperationalDataset dataset;
670 
671     error = otDatasetCreateNewNetwork(mInstance, &dataset);
672 
673     if (error == OT_ERROR_NONE)
674     {
675         error = EncodeOperationalDataset(dataset);
676     }
677     else
678     {
679         error = mEncoder.OverwriteWithLastStatusError(ThreadErrorToSpinelStatus(error));
680     }
681 
682     return error;
683 }
684 
685 #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
686 
HandlePropertyGet(void)687 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MESHCOP_COMMISSIONER_STATE>(void)
688 {
689     uint8_t state = SPINEL_MESHCOP_COMMISSIONER_STATE_DISABLED;
690 
691     switch (otCommissionerGetState(mInstance))
692     {
693     case OT_COMMISSIONER_STATE_DISABLED:
694         state = SPINEL_MESHCOP_COMMISSIONER_STATE_DISABLED;
695         break;
696 
697     case OT_COMMISSIONER_STATE_PETITION:
698         state = SPINEL_MESHCOP_COMMISSIONER_STATE_PETITION;
699         break;
700 
701     case OT_COMMISSIONER_STATE_ACTIVE:
702         state = SPINEL_MESHCOP_COMMISSIONER_STATE_ACTIVE;
703         break;
704     }
705 
706     return mEncoder.WriteUint8(state);
707 }
708 
HandlePropertySet(void)709 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_STATE>(void)
710 {
711     uint8_t state;
712     otError error = OT_ERROR_NONE;
713 
714     SuccessOrExit(error = mDecoder.ReadUint8(state));
715 
716     switch (state)
717     {
718     case SPINEL_MESHCOP_COMMISSIONER_STATE_DISABLED:
719         error = otCommissionerStop(mInstance);
720         break;
721 
722     case SPINEL_MESHCOP_COMMISSIONER_STATE_ACTIVE:
723         error = otCommissionerStart(mInstance, nullptr, nullptr, nullptr);
724         break;
725 
726     default:
727         error = OT_ERROR_INVALID_ARGS;
728         break;
729     }
730 
731 exit:
732     return error;
733 }
734 
HandlePropertyGet(void)735 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MESHCOP_COMMISSIONER_JOINERS>(void)
736 {
737     otError      error = OT_ERROR_NONE;
738     uint16_t     iter  = 0;
739     otJoinerInfo joinerInfo;
740 
741     while (otCommissionerGetNextJoinerInfo(mInstance, &iter, &joinerInfo) == OT_ERROR_NONE)
742     {
743         SuccessOrExit(error = mEncoder.OpenStruct());
744 
745         SuccessOrExit(error = mEncoder.OpenStruct()); // Joiner Id (any, EUI64 or a Joiner Discerner) struct
746 
747         switch (joinerInfo.mType)
748         {
749         case OT_JOINER_INFO_TYPE_ANY:
750             break;
751 
752         case OT_JOINER_INFO_TYPE_EUI64:
753             SuccessOrExit(error = mEncoder.WriteEui64(joinerInfo.mSharedId.mEui64));
754             break;
755 
756         case OT_JOINER_INFO_TYPE_DISCERNER:
757             SuccessOrExit(error = mEncoder.WriteUint8(joinerInfo.mSharedId.mDiscerner.mLength));
758             SuccessOrExit(error = mEncoder.WriteUint64(joinerInfo.mSharedId.mDiscerner.mValue));
759             break;
760         }
761 
762         SuccessOrExit(error = mEncoder.CloseStruct());
763 
764         SuccessOrExit(error = mEncoder.WriteUint32(joinerInfo.mExpirationTime));
765         SuccessOrExit(error = mEncoder.WriteUtf8(joinerInfo.mPskd.m8));
766 
767         SuccessOrExit(error = mEncoder.CloseStruct());
768     }
769 
770 exit:
771     return error;
772 }
773 
HandlePropertyInsert(void)774 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_MESHCOP_COMMISSIONER_JOINERS>(void)
775 {
776     otError             error = OT_ERROR_NONE;
777     otJoinerDiscerner   discerner;
778     bool                withDiscerner = false;
779     const otExtAddress *eui64;
780     uint32_t            timeout;
781     const char         *psk;
782 
783     SuccessOrExit(error = mDecoder.OpenStruct());
784 
785     switch (mDecoder.GetRemainingLengthInStruct())
786     {
787     case 0:
788         // Empty struct indicates any joiner
789         eui64 = nullptr;
790         break;
791 
792     case sizeof(spinel_eui64_t):
793         SuccessOrExit(error = mDecoder.ReadEui64(eui64));
794         break;
795 
796     default:
797         SuccessOrExit(error = mDecoder.ReadUint8(discerner.mLength));
798         SuccessOrExit(error = mDecoder.ReadUint64(discerner.mValue));
799         withDiscerner = true;
800         break;
801     }
802 
803     SuccessOrExit(error = mDecoder.CloseStruct());
804 
805     SuccessOrExit(error = mDecoder.ReadUint32(timeout));
806     SuccessOrExit(error = mDecoder.ReadUtf8(psk));
807 
808     if (withDiscerner)
809     {
810         error = otCommissionerAddJoinerWithDiscerner(mInstance, &discerner, psk, timeout);
811     }
812     else
813     {
814         error = otCommissionerAddJoiner(mInstance, eui64, psk, timeout);
815     }
816 
817 exit:
818     return error;
819 }
820 
HandlePropertyRemove(void)821 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_MESHCOP_COMMISSIONER_JOINERS>(void)
822 {
823     otError             error = OT_ERROR_NONE;
824     otJoinerDiscerner   discerner;
825     bool                withDiscerner = false;
826     const otExtAddress *eui64;
827 
828     SuccessOrExit(error = mDecoder.OpenStruct());
829 
830     switch (mDecoder.GetRemainingLengthInStruct())
831     {
832     case 0:
833         // Empty struct indicates any joiner
834         eui64 = nullptr;
835         break;
836 
837     case sizeof(spinel_eui64_t):
838         SuccessOrExit(error = mDecoder.ReadEui64(eui64));
839         break;
840 
841     default:
842         SuccessOrExit(error = mDecoder.ReadUint8(discerner.mLength));
843         SuccessOrExit(error = mDecoder.ReadUint64(discerner.mValue));
844         withDiscerner = true;
845         break;
846     }
847 
848     SuccessOrExit(error = mDecoder.CloseStruct());
849 
850     if (withDiscerner)
851     {
852         error = otCommissionerRemoveJoinerWithDiscerner(mInstance, &discerner);
853     }
854     else
855     {
856         error = otCommissionerRemoveJoiner(mInstance, eui64);
857     }
858 
859 exit:
860     return error;
861 }
862 
HandlePropertyGet(void)863 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MESHCOP_COMMISSIONER_PROVISIONING_URL>(void)
864 {
865     return mEncoder.WriteUtf8(otCommissionerGetProvisioningUrl(mInstance));
866 }
867 
HandlePropertySet(void)868 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_PROVISIONING_URL>(void)
869 {
870     otError     error = OT_ERROR_NONE;
871     const char *url;
872 
873     SuccessOrExit(error = mDecoder.ReadUtf8(url));
874 
875     error = otCommissionerSetProvisioningUrl(mInstance, url);
876 
877 exit:
878     return error;
879 }
880 
HandlePropertyGet(void)881 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MESHCOP_COMMISSIONER_SESSION_ID>(void)
882 {
883     return mEncoder.WriteUint16(otCommissionerGetSessionId(mInstance));
884 }
885 
HandlePropertySet(void)886 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_ANNOUNCE_BEGIN>(void)
887 {
888     otError             error = OT_ERROR_NONE;
889     uint32_t            channelMask;
890     uint8_t             count;
891     uint16_t            period;
892     const otIp6Address *address;
893 
894     SuccessOrExit(error = mDecoder.ReadUint32(channelMask));
895     SuccessOrExit(error = mDecoder.ReadUint8(count));
896     SuccessOrExit(error = mDecoder.ReadUint16(period));
897     SuccessOrExit(error = mDecoder.ReadIp6Address(address));
898 
899     error = otCommissionerAnnounceBegin(mInstance, channelMask, count, period, address);
900 
901 exit:
902     return error;
903 }
904 
HandlePropertySet(void)905 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_ENERGY_SCAN>(void)
906 {
907     otError             error = OT_ERROR_NONE;
908     uint32_t            channelMask;
909     uint8_t             count;
910     uint16_t            period;
911     uint16_t            scanDuration;
912     const otIp6Address *address;
913 
914     SuccessOrExit(error = mDecoder.ReadUint32(channelMask));
915     SuccessOrExit(error = mDecoder.ReadUint8(count));
916     SuccessOrExit(error = mDecoder.ReadUint16(period));
917     SuccessOrExit(error = mDecoder.ReadUint16(scanDuration));
918     SuccessOrExit(error = mDecoder.ReadIp6Address(address));
919 
920     error = otCommissionerEnergyScan(mInstance, channelMask, count, period, scanDuration, address,
921                                      &NcpBase::HandleCommissionerEnergyReport_Jump, this);
922 
923 exit:
924     return error;
925 }
926 
HandleCommissionerEnergyReport_Jump(uint32_t aChannelMask,const uint8_t * aEnergyData,uint8_t aLength,void * aContext)927 void NcpBase::HandleCommissionerEnergyReport_Jump(uint32_t       aChannelMask,
928                                                   const uint8_t *aEnergyData,
929                                                   uint8_t        aLength,
930                                                   void          *aContext)
931 {
932     static_cast<NcpBase *>(aContext)->HandleCommissionerEnergyReport(aChannelMask, aEnergyData, aLength);
933 }
934 
HandleCommissionerEnergyReport(uint32_t aChannelMask,const uint8_t * aEnergyData,uint8_t aLength)935 void NcpBase::HandleCommissionerEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyData, uint8_t aLength)
936 {
937     otError error = OT_ERROR_NONE;
938 
939     SuccessOrExit(error = mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_PROP_VALUE_INSERTED,
940                                               SPINEL_PROP_MESHCOP_COMMISSIONER_ENERGY_SCAN_RESULT));
941     SuccessOrExit(error = mEncoder.WriteUint32(aChannelMask));
942     SuccessOrExit(error = mEncoder.WriteDataWithLen(aEnergyData, aLength));
943     SuccessOrExit(error = mEncoder.EndFrame());
944 
945 exit:
946 
947     if (error != OT_ERROR_NONE)
948     {
949         mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM);
950         mUpdateChangedPropsTask.Post();
951     }
952 }
953 
HandlePropertySet(void)954 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_PAN_ID_QUERY>(void)
955 {
956     otError             error = OT_ERROR_NONE;
957     uint16_t            panId;
958     uint32_t            channelMask;
959     const otIp6Address *address;
960 
961     SuccessOrExit(error = mDecoder.ReadUint16(panId));
962     SuccessOrExit(error = mDecoder.ReadUint32(channelMask));
963     SuccessOrExit(error = mDecoder.ReadIp6Address(address));
964 
965     error = otCommissionerPanIdQuery(mInstance, panId, channelMask, address,
966                                      &NcpBase::HandleCommissionerPanIdConflict_Jump, this);
967 
968 exit:
969     return error;
970 }
971 
HandleCommissionerPanIdConflict_Jump(uint16_t aPanId,uint32_t aChannelMask,void * aContext)972 void NcpBase::HandleCommissionerPanIdConflict_Jump(uint16_t aPanId, uint32_t aChannelMask, void *aContext)
973 {
974     static_cast<NcpBase *>(aContext)->HandleCommissionerPanIdConflict(aPanId, aChannelMask);
975 }
976 
HandleCommissionerPanIdConflict(uint16_t aPanId,uint32_t aChannelMask)977 void NcpBase::HandleCommissionerPanIdConflict(uint16_t aPanId, uint32_t aChannelMask)
978 {
979     otError error = OT_ERROR_NONE;
980 
981     SuccessOrExit(error = mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_PROP_VALUE_INSERTED,
982                                               SPINEL_PROP_MESHCOP_COMMISSIONER_PAN_ID_CONFLICT_RESULT));
983 
984     SuccessOrExit(error = mEncoder.WriteUint16(aPanId));
985     SuccessOrExit(error = mEncoder.WriteUint32(aChannelMask));
986     SuccessOrExit(error = mEncoder.EndFrame());
987 
988 exit:
989 
990     if (error != OT_ERROR_NONE)
991     {
992         mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM);
993         mUpdateChangedPropsTask.Post();
994     }
995 }
996 
HandlePropertySet(void)997 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_MGMT_GET>(void)
998 {
999     otError        error = OT_ERROR_NONE;
1000     const uint8_t *tlvs;
1001     uint16_t       length;
1002 
1003     SuccessOrExit(error = mDecoder.ReadDataWithLen(tlvs, length));
1004     VerifyOrExit(length <= 255, error = OT_ERROR_INVALID_ARGS);
1005 
1006     error = otCommissionerSendMgmtGet(mInstance, tlvs, static_cast<uint8_t>(length));
1007 
1008 exit:
1009     return error;
1010 }
1011 
HandlePropertySet(void)1012 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_COMMISSIONER_MGMT_SET>(void)
1013 {
1014     otError                error = OT_ERROR_NONE;
1015     const uint8_t         *tlvs;
1016     uint16_t               length;
1017     otCommissioningDataset dataset;
1018 
1019     SuccessOrExit(error = mDecoder.ReadDataWithLen(tlvs, length));
1020     VerifyOrExit(length <= 255, error = OT_ERROR_INVALID_ARGS);
1021 
1022     memset(&dataset, 0, sizeof(otCommissioningDataset));
1023     error = otCommissionerSendMgmtSet(mInstance, &dataset, tlvs, static_cast<uint8_t>(length));
1024 
1025 exit:
1026     return error;
1027 }
1028 
HandlePropertySet_SPINEL_PROP_MESHCOP_COMMISSIONER_GENERATE_PSKC(uint8_t aHeader)1029 otError NcpBase::HandlePropertySet_SPINEL_PROP_MESHCOP_COMMISSIONER_GENERATE_PSKC(uint8_t aHeader)
1030 {
1031     otError        error = OT_ERROR_NONE;
1032     const char    *passPhrase;
1033     const char    *networkName;
1034     const uint8_t *extPanIdData;
1035     uint16_t       length;
1036     otPskc         pskc;
1037 
1038     SuccessOrExit(error = mDecoder.ReadUtf8(passPhrase));
1039     SuccessOrExit(error = mDecoder.ReadUtf8(networkName));
1040     SuccessOrExit(error = mDecoder.ReadDataWithLen(extPanIdData, length));
1041     VerifyOrExit(length == sizeof(spinel_net_xpanid_t), error = OT_ERROR_PARSE);
1042 
1043     SuccessOrExit(error = otDatasetGeneratePskc(passPhrase, reinterpret_cast<const otNetworkName *>(networkName),
1044                                                 reinterpret_cast<const otExtendedPanId *>(extPanIdData), &pskc));
1045 
1046     SuccessOrExit(
1047         error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_MESHCOP_COMMISSIONER_GENERATE_PSKC));
1048     SuccessOrExit(error = mEncoder.WriteData(pskc.m8, sizeof(pskc)));
1049     SuccessOrExit(error = mEncoder.EndFrame());
1050 
1051 exit:
1052     return error;
1053 }
1054 
1055 // SPINEL_PROP_THREAD_COMMISSIONER_ENABLED is replaced by SPINEL_PROP_MESHCOP_COMMISSIONER_STATE. Please use the new
1056 // property. The old property/implementation remains for backward compatibility.
1057 
HandlePropertyGet(void)1058 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_COMMISSIONER_ENABLED>(void)
1059 {
1060     return mEncoder.WriteBool(otCommissionerGetState(mInstance) == OT_COMMISSIONER_STATE_ACTIVE);
1061 }
1062 
HandlePropertySet_SPINEL_PROP_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader)1063 otError NcpBase::HandlePropertySet_SPINEL_PROP_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader)
1064 {
1065     bool    enabled = false;
1066     otError error   = OT_ERROR_NONE;
1067 
1068     SuccessOrExit(error = mDecoder.ReadBool(enabled));
1069 
1070     if (!enabled)
1071     {
1072         error = otCommissionerStop(mInstance);
1073     }
1074     else
1075     {
1076         error = otCommissionerStart(mInstance, nullptr, nullptr, nullptr);
1077     }
1078 
1079 exit:
1080     return PrepareLastStatusResponse(aHeader, ThreadErrorToSpinelStatus(error));
1081 }
1082 
1083 // SPINEL_PROP_THREAD_JOINERS is replaced by SPINEL_PROP_MESHCOP_COMMISSIONER_JOINERS. Please us the new property.
1084 // The old property/implementation remains for backward compatibility.
1085 
HandlePropertyInsert(void)1086 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_THREAD_JOINERS>(void)
1087 {
1088     otError             error         = OT_ERROR_NONE;
1089     const otExtAddress *eui64         = nullptr;
1090     const char         *pskd          = nullptr;
1091     uint32_t            joinerTimeout = 0;
1092 
1093     SuccessOrExit(error = mDecoder.ReadUtf8(pskd));
1094     SuccessOrExit(error = mDecoder.ReadUint32(joinerTimeout));
1095 
1096     if (mDecoder.ReadEui64(eui64) != OT_ERROR_NONE)
1097     {
1098         eui64 = nullptr;
1099     }
1100 
1101     error = otCommissionerAddJoiner(mInstance, eui64, pskd, joinerTimeout);
1102 
1103 exit:
1104     return error;
1105 }
1106 #endif // OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
1107 
HandlePropertySet(void)1108 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_LOCAL_LEADER_WEIGHT>(void)
1109 {
1110     uint8_t weight;
1111     otError error = OT_ERROR_NONE;
1112 
1113     SuccessOrExit(error = mDecoder.ReadUint8(weight));
1114 
1115     otThreadSetLocalLeaderWeight(mInstance, weight);
1116 
1117 exit:
1118     return error;
1119 }
1120 
1121 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
1122 
HandlePropertyGet(void)1123 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_STEERING_DATA>(void)
1124 {
1125     return mEncoder.WriteEui64(mSteeringDataAddress);
1126 }
1127 
HandlePropertySet(void)1128 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_STEERING_DATA>(void)
1129 {
1130     otError error = OT_ERROR_NONE;
1131 
1132     SuccessOrExit(error = mDecoder.ReadEui64(mSteeringDataAddress));
1133 
1134     otThreadSetSteeringData(mInstance, &mSteeringDataAddress);
1135 
1136 exit:
1137     return error;
1138 }
1139 #endif // #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
1140 
HandlePropertyGet(void)1141 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_PREFERRED_ROUTER_ID>(void)
1142 {
1143     return mEncoder.WriteUint8(mPreferredRouteId);
1144 }
1145 
HandlePropertySet(void)1146 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_PREFERRED_ROUTER_ID>(void)
1147 {
1148     otError error = OT_ERROR_NONE;
1149 
1150     SuccessOrExit(error = mDecoder.ReadUint8(mPreferredRouteId));
1151 
1152     SuccessOrExit(error = otThreadSetPreferredRouterId(mInstance, mPreferredRouteId));
1153 
1154 exit:
1155     return error;
1156 }
1157 
HandlePropertyRemove(void)1158 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_THREAD_ACTIVE_ROUTER_IDS>(void)
1159 {
1160     otError error = OT_ERROR_NONE;
1161     uint8_t routerId;
1162 
1163     SuccessOrExit(error = mDecoder.ReadUint8(routerId));
1164 
1165     error = otThreadReleaseRouterId(mInstance, routerId);
1166 
1167     // `INVALID_STATE` is returned when router ID was not allocated (i.e. not in the list)
1168     // in such a case, the "remove" operation can be considered successful.
1169 
1170     if (error == OT_ERROR_INVALID_STATE)
1171     {
1172         error = OT_ERROR_NONE;
1173     }
1174 
1175 exit:
1176     return error;
1177 }
1178 
HandlePropertyGet(void)1179 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ADDRESS_CACHE_TABLE>(void)
1180 {
1181     otError              error = OT_ERROR_NONE;
1182     otCacheEntryIterator iterator;
1183     otCacheEntryInfo     entry;
1184 
1185     memset(&iterator, 0, sizeof(iterator));
1186 
1187     for (uint8_t index = 0;; index++)
1188     {
1189         SuccessOrExit(otThreadGetNextCacheEntry(mInstance, &entry, &iterator));
1190 
1191         SuccessOrExit(error = mEncoder.OpenStruct());
1192         SuccessOrExit(error = mEncoder.WriteIp6Address(entry.mTarget));
1193         SuccessOrExit(error = mEncoder.WriteUint16(entry.mRloc16));
1194         SuccessOrExit(error = mEncoder.WriteUint8(index));
1195 
1196         switch (entry.mState)
1197         {
1198         case OT_CACHE_ENTRY_STATE_CACHED:
1199             SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_ADDRESS_CACHE_ENTRY_STATE_CACHED));
1200             break;
1201         case OT_CACHE_ENTRY_STATE_SNOOPED:
1202             SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_ADDRESS_CACHE_ENTRY_STATE_SNOOPED));
1203             break;
1204         case OT_CACHE_ENTRY_STATE_QUERY:
1205             SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_ADDRESS_CACHE_ENTRY_STATE_QUERY));
1206             break;
1207         case OT_CACHE_ENTRY_STATE_RETRY_QUERY:
1208             SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_ADDRESS_CACHE_ENTRY_STATE_RETRY_QUERY));
1209             break;
1210         }
1211 
1212         SuccessOrExit(error = mEncoder.OpenStruct());
1213 
1214         if (entry.mState == OT_CACHE_ENTRY_STATE_CACHED)
1215         {
1216             SuccessOrExit(error = mEncoder.WriteBool(entry.mValidLastTrans));
1217             SuccessOrExit(error = mEncoder.WriteUint32(entry.mLastTransTime));
1218             SuccessOrExit(error = mEncoder.WriteIp6Address(entry.mMeshLocalEid));
1219         }
1220 
1221         SuccessOrExit(error = mEncoder.CloseStruct());
1222 
1223         SuccessOrExit(error = mEncoder.OpenStruct());
1224 
1225         if (entry.mState != OT_CACHE_ENTRY_STATE_CACHED)
1226         {
1227             SuccessOrExit(error = mEncoder.WriteBool(entry.mCanEvict));
1228             SuccessOrExit(error = mEncoder.WriteUint16(entry.mRampDown ? 0 : entry.mTimeout));
1229             SuccessOrExit(error = mEncoder.WriteUint16(entry.mRetryDelay));
1230         }
1231 
1232         SuccessOrExit(error = mEncoder.CloseStruct());
1233 
1234         SuccessOrExit(error = mEncoder.CloseStruct());
1235     }
1236 
1237 exit:
1238     return error;
1239 }
1240 
HandlePropertyGet(void)1241 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHILD_SUPERVISION_INTERVAL>(void)
1242 {
1243     return mEncoder.WriteUint16(otChildSupervisionGetInterval(mInstance));
1244 }
1245 
HandlePropertySet(void)1246 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHILD_SUPERVISION_INTERVAL>(void)
1247 {
1248     otError  error = OT_ERROR_NONE;
1249     uint16_t interval;
1250 
1251     SuccessOrExit(error = mDecoder.ReadUint16(interval));
1252     otChildSupervisionSetInterval(mInstance, interval);
1253 
1254 exit:
1255     return error;
1256 }
1257 
1258 #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE
1259 
HandlePropertyGet(void)1260 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL>(void)
1261 {
1262     return mEncoder.WriteUint8(otChannelManagerGetRequestedChannel(mInstance));
1263 }
1264 
HandlePropertySet(void)1265 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL>(void)
1266 {
1267     uint8_t channel;
1268     otError error = OT_ERROR_NONE;
1269 
1270     SuccessOrExit(error = mDecoder.ReadUint8(channel));
1271 
1272     otChannelManagerRequestChannelChange(mInstance, channel);
1273 
1274 exit:
1275     return error;
1276 }
1277 
HandlePropertyGet(void)1278 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MANAGER_DELAY>(void)
1279 {
1280     return mEncoder.WriteUint16(otChannelManagerGetDelay(mInstance));
1281 }
1282 
HandlePropertySet(void)1283 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHANNEL_MANAGER_DELAY>(void)
1284 {
1285     uint16_t delay;
1286     otError  error = OT_ERROR_NONE;
1287 
1288     SuccessOrExit(error = mDecoder.ReadUint16(delay));
1289 
1290     error = otChannelManagerSetDelay(mInstance, delay);
1291 
1292 exit:
1293     return error;
1294 }
1295 
HandlePropertyGet(void)1296 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MANAGER_SUPPORTED_CHANNELS>(void)
1297 {
1298     return EncodeChannelMask(otChannelManagerGetSupportedChannels(mInstance));
1299 }
1300 
HandlePropertySet(void)1301 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHANNEL_MANAGER_SUPPORTED_CHANNELS>(void)
1302 {
1303     uint32_t channelMask = 0;
1304     otError  error       = OT_ERROR_NONE;
1305 
1306     SuccessOrExit(error = DecodeChannelMask(channelMask));
1307     otChannelManagerSetSupportedChannels(mInstance, channelMask);
1308 
1309 exit:
1310     return error;
1311 }
1312 
HandlePropertyGet(void)1313 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MANAGER_FAVORED_CHANNELS>(void)
1314 {
1315     return EncodeChannelMask(otChannelManagerGetFavoredChannels(mInstance));
1316 }
1317 
HandlePropertySet(void)1318 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHANNEL_MANAGER_FAVORED_CHANNELS>(void)
1319 {
1320     uint32_t channelMask = 0;
1321     otError  error       = OT_ERROR_NONE;
1322 
1323     SuccessOrExit(error = DecodeChannelMask(channelMask));
1324     otChannelManagerSetFavoredChannels(mInstance, channelMask);
1325 
1326 exit:
1327     return error;
1328 }
1329 
HandlePropertyGet(void)1330 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MANAGER_CHANNEL_SELECT>(void)
1331 {
1332     return mEncoder.WriteBool(false);
1333 }
1334 
HandlePropertySet(void)1335 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHANNEL_MANAGER_CHANNEL_SELECT>(void)
1336 {
1337     bool    skipQualityCheck = false;
1338     otError error            = OT_ERROR_NONE;
1339 
1340     SuccessOrExit(error = mDecoder.ReadBool(skipQualityCheck));
1341     error = otChannelManagerRequestChannelSelect(mInstance, skipQualityCheck);
1342 
1343 exit:
1344     return error;
1345 }
1346 
HandlePropertyGet(void)1347 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_ENABLED>(void)
1348 {
1349     return mEncoder.WriteBool(otChannelManagerGetAutoChannelSelectionEnabled(mInstance));
1350 }
1351 
HandlePropertySet(void)1352 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_ENABLED>(void)
1353 {
1354     bool    enabled = false;
1355     otError error   = OT_ERROR_NONE;
1356 
1357     SuccessOrExit(error = mDecoder.ReadBool(enabled));
1358     otChannelManagerSetAutoChannelSelectionEnabled(mInstance, enabled);
1359 
1360 exit:
1361     return error;
1362 }
1363 
HandlePropertyGet(void)1364 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL>(void)
1365 {
1366     return mEncoder.WriteUint32(otChannelManagerGetAutoChannelSelectionInterval(mInstance));
1367 }
1368 
HandlePropertySet(void)1369 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL>(void)
1370 {
1371     uint32_t interval;
1372     otError  error = OT_ERROR_NONE;
1373 
1374     SuccessOrExit(error = mDecoder.ReadUint32(interval));
1375     error = otChannelManagerSetAutoChannelSelectionInterval(mInstance, interval);
1376 
1377 exit:
1378     return error;
1379 }
1380 
1381 #endif // OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE
1382 
1383 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
HandlePropertyGet(void)1384 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_TIME_SYNC_PERIOD>(void)
1385 {
1386     return mEncoder.WriteUint16(otNetworkTimeGetSyncPeriod(mInstance));
1387 }
1388 
HandlePropertySet(void)1389 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_TIME_SYNC_PERIOD>(void)
1390 {
1391     otError  error = OT_ERROR_NONE;
1392     uint16_t timeSyncPeriod;
1393 
1394     SuccessOrExit(error = mDecoder.ReadUint16(timeSyncPeriod));
1395 
1396     SuccessOrExit(error = otNetworkTimeSetSyncPeriod(mInstance, timeSyncPeriod));
1397 
1398 exit:
1399     return error;
1400 }
1401 
HandlePropertyGet(void)1402 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_TIME_SYNC_XTAL_THRESHOLD>(void)
1403 {
1404     return mEncoder.WriteUint16(otNetworkTimeGetXtalThreshold(mInstance));
1405 }
1406 
HandlePropertySet(void)1407 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_TIME_SYNC_XTAL_THRESHOLD>(void)
1408 {
1409     otError  error = OT_ERROR_NONE;
1410     uint16_t xtalThreshold;
1411 
1412     SuccessOrExit(error = mDecoder.ReadUint16(xtalThreshold));
1413 
1414     SuccessOrExit(error = otNetworkTimeSetXtalThreshold(mInstance, xtalThreshold));
1415 
1416 exit:
1417     return error;
1418 }
1419 #endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1420 
1421 #if OPENTHREAD_CONFIG_NCP_INFRA_IF_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
HandlePropertySet(void)1422 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_INFRA_IF_STATE>(void)
1423 {
1424     otError  error = OT_ERROR_NONE;
1425     uint32_t infraIfIndex;
1426     bool     isInfraRunning;
1427 
1428     SuccessOrExit(error = mDecoder.ReadUint32(infraIfIndex));
1429     SuccessOrExit(error = mDecoder.ReadBool(isInfraRunning));
1430 
1431     mInfraIfAddrCount = 0;
1432     while (!mDecoder.IsAllReadInStruct())
1433     {
1434         const otIp6Address *addr;
1435 
1436         SuccessOrExit(error = mDecoder.ReadIp6Address(addr));
1437         SuccessOrExit(error = InfraIfAddAddress(*addr));
1438     }
1439 
1440     if (infraIfIndex != mInfraIfIndex)
1441     {
1442         mInfraIfIndex = infraIfIndex;
1443         IgnoreError(otBorderRoutingSetEnabled(mInstance, /* aEnabled */ false));
1444         SuccessOrExit(error = otBorderRoutingInit(mInstance, mInfraIfIndex, isInfraRunning));
1445         SuccessOrExit(error = otBorderRoutingSetEnabled(mInstance, /* aEnabled */ true));
1446     }
1447     else
1448     {
1449         SuccessOrExit(error = otPlatInfraIfStateChanged(mInstance, mInfraIfIndex, isInfraRunning));
1450     }
1451 
1452 exit:
1453     return error;
1454 }
1455 
HandlePropertySet(void)1456 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_INFRA_IF_RECV_ICMP6>(void)
1457 {
1458     otError             error = OT_ERROR_NONE;
1459     uint32_t            infraIfIndex;
1460     const otIp6Address *address;
1461     const uint8_t      *icmp6Data = nullptr;
1462     uint16_t            len;
1463 
1464     SuccessOrExit(error = mDecoder.ReadUint32(infraIfIndex));
1465     VerifyOrExit(mInfraIfIndex == infraIfIndex, error = OT_ERROR_DROP);
1466     SuccessOrExit(error = mDecoder.ReadIp6Address(address));
1467     SuccessOrExit(error = mDecoder.ReadData(icmp6Data, len));
1468 
1469     // Currently the ICMP6 messages can only be ND messages.
1470     otPlatInfraIfRecvIcmp6Nd(mInstance, infraIfIndex, address, icmp6Data, len);
1471 
1472 exit:
1473     return error;
1474 }
1475 
InfraIfAddAddress(const otIp6Address & aAddress)1476 otError NcpBase::InfraIfAddAddress(const otIp6Address &aAddress)
1477 {
1478     otError error = OT_ERROR_NONE;
1479 
1480     VerifyOrExit(mInfraIfAddrCount < kMaxInfraIfAddrs, error = OT_ERROR_NO_BUFS);
1481     memcpy(&mInfraIfAddrs[mInfraIfAddrCount++], &aAddress, sizeof(aAddress));
1482 exit:
1483     return error;
1484 }
1485 
InfraIfContainsAddress(const otIp6Address & aAddress)1486 bool NcpBase::InfraIfContainsAddress(const otIp6Address &aAddress)
1487 {
1488     bool result = false;
1489 
1490     for (uint8_t i = 0; i < mInfraIfAddrCount; i++)
1491     {
1492         if (memcmp(&mInfraIfAddrs[i], &aAddress, sizeof(aAddress)) == 0)
1493         {
1494             result = true;
1495             break;
1496         }
1497     }
1498     return result;
1499 }
1500 
InfraIfHasAddress(uint32_t aInfraIfIndex,const otIp6Address * aAddress)1501 bool NcpBase::InfraIfHasAddress(uint32_t aInfraIfIndex, const otIp6Address *aAddress)
1502 {
1503     return aInfraIfIndex == mInfraIfIndex && InfraIfContainsAddress(*aAddress);
1504 }
1505 
InfraIfSendIcmp6Nd(uint32_t aInfraIfIndex,const otIp6Address * aDestAddress,const uint8_t * aBuffer,uint16_t aBufferLength)1506 otError NcpBase::InfraIfSendIcmp6Nd(uint32_t            aInfraIfIndex,
1507                                     const otIp6Address *aDestAddress,
1508                                     const uint8_t      *aBuffer,
1509                                     uint16_t            aBufferLength)
1510 {
1511     otError error  = OT_ERROR_NONE;
1512     uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
1513 
1514     SuccessOrExit(error = mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_INFRA_IF_SEND_ICMP6));
1515     SuccessOrExit(error = mEncoder.WriteUint32(aInfraIfIndex));
1516     SuccessOrExit(error = mEncoder.WriteIp6Address(*aDestAddress));
1517     SuccessOrExit(error = mEncoder.WriteDataWithLen(aBuffer, aBufferLength));
1518     SuccessOrExit(error = mEncoder.EndFrame());
1519 
1520 exit:
1521     return error;
1522 }
1523 
1524 #endif // OPENTHREAD_CONFIG_NCP_INFRA_IF_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
1525 
1526 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
HandlePropertySet(void)1527 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_SRP_SERVER_ENABLED>(void)
1528 {
1529     otError error = OT_ERROR_NONE;
1530     bool    enable;
1531 
1532     SuccessOrExit(error = mDecoder.ReadBool(enable));
1533     otSrpServerSetEnabled(mInstance, enable);
1534 
1535 exit:
1536     return error;
1537 }
1538 
HandlePropertyGet(void)1539 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_SRP_SERVER_ENABLED>(void)
1540 {
1541     otSrpServerState srpServerState = otSrpServerGetState(mInstance);
1542 
1543     return mEncoder.WriteBool(srpServerState != OT_SRP_SERVER_STATE_DISABLED);
1544 }
1545 
1546 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
HandlePropertySet(void)1547 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_SRP_SERVER_AUTO_ENABLE_MODE>(void)
1548 {
1549     otError error = OT_ERROR_NONE;
1550     bool    enable;
1551 
1552     SuccessOrExit(error = mDecoder.ReadBool(enable));
1553     otSrpServerSetAutoEnableMode(mInstance, enable);
1554 
1555 exit:
1556     return error;
1557 }
1558 
HandlePropertyGet(void)1559 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_SRP_SERVER_AUTO_ENABLE_MODE>(void)
1560 {
1561     return mEncoder.WriteBool(otSrpServerIsAutoEnableMode(mInstance));
1562 }
1563 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
1564 #endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
1565 
1566 #if OPENTHREAD_CONFIG_NCP_DNSSD_ENABLE && OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
1567 
DnssdRegisterHost(const otPlatDnssdHost * aHost,otPlatDnssdRequestId aRequestId,otPlatDnssdRegisterCallback aCallback)1568 void NcpBase::DnssdRegisterHost(const otPlatDnssdHost      *aHost,
1569                                 otPlatDnssdRequestId        aRequestId,
1570                                 otPlatDnssdRegisterCallback aCallback)
1571 {
1572     DnssdUpdate(aHost, aRequestId, aCallback, /* aRegister */ true);
1573 }
1574 
DnssdUnregisterHost(const otPlatDnssdHost * aHost,otPlatDnssdRequestId aRequestId,otPlatDnssdRegisterCallback aCallback)1575 void NcpBase::DnssdUnregisterHost(const otPlatDnssdHost      *aHost,
1576                                   otPlatDnssdRequestId        aRequestId,
1577                                   otPlatDnssdRegisterCallback aCallback)
1578 {
1579     DnssdUpdate(aHost, aRequestId, aCallback, /* aRegister */ false);
1580 }
1581 
DnssdRegisterService(const otPlatDnssdService * aService,otPlatDnssdRequestId aRequestId,otPlatDnssdRegisterCallback aCallback)1582 void NcpBase::DnssdRegisterService(const otPlatDnssdService   *aService,
1583                                    otPlatDnssdRequestId        aRequestId,
1584                                    otPlatDnssdRegisterCallback aCallback)
1585 {
1586     DnssdUpdate(aService, aRequestId, aCallback, /* aRegister */ true);
1587 }
1588 
DnssdUnregisterService(const otPlatDnssdService * aService,otPlatDnssdRequestId aRequestId,otPlatDnssdRegisterCallback aCallback)1589 void NcpBase::DnssdUnregisterService(const otPlatDnssdService   *aService,
1590                                      otPlatDnssdRequestId        aRequestId,
1591                                      otPlatDnssdRegisterCallback aCallback)
1592 {
1593     DnssdUpdate(aService, aRequestId, aCallback, /* aRegister */ false);
1594 }
1595 
DnssdRegisterKey(const otPlatDnssdKey * aKey,otPlatDnssdRequestId aRequestId,otPlatDnssdRegisterCallback aCallback)1596 void NcpBase::DnssdRegisterKey(const otPlatDnssdKey       *aKey,
1597                                otPlatDnssdRequestId        aRequestId,
1598                                otPlatDnssdRegisterCallback aCallback)
1599 {
1600     DnssdUpdate(aKey, aRequestId, aCallback, /* aRegister */ true);
1601 }
1602 
DnssdUnregisterKey(const otPlatDnssdKey * aKey,otPlatDnssdRequestId aRequestId,otPlatDnssdRegisterCallback aCallback)1603 void NcpBase::DnssdUnregisterKey(const otPlatDnssdKey       *aKey,
1604                                  otPlatDnssdRequestId        aRequestId,
1605                                  otPlatDnssdRegisterCallback aCallback)
1606 {
1607     DnssdUpdate(aKey, aRequestId, aCallback, /* aRegister */ false);
1608 }
1609 
DnssdGetState(void)1610 otPlatDnssdState NcpBase::DnssdGetState(void) { return mDnssdState; }
1611 
HandlePropertySet(void)1612 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_DNSSD_STATE>(void)
1613 {
1614     otError error = OT_ERROR_NONE;
1615     uint8_t state;
1616 
1617     SuccessOrExit(error = mDecoder.ReadUint8(state));
1618 
1619     if (state != mDnssdState)
1620     {
1621         mDnssdState = static_cast<otPlatDnssdState>(state);
1622         otPlatDnssdStateHandleStateChange(mInstance);
1623     }
1624 
1625 exit:
1626     return error;
1627 }
1628 
HandlePropertySet(void)1629 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_DNSSD_REQUEST_RESULT>(void)
1630 {
1631     otError                     error = OT_ERROR_NONE;
1632     otPlatDnssdRequestId        requestId;
1633     uint8_t                     result;
1634     otPlatDnssdRegisterCallback callback = nullptr;
1635     const uint8_t              *context;
1636     uint16_t                    contextLen;
1637 
1638     SuccessOrExit(error = mDecoder.ReadUint8(result));
1639     SuccessOrExit(error = mDecoder.ReadUint32(requestId));
1640     SuccessOrExit(error = mDecoder.ReadData(context, contextLen));
1641     VerifyOrExit(contextLen == sizeof(otPlatDnssdRegisterCallback), error = OT_ERROR_PARSE);
1642     callback = *reinterpret_cast<const otPlatDnssdRegisterCallback *>(context);
1643     callback(mInstance, requestId, static_cast<otError>(result));
1644 
1645 exit:
1646     return error;
1647 }
1648 
1649 #endif // OPENTHREAD_CONFIG_NCP_DNSSD_ENABLE && OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
1650 
1651 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
1652 
HandlePropertyGet(void)1653 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_BORDER_AGENT_MESHCOP_SERVICE_STATE>(void)
1654 {
1655     otError                            error = OT_ERROR_NONE;
1656     otBorderAgentMeshCoPServiceTxtData txtData;
1657 
1658     SuccessOrExit(error = otBorderAgentGetMeshCoPServiceTxtData(mInstance, &txtData));
1659     SuccessOrExit(error = mEncoder.WriteBool(otBorderAgentIsActive(mInstance)));
1660     SuccessOrExit(error = mEncoder.WriteUint16(otBorderAgentGetUdpPort(mInstance)));
1661     SuccessOrExit(error = mEncoder.WriteData(txtData.mData, txtData.mLength));
1662 
1663 exit:
1664     return error;
1665 }
1666 
1667 #endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
1668 
1669 } // namespace Ncp
1670 } // namespace ot
1671 
1672 #endif // OPENTHREAD_FTD
1673