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 minimal thread device required Spinel interface to the OpenThread stack.
31  */
32 
33 #include "openthread-core-config.h"
34 
35 #include "ncp_base.hpp"
36 
37 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
38 #include <openthread/border_router.h>
39 #endif
40 #if OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE
41 #include <openthread/channel_monitor.h>
42 #endif
43 #include <openthread/child_supervision.h>
44 #include <openthread/diag.h>
45 #include <openthread/icmp6.h>
46 #if OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE
47 #include <openthread/jam_detection.h>
48 #endif
49 #include <openthread/ncp.h>
50 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
51 #include <openthread/network_time.h>
52 #endif
53 #include <openthread/platform/misc.h>
54 #include <openthread/platform/radio.h>
55 #if OPENTHREAD_FTD
56 #include <openthread/thread_ftd.h>
57 #endif
58 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
59 #include <openthread/server.h>
60 #endif
61 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
62 #include "openthread/backbone_router.h"
63 #endif
64 #if OPENTHREAD_CONFIG_SRP_CLIENT_BUFFERS_ENABLE
65 #include <openthread/srp_client_buffers.h>
66 #endif
67 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
68 #include <openthread/trel.h>
69 #endif
70 
71 #include "common/code_utils.hpp"
72 #include "common/debug.hpp"
73 #include "common/instance.hpp"
74 #include "common/string.hpp"
75 #include "net/ip6.hpp"
76 
77 #if OPENTHREAD_MTD || OPENTHREAD_FTD
78 
79 namespace ot {
80 namespace Ncp {
81 
BorderRouterConfigToFlagByte(const otBorderRouterConfig & aConfig)82 static uint8_t BorderRouterConfigToFlagByte(const otBorderRouterConfig &aConfig)
83 {
84     uint8_t flags = 0;
85 
86     if (aConfig.mPreferred)
87     {
88         flags |= SPINEL_NET_FLAG_PREFERRED;
89     }
90 
91     if (aConfig.mSlaac)
92     {
93         flags |= SPINEL_NET_FLAG_SLAAC;
94     }
95 
96     if (aConfig.mDhcp)
97     {
98         flags |= SPINEL_NET_FLAG_DHCP;
99     }
100 
101     if (aConfig.mDefaultRoute)
102     {
103         flags |= SPINEL_NET_FLAG_DEFAULT_ROUTE;
104     }
105 
106     if (aConfig.mConfigure)
107     {
108         flags |= SPINEL_NET_FLAG_CONFIGURE;
109     }
110 
111     if (aConfig.mOnMesh)
112     {
113         flags |= SPINEL_NET_FLAG_ON_MESH;
114     }
115 
116     flags |= (static_cast<uint8_t>(aConfig.mPreference) << SPINEL_NET_FLAG_PREFERENCE_OFFSET);
117 
118     return flags;
119 }
120 
BorderRouterConfigToFlagByteExtended(const otBorderRouterConfig & aConfig)121 static uint8_t BorderRouterConfigToFlagByteExtended(const otBorderRouterConfig &aConfig)
122 {
123     uint8_t flags = 0;
124 
125     if (aConfig.mNdDns)
126     {
127         flags |= SPINEL_NET_FLAG_EXT_DNS;
128     }
129 
130     if (aConfig.mDp)
131     {
132         flags |= SPINEL_NET_FLAG_EXT_DP;
133     }
134 
135     return flags;
136 }
137 
ExternalRouteConfigToFlagByte(const otExternalRouteConfig & aConfig)138 static uint8_t ExternalRouteConfigToFlagByte(const otExternalRouteConfig &aConfig)
139 {
140     uint8_t flags = 0;
141 
142     switch (aConfig.mPreference)
143     {
144     case OT_ROUTE_PREFERENCE_LOW:
145         flags |= SPINEL_ROUTE_PREFERENCE_LOW;
146         break;
147 
148     case OT_ROUTE_PREFERENCE_HIGH:
149         flags |= SPINEL_ROUTE_PREFERENCE_HIGH;
150         break;
151 
152     case OT_ROUTE_PREFERENCE_MED:
153     default:
154         flags |= SPINEL_ROUTE_PREFERENCE_MEDIUM;
155         break;
156     }
157 
158     if (aConfig.mNat64)
159     {
160         flags |= SPINEL_ROUTE_FLAG_NAT64;
161     }
162 
163     return flags;
164 }
165 
LinkFlagsToFlagByte(bool aRxOnWhenIdle,bool aDeviceType,bool aNetworkData)166 uint8_t NcpBase::LinkFlagsToFlagByte(bool aRxOnWhenIdle, bool aDeviceType, bool aNetworkData)
167 {
168     uint8_t flags(0);
169 
170     if (aRxOnWhenIdle)
171     {
172         flags |= SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE;
173     }
174 
175     if (aDeviceType)
176     {
177         flags |= SPINEL_THREAD_MODE_FULL_THREAD_DEV;
178     }
179 
180     if (aNetworkData)
181     {
182         flags |= SPINEL_THREAD_MODE_FULL_NETWORK_DATA;
183     }
184 
185     return flags;
186 }
187 
EncodeNeighborInfo(const otNeighborInfo & aNeighborInfo)188 otError NcpBase::EncodeNeighborInfo(const otNeighborInfo &aNeighborInfo)
189 {
190     otError error;
191     uint8_t modeFlags;
192 
193     modeFlags = LinkFlagsToFlagByte(aNeighborInfo.mRxOnWhenIdle, aNeighborInfo.mFullThreadDevice,
194                                     aNeighborInfo.mFullNetworkData);
195 
196     SuccessOrExit(error = mEncoder.OpenStruct());
197 
198     SuccessOrExit(error = mEncoder.WriteEui64(aNeighborInfo.mExtAddress));
199     SuccessOrExit(error = mEncoder.WriteUint16(aNeighborInfo.mRloc16));
200     SuccessOrExit(error = mEncoder.WriteUint32(aNeighborInfo.mAge));
201     SuccessOrExit(error = mEncoder.WriteUint8(aNeighborInfo.mLinkQualityIn));
202     SuccessOrExit(error = mEncoder.WriteInt8(aNeighborInfo.mAverageRssi));
203     SuccessOrExit(error = mEncoder.WriteUint8(modeFlags));
204     SuccessOrExit(error = mEncoder.WriteBool(aNeighborInfo.mIsChild));
205     SuccessOrExit(error = mEncoder.WriteUint32(aNeighborInfo.mLinkFrameCounter));
206     SuccessOrExit(error = mEncoder.WriteUint32(aNeighborInfo.mMleFrameCounter));
207     SuccessOrExit(error = mEncoder.WriteInt8(aNeighborInfo.mLastRssi));
208 
209     SuccessOrExit(error = mEncoder.CloseStruct());
210 
211 exit:
212     return error;
213 }
214 
215 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
EncodeLinkMetricsValues(const otLinkMetricsValues * aMetricsValues)216 otError NcpBase::EncodeLinkMetricsValues(const otLinkMetricsValues *aMetricsValues)
217 {
218     otError error = OT_ERROR_NONE;
219 
220     SuccessOrExit(error = mEncoder.OpenStruct());
221 
222     if (aMetricsValues->mMetrics.mPduCount)
223     {
224         SuccessOrExit(error = mEncoder.OpenStruct());
225         SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_THREAD_LINK_METRIC_PDU_COUNT));
226         SuccessOrExit(error = mEncoder.WriteUint32(aMetricsValues->mPduCountValue));
227         SuccessOrExit(error = mEncoder.CloseStruct());
228     }
229 
230     if (aMetricsValues->mMetrics.mLqi)
231     {
232         SuccessOrExit(error = mEncoder.OpenStruct());
233         SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_THREAD_LINK_METRIC_LQI));
234         SuccessOrExit(error = mEncoder.WriteUint8(aMetricsValues->mLqiValue));
235         SuccessOrExit(error = mEncoder.CloseStruct());
236     }
237 
238     if (aMetricsValues->mMetrics.mLinkMargin)
239     {
240         SuccessOrExit(error = mEncoder.OpenStruct());
241         SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_THREAD_LINK_METRIC_LINK_MARGIN));
242         SuccessOrExit(error = mEncoder.WriteUint8(aMetricsValues->mLinkMarginValue));
243         SuccessOrExit(error = mEncoder.CloseStruct());
244     }
245 
246     if (aMetricsValues->mMetrics.mRssi)
247     {
248         SuccessOrExit(error = mEncoder.OpenStruct());
249         SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_THREAD_LINK_METRIC_RSSI));
250         SuccessOrExit(error = mEncoder.WriteInt8(aMetricsValues->mRssiValue));
251         SuccessOrExit(error = mEncoder.CloseStruct());
252     }
253 
254     SuccessOrExit(error = mEncoder.CloseStruct());
255 
256 exit:
257     return error;
258 }
259 #endif
260 
261 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
HandlePropertySet(void)262 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_CSL_PERIOD>(void)
263 {
264     uint32_t cslPeriod;
265     otError  error = OT_ERROR_NONE;
266 
267     SuccessOrExit(error = mDecoder.ReadUint32(cslPeriod));
268 
269     error = otLinkSetCslPeriod(mInstance, cslPeriod);
270 
271 exit:
272     return error;
273 }
274 
HandlePropertyGet(void)275 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_CSL_PERIOD>(void)
276 {
277     return mEncoder.WriteUint32(otLinkGetCslPeriod(mInstance));
278 }
279 
HandlePropertySet(void)280 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_CSL_TIMEOUT>(void)
281 {
282     uint32_t cslTimeout;
283     otError  error = OT_ERROR_NONE;
284 
285     SuccessOrExit(error = mDecoder.ReadUint32(cslTimeout));
286 
287     error = otLinkSetCslTimeout(mInstance, cslTimeout);
288 
289 exit:
290     return error;
291 }
292 
HandlePropertyGet(void)293 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_CSL_TIMEOUT>(void)
294 {
295     return mEncoder.WriteUint32(otLinkGetCslTimeout(mInstance));
296 }
297 
HandlePropertySet(void)298 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_CSL_CHANNEL>(void)
299 {
300     uint8_t cslChannel;
301     otError error = OT_ERROR_NONE;
302 
303     SuccessOrExit(error = mDecoder.ReadUint8(cslChannel));
304 
305     error = otLinkSetCslChannel(mInstance, cslChannel);
306 
307 exit:
308     return error;
309 }
310 
HandlePropertyGet(void)311 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_CSL_CHANNEL>(void)
312 {
313     return mEncoder.WriteUint8(otLinkGetCslChannel(mInstance));
314 }
315 #endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
316 
317 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
HandlePropertySet(void)318 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_MLR_REQUEST>(void)
319 {
320     otError      error = OT_ERROR_NONE;
321     otIp6Address addresses[OT_IP6_MAX_MLR_ADDRESSES];
322     uint8_t      addressesCount = 0U;
323     bool         timeoutPresent = false;
324     uint32_t     timeout;
325 
326     SuccessOrExit(error = mDecoder.OpenStruct());
327 
328     while (mDecoder.GetRemainingLengthInStruct())
329     {
330         VerifyOrExit(addressesCount < Ip6AddressesTlv::kMaxAddresses, error = OT_ERROR_NO_BUFS);
331         SuccessOrExit(error = mDecoder.ReadIp6Address(addresses[addressesCount]));
332         ++addressesCount;
333     }
334 
335     SuccessOrExit(error = mDecoder.CloseStruct());
336 
337     while (mDecoder.GetRemainingLengthInStruct())
338     {
339         uint8_t paramId;
340 
341         SuccessOrExit(error = mDecoder.OpenStruct());
342 
343         SuccessOrExit(error = mDecoder.ReadUint8(paramId));
344 
345         switch (paramId)
346         {
347         case SPINEL_THREAD_MLR_PARAMID_TIMEOUT:
348             SuccessOrExit(error = mDecoder.ReadUint32(timeout));
349             timeoutPresent = true;
350             break;
351 
352         default:
353             ExitNow(error = OT_ERROR_INVALID_ARGS);
354         }
355 
356         SuccessOrExit(error = mDecoder.CloseStruct());
357     }
358 
359     SuccessOrExit(error = otIp6RegisterMulticastListeners(mInstance, addresses, addressesCount,
360                                                           timeoutPresent ? &timeout : nullptr,
361                                                           &NcpBase::HandleMlrRegResult_Jump, this));
362 exit:
363     return error;
364 }
365 
HandleMlrRegResult_Jump(void * aContext,otError aError,uint8_t aMlrStatus,const otIp6Address * aFailedAddresses,uint8_t aFailedAddressNum)366 void NcpBase::HandleMlrRegResult_Jump(void               *aContext,
367                                       otError             aError,
368                                       uint8_t             aMlrStatus,
369                                       const otIp6Address *aFailedAddresses,
370                                       uint8_t             aFailedAddressNum)
371 {
372     static_cast<NcpBase *>(aContext)->HandleMlrRegResult(aError, aMlrStatus, aFailedAddresses, aFailedAddressNum);
373 }
374 
HandleMlrRegResult(otError aError,uint8_t aMlrStatus,const otIp6Address * aFailedAddresses,uint8_t aFailedAddressNum)375 void NcpBase::HandleMlrRegResult(otError             aError,
376                                  uint8_t             aMlrStatus,
377                                  const otIp6Address *aFailedAddresses,
378                                  uint8_t             aFailedAddressNum)
379 {
380     SuccessOrExit(mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_PROP_VALUE_IS,
381                                       SPINEL_PROP_THREAD_MLR_RESPONSE));
382 
383     SuccessOrExit(mEncoder.WriteUint8(static_cast<uint8_t>(ThreadErrorToSpinelStatus(aError))));
384     SuccessOrExit(mEncoder.WriteUint8(aMlrStatus));
385 
386     SuccessOrExit(mEncoder.OpenStruct());
387 
388     if (aError == OT_ERROR_NONE)
389     {
390         for (size_t i = 0U; i < aFailedAddressNum; ++i)
391         {
392             SuccessOrExit(mEncoder.WriteIp6Address(aFailedAddresses[i]));
393         }
394     }
395 
396     SuccessOrExit(mEncoder.CloseStruct());
397 
398     SuccessOrExit(mEncoder.EndFrame());
399 
400 exit:
401     return;
402 }
403 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
404 
405 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
HandlePropertyGet(void)406 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_BACKBONE_ROUTER_PRIMARY>(void)
407 {
408     otError                error = OT_ERROR_NONE;
409     otBackboneRouterConfig bbrConfig;
410 
411     SuccessOrExit(error = otBackboneRouterGetPrimary(mInstance, &bbrConfig));
412 
413     SuccessOrExit(error = mEncoder.WriteUint16(bbrConfig.mServer16));
414     SuccessOrExit(error = mEncoder.WriteUint16(bbrConfig.mReregistrationDelay));
415     SuccessOrExit(error = mEncoder.WriteUint32(bbrConfig.mMlrTimeout));
416     SuccessOrExit(error = mEncoder.WriteUint8(bbrConfig.mSequenceNumber));
417 
418 exit:
419     return error;
420 }
421 #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
422 
HandlePropertyGet(void)423 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_DATA_POLL_PERIOD>(void)
424 {
425     return mEncoder.WriteUint32(otLinkGetPollPeriod(mInstance));
426 }
427 
HandlePropertySet(void)428 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_DATA_POLL_PERIOD>(void)
429 {
430     uint32_t pollPeriod;
431     otError  error = OT_ERROR_NONE;
432 
433     SuccessOrExit(error = mDecoder.ReadUint32(pollPeriod));
434 
435     error = otLinkSetPollPeriod(mInstance, pollPeriod);
436 
437 exit:
438     return error;
439 }
440 
HandlePropertyGet(void)441 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_EXTENDED_ADDR>(void)
442 {
443     return mEncoder.WriteEui64(*otLinkGetExtendedAddress(mInstance));
444 }
445 
HandlePropertyGet(void)446 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_MAX_RETRY_NUMBER_DIRECT>(void)
447 {
448     return mEncoder.WriteUint8(otLinkGetMaxFrameRetriesDirect(mInstance));
449 }
450 
HandlePropertySet(void)451 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_MAX_RETRY_NUMBER_DIRECT>(void)
452 {
453     uint8_t maxFrameRetriesDirect;
454     otError error = OT_ERROR_NONE;
455 
456     SuccessOrExit(error = mDecoder.ReadUint8(maxFrameRetriesDirect));
457     otLinkSetMaxFrameRetriesDirect(mInstance, maxFrameRetriesDirect);
458 
459 exit:
460     return error;
461 }
462 
HandlePropertySet(void)463 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_PHY_CHAN_SUPPORTED>(void)
464 {
465     uint32_t newMask = 0;
466     otError  error   = OT_ERROR_NONE;
467 
468     SuccessOrExit(error = DecodeChannelMask(newMask));
469     error = otLinkSetSupportedChannelMask(mInstance, newMask);
470 
471 exit:
472     return error;
473 }
474 
CommandHandler_NET_CLEAR(uint8_t aHeader)475 otError NcpBase::CommandHandler_NET_CLEAR(uint8_t aHeader)
476 {
477     return PrepareLastStatusResponse(aHeader, ThreadErrorToSpinelStatus(otInstanceErasePersistentInfo(mInstance)));
478 }
479 
HandlePropertyGet(void)480 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_SAVED>(void)
481 {
482     return mEncoder.WriteBool(otDatasetIsCommissioned(mInstance));
483 }
484 
HandlePropertyGet(void)485 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_IF_UP>(void)
486 {
487     return mEncoder.WriteBool(otIp6IsEnabled(mInstance));
488 }
489 
HandlePropertySet(void)490 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_IF_UP>(void)
491 {
492     bool    enabled = false;
493     otError error   = OT_ERROR_NONE;
494 
495     SuccessOrExit(error = mDecoder.ReadBool(enabled));
496 
497     error = otIp6SetEnabled(mInstance, enabled);
498 
499 exit:
500     return error;
501 }
502 
HandlePropertyGet(void)503 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_STACK_UP>(void)
504 {
505     return mEncoder.WriteBool(otThreadGetDeviceRole(mInstance) != OT_DEVICE_ROLE_DISABLED);
506 }
507 
HandlePropertySet(void)508 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_STACK_UP>(void)
509 {
510     bool    enabled = false;
511     otError error   = OT_ERROR_NONE;
512 
513     SuccessOrExit(error = mDecoder.ReadBool(enabled));
514 
515     // If the value has changed...
516     if (enabled != (otThreadGetDeviceRole(mInstance) != OT_DEVICE_ROLE_DISABLED))
517     {
518         if (enabled)
519         {
520             error = otThreadSetEnabled(mInstance, true);
521         }
522         else
523         {
524             error = otThreadSetEnabled(mInstance, false);
525         }
526     }
527 
528 exit:
529     return error;
530 }
531 
HandlePropertyGet(void)532 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_ROLE>(void)
533 {
534     spinel_net_role_t role(SPINEL_NET_ROLE_DETACHED);
535 
536     switch (otThreadGetDeviceRole(mInstance))
537     {
538     case OT_DEVICE_ROLE_DISABLED:
539     case OT_DEVICE_ROLE_DETACHED:
540         role = SPINEL_NET_ROLE_DETACHED;
541         break;
542 
543     case OT_DEVICE_ROLE_CHILD:
544         role = SPINEL_NET_ROLE_CHILD;
545         break;
546 
547     case OT_DEVICE_ROLE_ROUTER:
548         role = SPINEL_NET_ROLE_ROUTER;
549         break;
550 
551     case OT_DEVICE_ROLE_LEADER:
552         role = SPINEL_NET_ROLE_LEADER;
553         break;
554     }
555 
556     return mEncoder.WriteUint8(role);
557 }
558 
HandlePropertySet(void)559 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_ROLE>(void)
560 {
561     unsigned int role  = 0;
562     otError      error = OT_ERROR_NONE;
563 
564     SuccessOrExit(error = mDecoder.ReadUintPacked(role));
565 
566     switch (role)
567     {
568     case SPINEL_NET_ROLE_DETACHED:
569         error = otThreadBecomeDetached(mInstance);
570         break;
571 
572 #if OPENTHREAD_FTD
573     case SPINEL_NET_ROLE_ROUTER:
574         error = otThreadBecomeRouter(mInstance);
575         break;
576 
577     case SPINEL_NET_ROLE_LEADER:
578         error = otThreadBecomeLeader(mInstance);
579         break;
580 #endif // OPENTHREAD_FTD
581 
582     case SPINEL_NET_ROLE_CHILD:
583         error = otThreadBecomeChild(mInstance);
584         break;
585     }
586 
587 exit:
588     return error;
589 }
590 
HandlePropertyGet(void)591 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_NETWORK_NAME>(void)
592 {
593     return mEncoder.WriteUtf8(otThreadGetNetworkName(mInstance));
594 }
595 
HandlePropertySet(void)596 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_NETWORK_NAME>(void)
597 {
598     const char *string = nullptr;
599     otError     error  = OT_ERROR_NONE;
600 
601     SuccessOrExit(error = mDecoder.ReadUtf8(string));
602 
603     error = otThreadSetNetworkName(mInstance, string);
604 
605 exit:
606     return error;
607 }
608 
HandlePropertyGet(void)609 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_XPANID>(void)
610 {
611     return mEncoder.WriteData(otThreadGetExtendedPanId(mInstance)->m8, sizeof(spinel_net_xpanid_t));
612 }
613 
HandlePropertySet(void)614 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_XPANID>(void)
615 {
616     const uint8_t *ptr = nullptr;
617     uint16_t       len;
618     otError        error = OT_ERROR_NONE;
619 
620     SuccessOrExit(error = mDecoder.ReadData(ptr, len));
621 
622     VerifyOrExit(len == sizeof(spinel_net_xpanid_t), error = OT_ERROR_PARSE);
623 
624     error = otThreadSetExtendedPanId(mInstance, reinterpret_cast<const otExtendedPanId *>(ptr));
625 
626 exit:
627     return error;
628 }
629 
HandlePropertyGet(void)630 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_NETWORK_KEY>(void)
631 {
632     otNetworkKey networkKey;
633 
634     otThreadGetNetworkKey(mInstance, &networkKey);
635 
636     return mEncoder.WriteData(networkKey.m8, OT_NETWORK_KEY_SIZE);
637 }
638 
HandlePropertySet(void)639 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_NETWORK_KEY>(void)
640 {
641     const uint8_t *ptr = nullptr;
642     uint16_t       len;
643     otError        error = OT_ERROR_NONE;
644 
645     SuccessOrExit(error = mDecoder.ReadData(ptr, len));
646 
647     VerifyOrExit(len == OT_NETWORK_KEY_SIZE, error = OT_ERROR_PARSE);
648 
649     error = otThreadSetNetworkKey(mInstance, reinterpret_cast<const otNetworkKey *>(ptr));
650 
651 exit:
652     return error;
653 }
654 
HandlePropertyGet(void)655 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER>(void)
656 {
657     return mEncoder.WriteUint32(otThreadGetKeySequenceCounter(mInstance));
658 }
659 
HandlePropertySet(void)660 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER>(void)
661 {
662     uint32_t keySeqCounter;
663     otError  error = OT_ERROR_NONE;
664 
665     SuccessOrExit(error = mDecoder.ReadUint32(keySeqCounter));
666 
667     otThreadSetKeySequenceCounter(mInstance, keySeqCounter);
668 
669 exit:
670     return error;
671 }
672 
HandlePropertyGet(void)673 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_PARTITION_ID>(void)
674 {
675     return mEncoder.WriteUint32(otThreadGetPartitionId(mInstance));
676 }
677 
HandlePropertyGet(void)678 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_KEY_SWITCH_GUARDTIME>(void)
679 {
680     return mEncoder.WriteUint32(otThreadGetKeySwitchGuardTime(mInstance));
681 }
682 
HandlePropertySet(void)683 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_KEY_SWITCH_GUARDTIME>(void)
684 {
685     uint32_t keyGuardTime;
686     otError  error = OT_ERROR_NONE;
687 
688     SuccessOrExit(error = mDecoder.ReadUint32(keyGuardTime));
689 
690     otThreadSetKeySwitchGuardTime(mInstance, keyGuardTime);
691 
692 exit:
693     return error;
694 }
695 
HandlePropertyGet(void)696 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_NETWORK_DATA_VERSION>(void)
697 {
698     return mEncoder.WriteUint8(otNetDataGetVersion(mInstance));
699 }
700 
HandlePropertyGet(void)701 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_STABLE_NETWORK_DATA_VERSION>(void)
702 {
703     return mEncoder.WriteUint8(otNetDataGetStableVersion(mInstance));
704 }
705 
706 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
HandlePropertyGet(void)707 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_NETWORK_DATA>(void)
708 {
709     uint8_t networkData[255];
710     uint8_t networkDataLen = 255;
711 
712     IgnoreError(otBorderRouterGetNetData(mInstance,
713                                          false, // Stable?
714                                          networkData, &networkDataLen));
715 
716     return mEncoder.WriteData(networkData, networkDataLen);
717 }
718 
HandlePropertyGet(void)719 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_STABLE_NETWORK_DATA>(void)
720 {
721     uint8_t networkData[255];
722     uint8_t networkDataLen = 255;
723 
724     IgnoreError(otBorderRouterGetNetData(mInstance,
725                                          true, // Stable?
726                                          networkData, &networkDataLen));
727 
728     return mEncoder.WriteData(networkData, networkDataLen);
729 }
730 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
731 
HandlePropertyGet(void)732 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_LEADER_NETWORK_DATA>(void)
733 {
734     uint8_t networkData[255];
735     uint8_t networkDataLen = 255;
736 
737     IgnoreError(otNetDataGet(mInstance,
738                              false, // Stable?
739                              networkData, &networkDataLen));
740 
741     return mEncoder.WriteData(networkData, networkDataLen);
742 }
743 
HandlePropertyGet(void)744 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_STABLE_LEADER_NETWORK_DATA>(void)
745 {
746     uint8_t networkData[255];
747     uint8_t networkDataLen = 255;
748 
749     IgnoreError(otNetDataGet(mInstance,
750                              true, // Stable?
751                              networkData, &networkDataLen));
752 
753     return mEncoder.WriteData(networkData, networkDataLen);
754 }
755 
HandlePropertyGet(void)756 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_LEADER_RID>(void)
757 {
758     return mEncoder.WriteUint8(otThreadGetLeaderRouterId(mInstance));
759 }
760 
HandlePropertyGet(void)761 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_LEADER_ADDR>(void)
762 {
763     otError      error = OT_ERROR_NONE;
764     otIp6Address address;
765 
766     error = otThreadGetLeaderRloc(mInstance, &address);
767 
768     if (error == OT_ERROR_NONE)
769     {
770         error = mEncoder.WriteIp6Address(address);
771     }
772     else
773     {
774         error = mEncoder.OverwriteWithLastStatusError(ThreadErrorToSpinelStatus(error));
775     }
776 
777     return error;
778 }
779 
HandlePropertyGet(void)780 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_PARENT>(void)
781 {
782     otError error = OT_ERROR_NONE;
783 
784     otRouterInfo parentInfo;
785 
786     error = otThreadGetParentInfo(mInstance, &parentInfo);
787 
788     if (error == OT_ERROR_NONE)
789     {
790         if (parentInfo.mLinkEstablished)
791         {
792             int8_t averageRssi;
793             int8_t lastRssi;
794 
795             IgnoreError(otThreadGetParentAverageRssi(mInstance, &averageRssi));
796             IgnoreError(otThreadGetParentLastRssi(mInstance, &lastRssi));
797 
798             SuccessOrExit(error = mEncoder.WriteEui64(parentInfo.mExtAddress));
799             SuccessOrExit(error = mEncoder.WriteUint16(parentInfo.mRloc16));
800             SuccessOrExit(error = mEncoder.WriteUint32(parentInfo.mAge));
801             SuccessOrExit(error = mEncoder.WriteInt8(averageRssi));
802             SuccessOrExit(error = mEncoder.WriteInt8(lastRssi));
803             SuccessOrExit(error = mEncoder.WriteUint8(parentInfo.mLinkQualityIn));
804             SuccessOrExit(error = mEncoder.WriteUint8(parentInfo.mLinkQualityOut));
805             SuccessOrExit(error = mEncoder.WriteUint8(parentInfo.mVersion));
806 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
807             SuccessOrExit(error = mEncoder.WriteUint8(parentInfo.mCslClockAccuracy));
808             SuccessOrExit(error = mEncoder.WriteUint8(parentInfo.mCslUncertainty));
809 #endif
810         }
811         else
812         {
813             SuccessOrExit(error = mEncoder.OverwriteWithLastStatusError(SPINEL_STATUS_ITEM_NOT_FOUND));
814         }
815     }
816     else
817     {
818         error = mEncoder.OverwriteWithLastStatusError(ThreadErrorToSpinelStatus(error));
819     }
820 
821 exit:
822     return error;
823 }
824 
HandlePropertyGet(void)825 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_NEIGHBOR_TABLE>(void)
826 {
827     otError                error = OT_ERROR_NONE;
828     otNeighborInfoIterator iter  = OT_NEIGHBOR_INFO_ITERATOR_INIT;
829     otNeighborInfo         neighInfo;
830 
831     while (otThreadGetNextNeighborInfo(mInstance, &iter, &neighInfo) == OT_ERROR_NONE)
832     {
833         SuccessOrExit(error = EncodeNeighborInfo(neighInfo));
834     }
835 
836 exit:
837     return error;
838 }
839 
HandlePropertyGet(void)840 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_NEIGHBOR_TABLE_ERROR_RATES>(void)
841 {
842     otError                error = OT_ERROR_NONE;
843     otNeighborInfoIterator iter  = OT_NEIGHBOR_INFO_ITERATOR_INIT;
844     otNeighborInfo         neighInfo;
845 
846     while (otThreadGetNextNeighborInfo(mInstance, &iter, &neighInfo) == OT_ERROR_NONE)
847     {
848         SuccessOrExit(error = mEncoder.OpenStruct());
849 
850         SuccessOrExit(error = mEncoder.WriteEui64(neighInfo.mExtAddress));
851         SuccessOrExit(error = mEncoder.WriteUint16(neighInfo.mRloc16));
852         SuccessOrExit(error = mEncoder.WriteUint16(neighInfo.mFrameErrorRate));
853         SuccessOrExit(error = mEncoder.WriteUint16(neighInfo.mMessageErrorRate));
854         SuccessOrExit(error = mEncoder.WriteInt8(neighInfo.mAverageRssi));
855         SuccessOrExit(error = mEncoder.WriteInt8(neighInfo.mLastRssi));
856 
857         SuccessOrExit(error = mEncoder.CloseStruct());
858     }
859 
860 exit:
861     return error;
862 }
863 
HandlePropertyGet(void)864 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ASSISTING_PORTS>(void)
865 {
866     otError         error      = OT_ERROR_NONE;
867     uint8_t         numEntries = 0;
868     const uint16_t *ports      = otIp6GetUnsecurePorts(mInstance, &numEntries);
869 
870     for (; numEntries != 0; ports++, numEntries--)
871     {
872         SuccessOrExit(error = mEncoder.WriteUint16(*ports));
873     }
874 
875 exit:
876     return error;
877 }
878 
HandlePropertySet(void)879 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_ASSISTING_PORTS>(void)
880 {
881     otError error = OT_ERROR_NONE;
882 
883     // First, we need to remove all of the current assisting ports.
884     otIp6RemoveAllUnsecurePorts(mInstance);
885 
886     while (mDecoder.GetRemainingLengthInStruct() >= sizeof(uint16_t))
887     {
888         uint16_t port;
889 
890         SuccessOrExit(error = mDecoder.ReadUint16(port));
891         SuccessOrExit(error = otIp6AddUnsecurePort(mInstance, port));
892     }
893 
894 exit:
895 
896     if (error != OT_ERROR_NONE)
897     {
898         // We had an error, but we've actually changed
899         // the state of these ports, so we need to report
900         // those incomplete changes via an asynchronous
901         // change event.
902         IgnoreError(
903             WritePropertyValueIsFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_PROP_THREAD_ASSISTING_PORTS));
904     }
905 
906     return error;
907 }
908 
HandlePropertyGet(void)909 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE>(void)
910 {
911     return mEncoder.WriteBool(mAllowLocalNetworkDataChange);
912 }
913 
914 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
HandlePropertySet(void)915 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE>(void)
916 {
917     bool    value                    = false;
918     otError error                    = OT_ERROR_NONE;
919     bool    shouldRegisterWithLeader = false;
920 
921     SuccessOrExit(error = mDecoder.ReadBool(value));
922 
923     // Register any net data changes on transition from `true` to `false`.
924     shouldRegisterWithLeader = mAllowLocalNetworkDataChange && !value;
925 
926     mAllowLocalNetworkDataChange = value;
927 
928 exit:
929 
930     if (shouldRegisterWithLeader)
931     {
932         IgnoreError(otBorderRouterRegister(mInstance));
933     }
934 
935     return error;
936 }
937 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
938 
HandlePropertyGet(void)939 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ON_MESH_NETS>(void)
940 {
941     otError               error = OT_ERROR_NONE;
942     otBorderRouterConfig  borderRouterConfig;
943     otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT;
944 
945     // Fill from non-local network data first
946     while (otNetDataGetNextOnMeshPrefix(mInstance, &iter, &borderRouterConfig) == OT_ERROR_NONE)
947     {
948         SuccessOrExit(error = mEncoder.OpenStruct());
949 
950         SuccessOrExit(error = mEncoder.WriteIp6Address(borderRouterConfig.mPrefix.mPrefix));
951         SuccessOrExit(error = mEncoder.WriteUint8(borderRouterConfig.mPrefix.mLength));
952         SuccessOrExit(error = mEncoder.WriteBool(borderRouterConfig.mStable));
953         SuccessOrExit(error = mEncoder.WriteUint8(BorderRouterConfigToFlagByte(borderRouterConfig)));
954         SuccessOrExit(error = mEncoder.WriteBool(false)); // isLocal
955         SuccessOrExit(error = mEncoder.WriteUint16(borderRouterConfig.mRloc16));
956         SuccessOrExit(error = mEncoder.WriteUint8(BorderRouterConfigToFlagByteExtended(borderRouterConfig)));
957 
958         SuccessOrExit(error = mEncoder.CloseStruct());
959     }
960 
961 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
962 
963     iter = OT_NETWORK_DATA_ITERATOR_INIT;
964 
965     // Fill from local network data last
966     while (otBorderRouterGetNextOnMeshPrefix(mInstance, &iter, &borderRouterConfig) == OT_ERROR_NONE)
967     {
968         SuccessOrExit(error = mEncoder.OpenStruct());
969 
970         SuccessOrExit(error = mEncoder.WriteIp6Address(borderRouterConfig.mPrefix.mPrefix));
971         SuccessOrExit(error = mEncoder.WriteUint8(borderRouterConfig.mPrefix.mLength));
972         SuccessOrExit(error = mEncoder.WriteBool(borderRouterConfig.mStable));
973         SuccessOrExit(error = mEncoder.WriteUint8(BorderRouterConfigToFlagByte(borderRouterConfig)));
974         SuccessOrExit(error = mEncoder.WriteBool(true)); // isLocal
975         SuccessOrExit(error = mEncoder.WriteUint16(borderRouterConfig.mRloc16));
976         SuccessOrExit(error = mEncoder.WriteUint8(BorderRouterConfigToFlagByteExtended(borderRouterConfig)));
977 
978         SuccessOrExit(error = mEncoder.CloseStruct());
979     }
980 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
981 
982 exit:
983     return error;
984 }
985 
986 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
HandlePropertyInsert(void)987 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_THREAD_ON_MESH_NETS>(void)
988 {
989     otError              error = OT_ERROR_NONE;
990     otBorderRouterConfig borderRouterConfig;
991     bool                 stable = false;
992     bool                 isLocal;
993     uint8_t              flags         = 0;
994     uint8_t              flagsExtended = 0;
995     uint8_t              prefixLength;
996     uint16_t             rloc16;
997 
998     memset(&borderRouterConfig, 0, sizeof(otBorderRouterConfig));
999 
1000     VerifyOrExit(mAllowLocalNetworkDataChange, error = OT_ERROR_INVALID_STATE);
1001 
1002     SuccessOrExit(error = mDecoder.ReadIp6Address(borderRouterConfig.mPrefix.mPrefix));
1003     SuccessOrExit(error = mDecoder.ReadUint8(prefixLength));
1004     SuccessOrExit(error = mDecoder.ReadBool(stable));
1005     SuccessOrExit(error = mDecoder.ReadUint8(flags));
1006 
1007     borderRouterConfig.mPrefix.mLength = prefixLength;
1008     borderRouterConfig.mStable         = stable;
1009     borderRouterConfig.mPreference   = ((flags & SPINEL_NET_FLAG_PREFERENCE_MASK) >> SPINEL_NET_FLAG_PREFERENCE_OFFSET);
1010     borderRouterConfig.mPreferred    = ((flags & SPINEL_NET_FLAG_PREFERRED) != 0);
1011     borderRouterConfig.mSlaac        = ((flags & SPINEL_NET_FLAG_SLAAC) != 0);
1012     borderRouterConfig.mDhcp         = ((flags & SPINEL_NET_FLAG_DHCP) != 0);
1013     borderRouterConfig.mConfigure    = ((flags & SPINEL_NET_FLAG_CONFIGURE) != 0);
1014     borderRouterConfig.mDefaultRoute = ((flags & SPINEL_NET_FLAG_DEFAULT_ROUTE) != 0);
1015     borderRouterConfig.mOnMesh       = ((flags & SPINEL_NET_FLAG_ON_MESH) != 0);
1016 
1017     // A new field 'TLV flags extended' has been added to the SPINEL_PROP_THREAD_ON_MESH_NETS property.
1018     // To correctly handle a new field for INSERT command, the additional fields 'isLocal' and 'rloc16' are read and
1019     // ignored.
1020     if ((mDecoder.ReadBool(isLocal) == OT_ERROR_NONE) && (mDecoder.ReadUint16(rloc16) == OT_ERROR_NONE) &&
1021         (mDecoder.ReadUint8(flagsExtended) == OT_ERROR_NONE))
1022     {
1023         borderRouterConfig.mNdDns = ((flagsExtended & SPINEL_NET_FLAG_EXT_DNS) != 0);
1024         borderRouterConfig.mDp    = ((flagsExtended & SPINEL_NET_FLAG_EXT_DP) != 0);
1025     }
1026 
1027     error = otBorderRouterAddOnMeshPrefix(mInstance, &borderRouterConfig);
1028 
1029 exit:
1030     return error;
1031 }
1032 
HandlePropertyRemove(void)1033 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_THREAD_ON_MESH_NETS>(void)
1034 {
1035     otError     error = OT_ERROR_NONE;
1036     otIp6Prefix ip6Prefix;
1037     uint8_t     prefixLength;
1038 
1039     memset(&ip6Prefix, 0, sizeof(otIp6Prefix));
1040 
1041     VerifyOrExit(mAllowLocalNetworkDataChange, error = OT_ERROR_INVALID_STATE);
1042 
1043     SuccessOrExit(error = mDecoder.ReadIp6Address(ip6Prefix.mPrefix));
1044     SuccessOrExit(error = mDecoder.ReadUint8(prefixLength));
1045 
1046     ip6Prefix.mLength = prefixLength;
1047 
1048     error = otBorderRouterRemoveOnMeshPrefix(mInstance, &ip6Prefix);
1049 
1050     // If prefix was not on the list, "remove" command can be considered
1051     // successful.
1052 
1053     if (error == OT_ERROR_NOT_FOUND)
1054     {
1055         error = OT_ERROR_NONE;
1056     }
1057 
1058 exit:
1059     return error;
1060 }
1061 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
1062 
1063 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
1064 
HandlePropertyGet(void)1065 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_SERVER_ALLOW_LOCAL_DATA_CHANGE>(void)
1066 {
1067     return mEncoder.WriteBool(mAllowLocalServerDataChange);
1068 }
1069 
HandlePropertySet(void)1070 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_SERVER_ALLOW_LOCAL_DATA_CHANGE>(void)
1071 {
1072     bool    value                    = false;
1073     otError error                    = OT_ERROR_NONE;
1074     bool    shouldRegisterWithLeader = false;
1075 
1076     SuccessOrExit(error = mDecoder.ReadBool(value));
1077 
1078     // Register any server data changes on transition from `true` to `false`.
1079     shouldRegisterWithLeader = mAllowLocalServerDataChange && !value;
1080 
1081     mAllowLocalServerDataChange = value;
1082 
1083 exit:
1084 
1085     if (shouldRegisterWithLeader)
1086     {
1087         IgnoreError(otServerRegister(mInstance));
1088     }
1089 
1090     return error;
1091 }
1092 
HandlePropertyInsert(void)1093 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_SERVER_SERVICES>(void)
1094 {
1095     otError         error = OT_ERROR_NONE;
1096     otServiceConfig cfg;
1097     bool            stable;
1098     const uint8_t  *data;
1099     uint16_t        dataLen;
1100 
1101     VerifyOrExit(mAllowLocalServerDataChange, error = OT_ERROR_INVALID_STATE);
1102 
1103     SuccessOrExit(error = mDecoder.ReadUint32(cfg.mEnterpriseNumber));
1104     SuccessOrExit(error = mDecoder.ReadDataWithLen(data, dataLen));
1105 
1106     VerifyOrExit((dataLen <= sizeof(cfg.mServiceData)), error = OT_ERROR_INVALID_ARGS);
1107     memcpy(cfg.mServiceData, data, dataLen);
1108 
1109     static_assert((sizeof(cfg.mServiceData) <= UINT8_MAX), "Cannot handle full range of buffer length");
1110     cfg.mServiceDataLength = static_cast<uint8_t>(dataLen);
1111 
1112     SuccessOrExit(error = mDecoder.ReadBool(stable));
1113     cfg.mServerConfig.mStable = stable;
1114     SuccessOrExit(error = mDecoder.ReadDataWithLen(data, dataLen));
1115 
1116     VerifyOrExit((dataLen <= sizeof(cfg.mServerConfig.mServerData)), error = OT_ERROR_INVALID_ARGS);
1117     memcpy(cfg.mServerConfig.mServerData, data, dataLen);
1118 
1119     static_assert((sizeof(cfg.mServerConfig.mServerData) <= UINT8_MAX), "Cannot handle full range of buffer length");
1120     cfg.mServerConfig.mServerDataLength = static_cast<uint8_t>(dataLen);
1121 
1122     SuccessOrExit(error = otServerAddService(mInstance, &cfg));
1123 exit:
1124     return error;
1125 }
1126 
HandlePropertyRemove(void)1127 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_SERVER_SERVICES>(void)
1128 {
1129     otError error = OT_ERROR_NONE;
1130 
1131     uint32_t       enterpriseNumber;
1132     const uint8_t *serviceData;
1133     uint16_t       serviceDataLength;
1134 
1135     VerifyOrExit(mAllowLocalServerDataChange, error = OT_ERROR_INVALID_STATE);
1136 
1137     SuccessOrExit(error = mDecoder.ReadUint32(enterpriseNumber));
1138     SuccessOrExit(error = mDecoder.ReadDataWithLen(serviceData, serviceDataLength));
1139 
1140     VerifyOrExit(serviceDataLength <= UINT8_MAX, error = OT_ERROR_INVALID_ARGS);
1141 
1142     SuccessOrExit(error = otServerRemoveService(mInstance, enterpriseNumber, serviceData,
1143                                                 static_cast<uint8_t>(serviceDataLength)));
1144 exit:
1145     return error;
1146 }
1147 
HandlePropertyGet(void)1148 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_SERVER_SERVICES>(void)
1149 {
1150     otError               error    = OT_ERROR_NONE;
1151     otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
1152     otServiceConfig       cfg;
1153 
1154     while (otServerGetNextService(mInstance, &iterator, &cfg) == OT_ERROR_NONE)
1155     {
1156         SuccessOrExit(error = mEncoder.OpenStruct());
1157 
1158         SuccessOrExit(error = mEncoder.WriteUint32(cfg.mEnterpriseNumber));
1159         SuccessOrExit(error = mEncoder.WriteDataWithLen(cfg.mServiceData, cfg.mServiceDataLength));
1160         SuccessOrExit(error = mEncoder.WriteBool(cfg.mServerConfig.mStable));
1161         SuccessOrExit(
1162             error = mEncoder.WriteDataWithLen(cfg.mServerConfig.mServerData, cfg.mServerConfig.mServerDataLength));
1163         SuccessOrExit(error = mEncoder.WriteUint16(cfg.mServerConfig.mRloc16));
1164 
1165         SuccessOrExit(error = mEncoder.CloseStruct());
1166     }
1167 exit:
1168     return error;
1169 }
1170 #endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
1171 
HandlePropertyGet(void)1172 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_SERVER_LEADER_SERVICES>(void)
1173 {
1174     otError               error    = OT_ERROR_NONE;
1175     otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
1176     otServiceConfig       cfg;
1177 
1178     while (otNetDataGetNextService(mInstance, &iterator, &cfg) == OT_ERROR_NONE)
1179     {
1180         SuccessOrExit(error = mEncoder.OpenStruct());
1181 
1182         SuccessOrExit(error = mEncoder.WriteUint8(cfg.mServiceId));
1183         SuccessOrExit(error = mEncoder.WriteUint32(cfg.mEnterpriseNumber));
1184         SuccessOrExit(error = mEncoder.WriteDataWithLen(cfg.mServiceData, cfg.mServiceDataLength));
1185         SuccessOrExit(error = mEncoder.WriteBool(cfg.mServerConfig.mStable));
1186         SuccessOrExit(
1187             error = mEncoder.WriteDataWithLen(cfg.mServerConfig.mServerData, cfg.mServerConfig.mServerDataLength));
1188         SuccessOrExit(error = mEncoder.WriteUint16(cfg.mServerConfig.mRloc16));
1189 
1190         SuccessOrExit(error = mEncoder.CloseStruct());
1191     }
1192 exit:
1193     return error;
1194 }
1195 
HandlePropertyGet(void)1196 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_DISCOVERY_SCAN_JOINER_FLAG>(void)
1197 {
1198     return mEncoder.WriteBool(mDiscoveryScanJoinerFlag);
1199 }
1200 
HandlePropertySet(void)1201 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_DISCOVERY_SCAN_JOINER_FLAG>(void)
1202 {
1203     return mDecoder.ReadBool(mDiscoveryScanJoinerFlag);
1204 }
1205 
HandlePropertyGet(void)1206 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING>(void)
1207 {
1208     return mEncoder.WriteBool(mDiscoveryScanEnableFiltering);
1209 }
1210 
HandlePropertySet(void)1211 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING>(void)
1212 {
1213     return mDecoder.ReadBool(mDiscoveryScanEnableFiltering);
1214 }
1215 
HandlePropertyGet(void)1216 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_DISCOVERY_SCAN_PANID>(void)
1217 {
1218     return mEncoder.WriteUint16(mDiscoveryScanPanId);
1219 }
1220 
HandlePropertySet(void)1221 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_DISCOVERY_SCAN_PANID>(void)
1222 {
1223     return mDecoder.ReadUint16(mDiscoveryScanPanId);
1224 }
1225 
EncodeOperationalDataset(const otOperationalDataset & aDataset)1226 otError NcpBase::EncodeOperationalDataset(const otOperationalDataset &aDataset)
1227 {
1228     otError error = OT_ERROR_NONE;
1229 
1230     if (aDataset.mComponents.mIsActiveTimestampPresent)
1231     {
1232         const otTimestamp &activeTimestamp = aDataset.mActiveTimestamp;
1233 
1234         SuccessOrExit(error = mEncoder.OpenStruct());
1235         SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_DATASET_ACTIVE_TIMESTAMP));
1236         SuccessOrExit(error = mEncoder.WriteUint64(activeTimestamp.mSeconds));
1237         SuccessOrExit(error = mEncoder.CloseStruct());
1238     }
1239 
1240     if (aDataset.mComponents.mIsPendingTimestampPresent)
1241     {
1242         const otTimestamp &pendingTimestamp = aDataset.mPendingTimestamp;
1243 
1244         SuccessOrExit(error = mEncoder.OpenStruct());
1245         SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_DATASET_PENDING_TIMESTAMP));
1246         SuccessOrExit(error = mEncoder.WriteUint64(pendingTimestamp.mSeconds));
1247         SuccessOrExit(error = mEncoder.CloseStruct());
1248     }
1249 
1250     if (aDataset.mComponents.mIsNetworkKeyPresent)
1251     {
1252         SuccessOrExit(error = mEncoder.OpenStruct());
1253         SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_NET_NETWORK_KEY));
1254         SuccessOrExit(error = mEncoder.WriteData(aDataset.mNetworkKey.m8, OT_NETWORK_KEY_SIZE));
1255         SuccessOrExit(error = mEncoder.CloseStruct());
1256     }
1257 
1258     if (aDataset.mComponents.mIsNetworkNamePresent)
1259     {
1260         SuccessOrExit(error = mEncoder.OpenStruct());
1261         SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_NET_NETWORK_NAME));
1262         SuccessOrExit(error = mEncoder.WriteUtf8(aDataset.mNetworkName.m8));
1263         SuccessOrExit(error = mEncoder.CloseStruct());
1264     }
1265 
1266     if (aDataset.mComponents.mIsExtendedPanIdPresent)
1267     {
1268         SuccessOrExit(error = mEncoder.OpenStruct());
1269         SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_NET_XPANID));
1270         SuccessOrExit(error = mEncoder.WriteData(aDataset.mExtendedPanId.m8, OT_EXT_PAN_ID_SIZE));
1271         SuccessOrExit(error = mEncoder.CloseStruct());
1272     }
1273 
1274     if (aDataset.mComponents.mIsMeshLocalPrefixPresent)
1275     {
1276         otIp6Address addr;
1277 
1278         memcpy(addr.mFields.m8, aDataset.mMeshLocalPrefix.m8, 8);
1279         memset(addr.mFields.m8 + 8, 0, 8); // Zero out the last 8 bytes.
1280 
1281         SuccessOrExit(error = mEncoder.OpenStruct());
1282         SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_IPV6_ML_PREFIX));
1283         SuccessOrExit(error = mEncoder.WriteIp6Address(addr));             // Mesh local prefix
1284         SuccessOrExit(error = mEncoder.WriteUint8(OT_IP6_PREFIX_BITSIZE)); // Prefix length (in bits)
1285         SuccessOrExit(error = mEncoder.CloseStruct());
1286     }
1287 
1288     if (aDataset.mComponents.mIsDelayPresent)
1289     {
1290         SuccessOrExit(error = mEncoder.OpenStruct());
1291         SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_DATASET_DELAY_TIMER));
1292         SuccessOrExit(error = mEncoder.WriteUint32(aDataset.mDelay));
1293         SuccessOrExit(error = mEncoder.CloseStruct());
1294     }
1295 
1296     if (aDataset.mComponents.mIsPanIdPresent)
1297     {
1298         SuccessOrExit(error = mEncoder.OpenStruct());
1299         SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_MAC_15_4_PANID));
1300         SuccessOrExit(error = mEncoder.WriteUint16(aDataset.mPanId));
1301         SuccessOrExit(error = mEncoder.CloseStruct());
1302     }
1303 
1304     if (aDataset.mComponents.mIsChannelPresent)
1305     {
1306         SuccessOrExit(error = mEncoder.OpenStruct());
1307         SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_PHY_CHAN));
1308 
1309         // The channel is stored in Dataset as `uint16_t` (to accommodate
1310         // larger number of channels in sub-GHz band),  however the current
1311         // definition of `SPINEL_PROP_PHY_CHAN` property limits the channel
1312         // to a `uint8_t`.
1313 
1314         SuccessOrExit(error = mEncoder.WriteUint8(static_cast<uint8_t>(aDataset.mChannel)));
1315         SuccessOrExit(error = mEncoder.CloseStruct());
1316     }
1317 
1318     if (aDataset.mComponents.mIsPskcPresent)
1319     {
1320         SuccessOrExit(error = mEncoder.OpenStruct());
1321         SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_NET_PSKC));
1322         SuccessOrExit(error = mEncoder.WriteData(aDataset.mPskc.m8, sizeof(spinel_net_pskc_t)));
1323         SuccessOrExit(error = mEncoder.CloseStruct());
1324     }
1325 
1326     if (aDataset.mComponents.mIsSecurityPolicyPresent)
1327     {
1328         uint8_t flags[2];
1329 
1330         static_cast<const SecurityPolicy &>(aDataset.mSecurityPolicy).GetFlags(flags, sizeof(flags));
1331         SuccessOrExit(error = mEncoder.OpenStruct());
1332         SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_DATASET_SECURITY_POLICY));
1333         SuccessOrExit(error = mEncoder.WriteUint16(aDataset.mSecurityPolicy.mRotationTime));
1334         SuccessOrExit(error = mEncoder.WriteUint8(flags[0]));
1335         if (otThreadGetVersion() >= OT_THREAD_VERSION_1_2)
1336         {
1337             SuccessOrExit(error = mEncoder.WriteUint8(flags[1]));
1338         }
1339         SuccessOrExit(error = mEncoder.CloseStruct());
1340     }
1341 
1342     if (aDataset.mComponents.mIsChannelMaskPresent)
1343     {
1344         SuccessOrExit(error = mEncoder.OpenStruct());
1345         SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROP_PHY_CHAN_SUPPORTED));
1346         SuccessOrExit(error = EncodeChannelMask(aDataset.mChannelMask));
1347         SuccessOrExit(error = mEncoder.CloseStruct());
1348     }
1349 
1350 exit:
1351     return error;
1352 }
1353 
HandlePropertyGet(void)1354 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_ACTIVE_DATASET>(void)
1355 {
1356     otOperationalDataset dataset;
1357 
1358     IgnoreError(otDatasetGetActive(mInstance, &dataset));
1359     return EncodeOperationalDataset(dataset);
1360 }
1361 
HandlePropertyGet(void)1362 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_PENDING_DATASET>(void)
1363 {
1364     otOperationalDataset dataset;
1365 
1366     IgnoreError(otDatasetGetPending(mInstance, &dataset));
1367     return EncodeOperationalDataset(dataset);
1368 }
1369 
DecodeOperationalDataset(otOperationalDataset & aDataset,const uint8_t ** aTlvs,uint8_t * aTlvsLength,const otIp6Address ** aDestIpAddress,bool aAllowEmptyValues)1370 otError NcpBase::DecodeOperationalDataset(otOperationalDataset &aDataset,
1371                                           const uint8_t       **aTlvs,
1372                                           uint8_t              *aTlvsLength,
1373                                           const otIp6Address  **aDestIpAddress,
1374                                           bool                  aAllowEmptyValues)
1375 {
1376     otError error = OT_ERROR_NONE;
1377 
1378     memset(&aDataset, 0, sizeof(otOperationalDataset));
1379 
1380     if (aTlvs != nullptr)
1381     {
1382         *aTlvs = nullptr;
1383     }
1384 
1385     if (aTlvsLength != nullptr)
1386     {
1387         *aTlvsLength = 0;
1388     }
1389 
1390     if (aDestIpAddress != nullptr)
1391     {
1392         *aDestIpAddress = nullptr;
1393     }
1394 
1395     while (!mDecoder.IsAllReadInStruct())
1396     {
1397         unsigned int propKey;
1398 
1399         SuccessOrExit(error = mDecoder.OpenStruct());
1400         SuccessOrExit(error = mDecoder.ReadUintPacked(propKey));
1401 
1402         switch (static_cast<spinel_prop_key_t>(propKey))
1403         {
1404         case SPINEL_PROP_DATASET_ACTIVE_TIMESTAMP:
1405 
1406             if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct())
1407             {
1408                 SuccessOrExit(error = mDecoder.ReadUint64(aDataset.mActiveTimestamp.mSeconds));
1409                 aDataset.mActiveTimestamp.mTicks         = 0;
1410                 aDataset.mActiveTimestamp.mAuthoritative = false;
1411             }
1412 
1413             aDataset.mComponents.mIsActiveTimestampPresent = true;
1414             break;
1415 
1416         case SPINEL_PROP_DATASET_PENDING_TIMESTAMP:
1417 
1418             if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct())
1419             {
1420                 SuccessOrExit(error = mDecoder.ReadUint64(aDataset.mPendingTimestamp.mSeconds));
1421                 aDataset.mPendingTimestamp.mTicks         = 0;
1422                 aDataset.mPendingTimestamp.mAuthoritative = false;
1423             }
1424 
1425             aDataset.mComponents.mIsPendingTimestampPresent = true;
1426             break;
1427 
1428         case SPINEL_PROP_NET_NETWORK_KEY:
1429 
1430             if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct())
1431             {
1432                 const uint8_t *key;
1433                 uint16_t       len;
1434 
1435                 SuccessOrExit(error = mDecoder.ReadData(key, len));
1436                 VerifyOrExit(len == OT_NETWORK_KEY_SIZE, error = OT_ERROR_INVALID_ARGS);
1437                 memcpy(aDataset.mNetworkKey.m8, key, len);
1438             }
1439 
1440             aDataset.mComponents.mIsNetworkKeyPresent = true;
1441             break;
1442 
1443         case SPINEL_PROP_NET_NETWORK_NAME:
1444 
1445             if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct())
1446             {
1447                 const char *name;
1448                 size_t      len;
1449 
1450                 SuccessOrExit(error = mDecoder.ReadUtf8(name));
1451                 len = strlen(name);
1452                 VerifyOrExit(len <= OT_NETWORK_NAME_MAX_SIZE, error = OT_ERROR_INVALID_ARGS);
1453                 memcpy(aDataset.mNetworkName.m8, name, len + 1);
1454             }
1455 
1456             aDataset.mComponents.mIsNetworkNamePresent = true;
1457             break;
1458 
1459         case SPINEL_PROP_NET_XPANID:
1460 
1461             if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct())
1462             {
1463                 const uint8_t *xpanid;
1464                 uint16_t       len;
1465 
1466                 SuccessOrExit(error = mDecoder.ReadData(xpanid, len));
1467                 VerifyOrExit(len == OT_EXT_PAN_ID_SIZE, error = OT_ERROR_INVALID_ARGS);
1468                 memcpy(aDataset.mExtendedPanId.m8, xpanid, len);
1469             }
1470 
1471             aDataset.mComponents.mIsExtendedPanIdPresent = true;
1472             break;
1473 
1474         case SPINEL_PROP_IPV6_ML_PREFIX:
1475 
1476             if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct())
1477             {
1478                 const otIp6Address *addr;
1479                 uint8_t             prefixLen;
1480 
1481                 SuccessOrExit(error = mDecoder.ReadIp6Address(addr));
1482                 SuccessOrExit(error = mDecoder.ReadUint8(prefixLen));
1483                 VerifyOrExit(prefixLen == OT_IP6_PREFIX_BITSIZE, error = OT_ERROR_INVALID_ARGS);
1484                 memcpy(aDataset.mMeshLocalPrefix.m8, addr, OT_MESH_LOCAL_PREFIX_SIZE);
1485             }
1486 
1487             aDataset.mComponents.mIsMeshLocalPrefixPresent = true;
1488             break;
1489 
1490         case SPINEL_PROP_DATASET_DELAY_TIMER:
1491 
1492             if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct())
1493             {
1494                 SuccessOrExit(error = mDecoder.ReadUint32(aDataset.mDelay));
1495             }
1496 
1497             aDataset.mComponents.mIsDelayPresent = true;
1498             break;
1499 
1500         case SPINEL_PROP_MAC_15_4_PANID:
1501 
1502             if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct())
1503             {
1504                 SuccessOrExit(error = mDecoder.ReadUint16(aDataset.mPanId));
1505             }
1506 
1507             aDataset.mComponents.mIsPanIdPresent = true;
1508             break;
1509 
1510         case SPINEL_PROP_PHY_CHAN:
1511 
1512             if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct())
1513             {
1514                 uint8_t channel;
1515 
1516                 SuccessOrExit(error = mDecoder.ReadUint8(channel));
1517                 aDataset.mChannel = channel;
1518             }
1519 
1520             aDataset.mComponents.mIsChannelPresent = true;
1521             break;
1522 
1523         case SPINEL_PROP_NET_PSKC:
1524 
1525             if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct())
1526             {
1527                 const uint8_t *psk;
1528                 uint16_t       len;
1529 
1530                 SuccessOrExit(error = mDecoder.ReadData(psk, len));
1531                 VerifyOrExit(len == OT_PSKC_MAX_SIZE, error = OT_ERROR_INVALID_ARGS);
1532                 memcpy(aDataset.mPskc.m8, psk, OT_PSKC_MAX_SIZE);
1533             }
1534 
1535             aDataset.mComponents.mIsPskcPresent = true;
1536             break;
1537 
1538         case SPINEL_PROP_DATASET_SECURITY_POLICY:
1539 
1540             if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct())
1541             {
1542                 uint8_t flags[2];
1543                 uint8_t flagsLength = 1;
1544 
1545                 SuccessOrExit(error = mDecoder.ReadUint16(aDataset.mSecurityPolicy.mRotationTime));
1546                 SuccessOrExit(error = mDecoder.ReadUint8(flags[0]));
1547                 if (otThreadGetVersion() >= OT_THREAD_VERSION_1_2 && mDecoder.GetRemainingLengthInStruct() > 0)
1548                 {
1549                     SuccessOrExit(error = mDecoder.ReadUint8(flags[1]));
1550                     ++flagsLength;
1551                 }
1552                 static_cast<SecurityPolicy &>(aDataset.mSecurityPolicy).SetFlags(flags, flagsLength);
1553             }
1554 
1555             aDataset.mComponents.mIsSecurityPolicyPresent = true;
1556             break;
1557 
1558         case SPINEL_PROP_PHY_CHAN_SUPPORTED:
1559 
1560             if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct())
1561             {
1562                 uint8_t channel;
1563 
1564                 aDataset.mChannelMask = 0;
1565 
1566                 while (!mDecoder.IsAllReadInStruct())
1567                 {
1568                     SuccessOrExit(error = mDecoder.ReadUint8(channel));
1569                     VerifyOrExit(channel <= 31, error = OT_ERROR_INVALID_ARGS);
1570                     aDataset.mChannelMask |= (1UL << channel);
1571                 }
1572             }
1573 
1574             aDataset.mComponents.mIsChannelMaskPresent = true;
1575             break;
1576 
1577         case SPINEL_PROP_DATASET_RAW_TLVS:
1578 
1579             if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct())
1580             {
1581                 const uint8_t *tlvs;
1582                 uint16_t       len;
1583 
1584                 SuccessOrExit(error = mDecoder.ReadData(tlvs, len));
1585                 VerifyOrExit(len <= 255, error = OT_ERROR_INVALID_ARGS);
1586 
1587                 if (aTlvs != nullptr)
1588                 {
1589                     *aTlvs = tlvs;
1590                 }
1591 
1592                 if (aTlvsLength != nullptr)
1593                 {
1594                     *aTlvsLength = static_cast<uint8_t>(len);
1595                 }
1596             }
1597 
1598             break;
1599 
1600         case SPINEL_PROP_DATASET_DEST_ADDRESS:
1601 
1602             if (!aAllowEmptyValues || !mDecoder.IsAllReadInStruct())
1603             {
1604                 const otIp6Address *addr;
1605 
1606                 SuccessOrExit(error = mDecoder.ReadIp6Address(addr));
1607 
1608                 if (aDestIpAddress != nullptr)
1609                 {
1610                     *aDestIpAddress = addr;
1611                 }
1612             }
1613 
1614             break;
1615 
1616         default:
1617             break;
1618         }
1619 
1620         SuccessOrExit(error = mDecoder.CloseStruct());
1621     }
1622 
1623 exit:
1624     return error;
1625 }
1626 
HandlePropertySet(void)1627 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_ACTIVE_DATASET>(void)
1628 {
1629     otError              error = OT_ERROR_NONE;
1630     otOperationalDataset dataset;
1631 
1632     SuccessOrExit(error = DecodeOperationalDataset(dataset));
1633     error = otDatasetSetActive(mInstance, &dataset);
1634 
1635 exit:
1636     return error;
1637 }
1638 
HandlePropertySet(void)1639 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_PENDING_DATASET>(void)
1640 {
1641     otError              error = OT_ERROR_NONE;
1642     otOperationalDataset dataset;
1643 
1644     SuccessOrExit(error = DecodeOperationalDataset(dataset));
1645     error = otDatasetSetPending(mInstance, &dataset);
1646 
1647 exit:
1648     return error;
1649 }
1650 
HandlePropertySet(void)1651 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_MGMT_SET_ACTIVE_DATASET>(void)
1652 {
1653     otError              error = OT_ERROR_NONE;
1654     otOperationalDataset dataset;
1655     const uint8_t       *extraTlvs;
1656     uint8_t              extraTlvsLength;
1657 
1658     SuccessOrExit(error = DecodeOperationalDataset(dataset, &extraTlvs, &extraTlvsLength));
1659     error = otDatasetSendMgmtActiveSet(mInstance, &dataset, extraTlvs, extraTlvsLength, /* aCallback */ nullptr,
1660                                        /* aContext */ nullptr);
1661 
1662 exit:
1663     return error;
1664 }
1665 
HandlePropertySet(void)1666 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET>(void)
1667 {
1668     otError              error = OT_ERROR_NONE;
1669     otOperationalDataset dataset;
1670     const uint8_t       *extraTlvs;
1671     uint8_t              extraTlvsLength;
1672 
1673     SuccessOrExit(error = DecodeOperationalDataset(dataset, &extraTlvs, &extraTlvsLength));
1674     error = otDatasetSendMgmtPendingSet(mInstance, &dataset, extraTlvs, extraTlvsLength, /* aCallback */ nullptr,
1675                                         /* aContext */ nullptr);
1676 
1677 exit:
1678     return error;
1679 }
1680 
HandlePropertySet(void)1681 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_MGMT_GET_ACTIVE_DATASET>(void)
1682 {
1683     otError              error = OT_ERROR_NONE;
1684     otOperationalDataset dataset;
1685     const uint8_t       *extraTlvs;
1686     uint8_t              extraTlvsLength;
1687     const otIp6Address  *destIpAddress;
1688 
1689     SuccessOrExit(error = DecodeOperationalDataset(dataset, &extraTlvs, &extraTlvsLength, &destIpAddress, true));
1690     error = otDatasetSendMgmtActiveGet(mInstance, &dataset.mComponents, extraTlvs, extraTlvsLength, destIpAddress);
1691 
1692 exit:
1693     return error;
1694 }
1695 
HandlePropertySet(void)1696 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_MGMT_GET_PENDING_DATASET>(void)
1697 {
1698     otError              error = OT_ERROR_NONE;
1699     otOperationalDataset dataset;
1700     const uint8_t       *extraTlvs;
1701     uint8_t              extraTlvsLength;
1702     const otIp6Address  *destIpAddress;
1703 
1704     SuccessOrExit(error = DecodeOperationalDataset(dataset, &extraTlvs, &extraTlvsLength, &destIpAddress, true));
1705     error = otDatasetSendMgmtPendingGet(mInstance, &dataset.mComponents, extraTlvs, extraTlvsLength, destIpAddress);
1706 
1707 exit:
1708     return error;
1709 }
1710 #if OPENTHREAD_CONFIG_JOINER_ENABLE
HandlePropertyGet(void)1711 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MESHCOP_JOINER_STATE>(void)
1712 {
1713     spinel_meshcop_joiner_state_t state = SPINEL_MESHCOP_JOINER_STATE_IDLE;
1714 
1715     switch (otJoinerGetState(mInstance))
1716     {
1717     case OT_JOINER_STATE_IDLE:
1718         state = SPINEL_MESHCOP_JOINER_STATE_IDLE;
1719         break;
1720     case OT_JOINER_STATE_DISCOVER:
1721         state = SPINEL_MESHCOP_JOINER_STATE_DISCOVER;
1722         break;
1723     case OT_JOINER_STATE_CONNECT:
1724         state = SPINEL_MESHCOP_JOINER_STATE_CONNECTING;
1725         break;
1726     case OT_JOINER_STATE_CONNECTED:
1727         state = SPINEL_MESHCOP_JOINER_STATE_CONNECTED;
1728         break;
1729     case OT_JOINER_STATE_ENTRUST:
1730         state = SPINEL_MESHCOP_JOINER_STATE_ENTRUST;
1731         break;
1732     case OT_JOINER_STATE_JOINED:
1733         state = SPINEL_MESHCOP_JOINER_STATE_JOINED;
1734         break;
1735     }
1736 
1737     return mEncoder.WriteUint8(state);
1738 }
1739 
HandlePropertySet(void)1740 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_JOINER_COMMISSIONING>(void)
1741 {
1742     otError     error           = OT_ERROR_NONE;
1743     bool        action          = false;
1744     const char *psk             = nullptr;
1745     const char *provisioningUrl = nullptr;
1746     const char *vendorName      = nullptr;
1747     const char *vendorModel     = nullptr;
1748     const char *vendorSwVersion = nullptr;
1749     const char *vendorData      = nullptr;
1750 
1751     SuccessOrExit(error = mDecoder.ReadBool(action));
1752 
1753     if (!action)
1754     {
1755         otJoinerStop(mInstance);
1756         ExitNow();
1757     }
1758 
1759     SuccessOrExit(error = mDecoder.ReadUtf8(psk));
1760 
1761     // Parse optional fields
1762 
1763     if (!mDecoder.IsAllReadInStruct())
1764     {
1765         SuccessOrExit(error = mDecoder.ReadUtf8(provisioningUrl));
1766     }
1767 
1768     if (!mDecoder.IsAllReadInStruct())
1769     {
1770         SuccessOrExit(error = mDecoder.ReadUtf8(vendorName));
1771     }
1772 
1773     if (!mDecoder.IsAllReadInStruct())
1774     {
1775         SuccessOrExit(error = mDecoder.ReadUtf8(vendorModel));
1776     }
1777 
1778     if (!mDecoder.IsAllReadInStruct())
1779     {
1780         SuccessOrExit(error = mDecoder.ReadUtf8(vendorSwVersion));
1781     }
1782 
1783     if (!mDecoder.IsAllReadInStruct())
1784     {
1785         SuccessOrExit(error = mDecoder.ReadUtf8(vendorData));
1786     }
1787 
1788     // Use OpenThread default values for vendor name, mode, sw version if
1789     // not specified or an empty string is given.
1790 
1791     if ((vendorName == nullptr) || (vendorName[0] == 0))
1792     {
1793         vendorName = PACKAGE_NAME;
1794     }
1795 
1796     if ((vendorModel == nullptr) || (vendorModel[0] == 0))
1797     {
1798         vendorModel = OPENTHREAD_CONFIG_PLATFORM_INFO;
1799     }
1800 
1801     if ((vendorSwVersion == nullptr) || (vendorSwVersion[0] == 0))
1802     {
1803         vendorSwVersion = PACKAGE_VERSION;
1804     }
1805 
1806     error = otJoinerStart(mInstance, psk, provisioningUrl, vendorName, vendorModel, vendorSwVersion, vendorData,
1807                           &NcpBase::HandleJoinerCallback_Jump, this);
1808 
1809 exit:
1810     return error;
1811 }
1812 
HandlePropertyGet(void)1813 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MESHCOP_JOINER_DISCERNER>(void)
1814 {
1815     otError                  error;
1816     const otJoinerDiscerner *discerner = otJoinerGetDiscerner(mInstance);
1817 
1818     if (discerner == nullptr)
1819     {
1820         SuccessOrExit(error = mEncoder.WriteUint8(0));
1821     }
1822     else
1823     {
1824         SuccessOrExit(error = mEncoder.WriteUint8(discerner->mLength));
1825         SuccessOrExit(error = mEncoder.WriteUint64(discerner->mValue));
1826     }
1827 
1828 exit:
1829     return error;
1830 }
1831 
HandlePropertySet(void)1832 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MESHCOP_JOINER_DISCERNER>(void)
1833 {
1834     otError           error = OT_ERROR_NONE;
1835     otJoinerDiscerner discerner;
1836 
1837     SuccessOrExit(error = mDecoder.ReadUint8(discerner.mLength));
1838 
1839     if (discerner.mLength == 0)
1840     {
1841         // Clearing any previously set Joiner Discerner
1842         error = otJoinerSetDiscerner(mInstance, nullptr);
1843         ExitNow();
1844     }
1845 
1846     SuccessOrExit(error = mDecoder.ReadUint64(discerner.mValue));
1847     error = otJoinerSetDiscerner(mInstance, &discerner);
1848 
1849 exit:
1850     return error;
1851 }
1852 
1853 #endif // OPENTHREAD_CONFIG_JOINER_ENABLE
1854 
HandlePropertyGet(void)1855 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_ML_PREFIX>(void)
1856 {
1857     otError                  error    = OT_ERROR_NONE;
1858     const otMeshLocalPrefix *mlPrefix = otThreadGetMeshLocalPrefix(mInstance);
1859     otIp6Address             addr;
1860 
1861     VerifyOrExit(mlPrefix != nullptr); // If `mlPrefix` is nullptr send empty response.
1862 
1863     memcpy(addr.mFields.m8, mlPrefix->m8, 8);
1864 
1865     // Zero out the last 8 bytes.
1866     memset(addr.mFields.m8 + 8, 0, 8);
1867 
1868     SuccessOrExit(error = mEncoder.WriteIp6Address(addr));             // Mesh local prefix
1869     SuccessOrExit(error = mEncoder.WriteUint8(OT_IP6_PREFIX_BITSIZE)); // Prefix length (in bits)
1870 
1871 exit:
1872     return error;
1873 }
1874 
HandlePropertySet(void)1875 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_IPV6_ML_PREFIX>(void)
1876 {
1877     otError             error = OT_ERROR_NONE;
1878     const otIp6Address *meshLocalPrefix;
1879     uint8_t             prefixLength;
1880 
1881     SuccessOrExit(error = mDecoder.ReadIp6Address(meshLocalPrefix));
1882     SuccessOrExit(error = mDecoder.ReadUint8(prefixLength));
1883     VerifyOrExit(prefixLength == OT_IP6_PREFIX_BITSIZE, error = OT_ERROR_INVALID_ARGS);
1884 
1885     error = otThreadSetMeshLocalPrefix(mInstance, reinterpret_cast<const otMeshLocalPrefix *>(meshLocalPrefix));
1886 
1887 exit:
1888     return error;
1889 }
1890 
HandlePropertyGet(void)1891 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_ML_ADDR>(void)
1892 {
1893     otError             error = OT_ERROR_NONE;
1894     const otIp6Address *ml64  = otThreadGetMeshLocalEid(mInstance);
1895 
1896     VerifyOrExit(ml64 != nullptr);
1897     SuccessOrExit(error = mEncoder.WriteIp6Address(*ml64));
1898 
1899 exit:
1900     return error;
1901 }
1902 
HandlePropertyGet(void)1903 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_LL_ADDR>(void)
1904 {
1905     otError             error   = OT_ERROR_NONE;
1906     const otIp6Address *address = otThreadGetLinkLocalIp6Address(mInstance);
1907 
1908     VerifyOrExit(address != nullptr);
1909     SuccessOrExit(error = mEncoder.WriteIp6Address(*address));
1910 
1911 exit:
1912     return error;
1913 }
1914 
HandlePropertyGet(void)1915 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_ADDRESS_TABLE>(void)
1916 {
1917     otError error = OT_ERROR_NONE;
1918 
1919     for (const otNetifAddress *address = otIp6GetUnicastAddresses(mInstance); address; address = address->mNext)
1920     {
1921         SuccessOrExit(error = mEncoder.OpenStruct());
1922 
1923         SuccessOrExit(error = mEncoder.WriteIp6Address(address->mAddress));
1924         SuccessOrExit(error = mEncoder.WriteUint8(address->mPrefixLength));
1925         SuccessOrExit(error = mEncoder.WriteUint32(address->mPreferred ? 0xffffffff : 0));
1926         SuccessOrExit(error = mEncoder.WriteUint32(address->mValid ? 0xffffffff : 0));
1927 
1928         SuccessOrExit(error = mEncoder.CloseStruct());
1929     }
1930 
1931 exit:
1932     return error;
1933 }
1934 
HandlePropertyInsert(void)1935 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_IPV6_ADDRESS_TABLE>(void)
1936 {
1937     otError        error = OT_ERROR_NONE;
1938     otNetifAddress netifAddr;
1939     uint32_t       preferredLifetime;
1940     uint32_t       validLifetime;
1941 
1942     SuccessOrExit(error = mDecoder.ReadIp6Address(netifAddr.mAddress));
1943     SuccessOrExit(error = mDecoder.ReadUint8(netifAddr.mPrefixLength));
1944     SuccessOrExit(error = mDecoder.ReadUint32(preferredLifetime));
1945     SuccessOrExit(error = mDecoder.ReadUint32(validLifetime));
1946 
1947     netifAddr.mAddressOrigin = OT_ADDRESS_ORIGIN_MANUAL;
1948     netifAddr.mPreferred     = (preferredLifetime != 0);
1949     netifAddr.mValid         = (validLifetime != 0);
1950 
1951     error = otIp6AddUnicastAddress(mInstance, &netifAddr);
1952 
1953 exit:
1954     return error;
1955 }
1956 
HandlePropertyRemove(void)1957 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_IPV6_ADDRESS_TABLE>(void)
1958 {
1959     otError             error = OT_ERROR_NONE;
1960     const otIp6Address *addrPtr;
1961 
1962     SuccessOrExit(error = mDecoder.ReadIp6Address(addrPtr));
1963 
1964     error = otIp6RemoveUnicastAddress(mInstance, addrPtr);
1965 
1966     // If address was not on the list, "remove" command is successful.
1967     if (error == OT_ERROR_NOT_FOUND)
1968     {
1969         error = OT_ERROR_NONE;
1970     }
1971 
1972 exit:
1973     return error;
1974 }
1975 
HandlePropertyGet(void)1976 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_ROUTE_TABLE>(void)
1977 {
1978     // TODO: Implement get route table
1979     return mEncoder.OverwriteWithLastStatusError(SPINEL_STATUS_UNIMPLEMENTED);
1980 }
1981 
HandlePropertyGet(void)1982 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_ICMP_PING_OFFLOAD>(void)
1983 {
1984     return mEncoder.WriteBool(otIcmp6GetEchoMode(mInstance) != OT_ICMP6_ECHO_HANDLER_DISABLED);
1985 }
1986 
HandlePropertySet(void)1987 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_IPV6_ICMP_PING_OFFLOAD>(void)
1988 {
1989     bool    enabled = false;
1990     otError error   = OT_ERROR_NONE;
1991 
1992     SuccessOrExit(error = mDecoder.ReadBool(enabled));
1993 
1994     otIcmp6SetEchoMode(mInstance, enabled ? OT_ICMP6_ECHO_HANDLER_ALL : OT_ICMP6_ECHO_HANDLER_DISABLED);
1995 
1996 exit:
1997     return error;
1998 }
1999 
HandlePropertyGet(void)2000 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE>(void)
2001 {
2002     otError                        error = OT_ERROR_NONE;
2003     const otNetifMulticastAddress *address;
2004 
2005     for (address = otIp6GetMulticastAddresses(mInstance); address; address = address->mNext)
2006     {
2007         SuccessOrExit(error = mEncoder.OpenStruct());
2008         SuccessOrExit(error = mEncoder.WriteIp6Address(address->mAddress));
2009         SuccessOrExit(error = mEncoder.CloseStruct());
2010     }
2011 
2012 exit:
2013     return error;
2014 }
2015 
HandlePropertyInsert(void)2016 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE>(void)
2017 {
2018     otError             error = OT_ERROR_NONE;
2019     const otIp6Address *addrPtr;
2020 
2021     SuccessOrExit(error = mDecoder.ReadIp6Address(addrPtr));
2022 
2023     error = otIp6SubscribeMulticastAddress(mInstance, addrPtr);
2024 
2025     if (error == OT_ERROR_ALREADY)
2026     {
2027         error = OT_ERROR_NONE;
2028     }
2029 
2030 exit:
2031     return error;
2032 }
2033 
HandlePropertyRemove(void)2034 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE>(void)
2035 {
2036     otError             error = OT_ERROR_NONE;
2037     const otIp6Address *addrPtr;
2038 
2039     SuccessOrExit(error = mDecoder.ReadIp6Address(addrPtr));
2040 
2041     error = otIp6UnsubscribeMulticastAddress(mInstance, addrPtr);
2042 
2043     // If the address was not on the list, "remove" command is successful,
2044     // and we respond with a `SPINEL_STATUS_OK` status.
2045     if (error == OT_ERROR_NOT_FOUND)
2046     {
2047         error = OT_ERROR_NONE;
2048     }
2049 
2050 exit:
2051     return error;
2052 }
2053 
HandlePropertyGet(void)2054 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_ICMP_PING_OFFLOAD_MODE>(void)
2055 {
2056     spinel_ipv6_icmp_ping_offload_mode_t mode = SPINEL_IPV6_ICMP_PING_OFFLOAD_DISABLED;
2057 
2058     switch (otIcmp6GetEchoMode(mInstance))
2059     {
2060     case OT_ICMP6_ECHO_HANDLER_DISABLED:
2061         mode = SPINEL_IPV6_ICMP_PING_OFFLOAD_DISABLED;
2062         break;
2063     case OT_ICMP6_ECHO_HANDLER_UNICAST_ONLY:
2064         mode = SPINEL_IPV6_ICMP_PING_OFFLOAD_UNICAST_ONLY;
2065         break;
2066     case OT_ICMP6_ECHO_HANDLER_MULTICAST_ONLY:
2067         mode = SPINEL_IPV6_ICMP_PING_OFFLOAD_MULTICAST_ONLY;
2068         break;
2069     case OT_ICMP6_ECHO_HANDLER_ALL:
2070         mode = SPINEL_IPV6_ICMP_PING_OFFLOAD_ALL;
2071         break;
2072     };
2073 
2074     return mEncoder.WriteUint8(mode);
2075 }
2076 
HandlePropertySet(void)2077 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_IPV6_ICMP_PING_OFFLOAD_MODE>(void)
2078 {
2079     otError         error = OT_ERROR_NONE;
2080     otIcmp6EchoMode mode  = OT_ICMP6_ECHO_HANDLER_DISABLED;
2081     uint8_t         spinelMode;
2082 
2083     SuccessOrExit(error = mDecoder.ReadUint8(spinelMode));
2084 
2085     switch (spinelMode)
2086     {
2087     case SPINEL_IPV6_ICMP_PING_OFFLOAD_DISABLED:
2088         mode = OT_ICMP6_ECHO_HANDLER_DISABLED;
2089         break;
2090     case SPINEL_IPV6_ICMP_PING_OFFLOAD_UNICAST_ONLY:
2091         mode = OT_ICMP6_ECHO_HANDLER_UNICAST_ONLY;
2092         break;
2093     case SPINEL_IPV6_ICMP_PING_OFFLOAD_MULTICAST_ONLY:
2094         mode = OT_ICMP6_ECHO_HANDLER_MULTICAST_ONLY;
2095         break;
2096     case SPINEL_IPV6_ICMP_PING_OFFLOAD_ALL:
2097         mode = OT_ICMP6_ECHO_HANDLER_ALL;
2098         break;
2099     };
2100 
2101     otIcmp6SetEchoMode(mInstance, mode);
2102 
2103 exit:
2104     return error;
2105 }
2106 
HandlePropertyGet(void)2107 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_RLOC16_DEBUG_PASSTHRU>(void)
2108 {
2109     // Note reverse logic: passthru enabled = filter disabled
2110     return mEncoder.WriteBool(!otIp6IsReceiveFilterEnabled(mInstance));
2111 }
2112 
HandlePropertySet(void)2113 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_RLOC16_DEBUG_PASSTHRU>(void)
2114 {
2115     bool    enabled = false;
2116     otError error   = OT_ERROR_NONE;
2117 
2118     SuccessOrExit(error = mDecoder.ReadBool(enabled));
2119 
2120     // Note reverse logic: passthru enabled = filter disabled
2121     otIp6SetReceiveFilterEnabled(mInstance, !enabled);
2122 
2123 exit:
2124     return error;
2125 }
2126 
HandlePropertyGet(void)2127 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_OFF_MESH_ROUTES>(void)
2128 {
2129     otError               error = OT_ERROR_NONE;
2130     otExternalRouteConfig routeConfig;
2131     otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT;
2132 
2133     while (otNetDataGetNextRoute(mInstance, &iter, &routeConfig) == OT_ERROR_NONE)
2134     {
2135         SuccessOrExit(error = mEncoder.OpenStruct());
2136 
2137         SuccessOrExit(error = mEncoder.WriteIp6Address(routeConfig.mPrefix.mPrefix));
2138         SuccessOrExit(error = mEncoder.WriteUint8(routeConfig.mPrefix.mLength));
2139         SuccessOrExit(error = mEncoder.WriteBool(routeConfig.mStable));
2140         SuccessOrExit(error = mEncoder.WriteUint8(ExternalRouteConfigToFlagByte(routeConfig)));
2141         SuccessOrExit(error = mEncoder.WriteBool(false)); // IsLocal
2142         SuccessOrExit(error = mEncoder.WriteBool(routeConfig.mNextHopIsThisDevice));
2143         SuccessOrExit(error = mEncoder.WriteUint16(routeConfig.mRloc16));
2144 
2145         SuccessOrExit(error = mEncoder.CloseStruct());
2146     }
2147 
2148 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
2149 
2150     iter = OT_NETWORK_DATA_ITERATOR_INIT;
2151 
2152     while (otBorderRouterGetNextRoute(mInstance, &iter, &routeConfig) == OT_ERROR_NONE)
2153     {
2154         SuccessOrExit(error = mEncoder.OpenStruct());
2155 
2156         SuccessOrExit(error = mEncoder.WriteIp6Address(routeConfig.mPrefix.mPrefix));
2157         SuccessOrExit(error = mEncoder.WriteUint8(routeConfig.mPrefix.mLength));
2158         SuccessOrExit(error = mEncoder.WriteBool(routeConfig.mStable));
2159         SuccessOrExit(error = mEncoder.WriteUint8(ExternalRouteConfigToFlagByte(routeConfig)));
2160         SuccessOrExit(error = mEncoder.WriteBool(true)); // IsLocal
2161         SuccessOrExit(error = mEncoder.WriteBool(routeConfig.mNextHopIsThisDevice));
2162         SuccessOrExit(error = mEncoder.WriteUint16(routeConfig.mRloc16));
2163 
2164         SuccessOrExit(error = mEncoder.CloseStruct());
2165     }
2166 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
2167 
2168 exit:
2169     return error;
2170 }
2171 
2172 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
FlagByteToExternalRoutePreference(uint8_t aFlags)2173 static int FlagByteToExternalRoutePreference(uint8_t aFlags)
2174 {
2175     int route_preference = 0;
2176 
2177     switch (aFlags & SPINEL_NET_FLAG_PREFERENCE_MASK)
2178     {
2179     case SPINEL_ROUTE_PREFERENCE_HIGH:
2180         route_preference = OT_ROUTE_PREFERENCE_HIGH;
2181         break;
2182 
2183     case SPINEL_ROUTE_PREFERENCE_MEDIUM:
2184         route_preference = OT_ROUTE_PREFERENCE_MED;
2185         break;
2186 
2187     case SPINEL_ROUTE_PREFERENCE_LOW:
2188         route_preference = OT_ROUTE_PREFERENCE_LOW;
2189         break;
2190     }
2191 
2192     return route_preference;
2193 }
2194 
HandlePropertyInsert(void)2195 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_THREAD_OFF_MESH_ROUTES>(void)
2196 {
2197     otError               error = OT_ERROR_NONE;
2198     otExternalRouteConfig routeConfig;
2199     bool                  stable = false;
2200     uint8_t               flags  = 0;
2201     uint8_t               prefixLength;
2202 
2203     memset(&routeConfig, 0, sizeof(otExternalRouteConfig));
2204 
2205     VerifyOrExit(mAllowLocalNetworkDataChange, error = OT_ERROR_INVALID_STATE);
2206 
2207     SuccessOrExit(error = mDecoder.ReadIp6Address(routeConfig.mPrefix.mPrefix));
2208     SuccessOrExit(error = mDecoder.ReadUint8(prefixLength));
2209     SuccessOrExit(error = mDecoder.ReadBool(stable));
2210     SuccessOrExit(error = mDecoder.ReadUint8(flags));
2211 
2212     routeConfig.mPrefix.mLength = prefixLength;
2213     routeConfig.mStable         = stable;
2214     routeConfig.mPreference     = FlagByteToExternalRoutePreference(flags);
2215     routeConfig.mNat64          = ((flags & SPINEL_ROUTE_FLAG_NAT64) != 0);
2216 
2217     error = otBorderRouterAddRoute(mInstance, &routeConfig);
2218 
2219 exit:
2220     return error;
2221 }
2222 
HandlePropertyRemove(void)2223 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_THREAD_OFF_MESH_ROUTES>(void)
2224 {
2225     otError     error = OT_ERROR_NONE;
2226     otIp6Prefix ip6Prefix;
2227     uint8_t     prefixLength;
2228 
2229     memset(&ip6Prefix, 0, sizeof(otIp6Prefix));
2230 
2231     VerifyOrExit(mAllowLocalNetworkDataChange, error = OT_ERROR_INVALID_STATE);
2232 
2233     SuccessOrExit(error = mDecoder.ReadIp6Address(ip6Prefix.mPrefix));
2234     SuccessOrExit(error = mDecoder.ReadUint8(prefixLength));
2235 
2236     ip6Prefix.mLength = prefixLength;
2237 
2238     error = otBorderRouterRemoveRoute(mInstance, &ip6Prefix);
2239 
2240     // If the route prefix was not on the list, "remove" command is successful.
2241     if (error == OT_ERROR_NOT_FOUND)
2242     {
2243         error = OT_ERROR_NONE;
2244     }
2245 
2246 exit:
2247     return error;
2248 }
2249 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
2250 
HandlePropertySet(void)2251 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_STREAM_NET>(void)
2252 {
2253     const uint8_t *framePtr = nullptr;
2254     uint16_t       frameLen = 0;
2255     const uint8_t *metaPtr  = nullptr;
2256     uint16_t       metaLen  = 0;
2257     otMessage     *message  = nullptr;
2258     otError        error    = OT_ERROR_NONE;
2259 
2260     SuccessOrExit(error = mDecoder.ReadDataWithLen(framePtr, frameLen));
2261     SuccessOrExit(error = mDecoder.ReadData(metaPtr, metaLen));
2262 
2263     // We ignore metadata for now.
2264     // May later include TX power, allow retransmits, etc...
2265 
2266     // STREAM_NET requires layer 2 security.
2267     message = otIp6NewMessageFromBuffer(mInstance, framePtr, frameLen, nullptr);
2268     VerifyOrExit(message != nullptr, error = OT_ERROR_NO_BUFS);
2269 
2270     error = otIp6Send(mInstance, message);
2271 
2272 exit:
2273 
2274     if (error == OT_ERROR_NONE)
2275     {
2276         mInboundSecureIpFrameCounter++;
2277     }
2278     else
2279     {
2280         mDroppedInboundIpFrameCounter++;
2281     }
2282 
2283     return error;
2284 }
2285 
2286 #if OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE
2287 
HandlePropertyGet(void)2288 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_JAM_DETECT_ENABLE>(void)
2289 {
2290     return mEncoder.WriteBool(otJamDetectionIsEnabled(mInstance));
2291 }
2292 
HandlePropertyGet(void)2293 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_JAM_DETECTED>(void)
2294 {
2295     return mEncoder.WriteBool(otJamDetectionGetState(mInstance));
2296 }
2297 
HandlePropertyGet(void)2298 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_JAM_DETECT_RSSI_THRESHOLD>(void)
2299 {
2300     return mEncoder.WriteInt8(otJamDetectionGetRssiThreshold(mInstance));
2301 }
2302 
HandlePropertyGet(void)2303 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_JAM_DETECT_WINDOW>(void)
2304 {
2305     return mEncoder.WriteUint8(otJamDetectionGetWindow(mInstance));
2306 }
2307 
HandlePropertyGet(void)2308 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_JAM_DETECT_BUSY>(void)
2309 {
2310     return mEncoder.WriteUint8(otJamDetectionGetBusyPeriod(mInstance));
2311 }
2312 
HandlePropertyGet(void)2313 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_JAM_DETECT_HISTORY_BITMAP>(void)
2314 {
2315     return mEncoder.WriteUint64(otJamDetectionGetHistoryBitmap(mInstance));
2316 }
2317 
HandlePropertySet(void)2318 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_JAM_DETECT_ENABLE>(void)
2319 {
2320     bool    enabled;
2321     otError error = OT_ERROR_NONE;
2322 
2323     SuccessOrExit(error = mDecoder.ReadBool(enabled));
2324 
2325     if (enabled)
2326     {
2327         IgnoreError(otJamDetectionStart(mInstance, &NcpBase::HandleJamStateChange_Jump, this));
2328     }
2329     else
2330     {
2331         IgnoreError(otJamDetectionStop(mInstance));
2332     }
2333 
2334 exit:
2335     return error;
2336 }
2337 
HandlePropertySet(void)2338 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_JAM_DETECT_RSSI_THRESHOLD>(void)
2339 {
2340     int8_t  threshold = 0;
2341     otError error     = OT_ERROR_NONE;
2342 
2343     SuccessOrExit(error = mDecoder.ReadInt8(threshold));
2344 
2345     error = otJamDetectionSetRssiThreshold(mInstance, threshold);
2346 
2347 exit:
2348     return error;
2349 }
2350 
HandlePropertySet(void)2351 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_JAM_DETECT_WINDOW>(void)
2352 {
2353     uint8_t window = 0;
2354     otError error  = OT_ERROR_NONE;
2355 
2356     SuccessOrExit(error = mDecoder.ReadUint8(window));
2357 
2358     error = otJamDetectionSetWindow(mInstance, window);
2359 
2360 exit:
2361     return error;
2362 }
2363 
HandlePropertySet(void)2364 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_JAM_DETECT_BUSY>(void)
2365 {
2366     uint8_t busy  = 0;
2367     otError error = OT_ERROR_NONE;
2368 
2369     SuccessOrExit(error = mDecoder.ReadUint8(busy));
2370 
2371     error = otJamDetectionSetBusyPeriod(mInstance, busy);
2372 
2373 exit:
2374     return error;
2375 }
2376 
HandleJamStateChange_Jump(bool aJamState,void * aContext)2377 void NcpBase::HandleJamStateChange_Jump(bool aJamState, void *aContext)
2378 {
2379     static_cast<NcpBase *>(aContext)->HandleJamStateChange(aJamState);
2380 }
2381 
HandleJamStateChange(bool aJamState)2382 void NcpBase::HandleJamStateChange(bool aJamState)
2383 {
2384     OT_UNUSED_VARIABLE(aJamState);
2385 
2386     mChangedPropsSet.AddProperty(SPINEL_PROP_JAM_DETECTED);
2387     mUpdateChangedPropsTask.Post();
2388 }
2389 
2390 #endif // OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE
2391 
HandlePropertyGet(void)2392 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHILD_SUPERVISION_CHECK_TIMEOUT>(void)
2393 {
2394     return mEncoder.WriteUint16(otChildSupervisionGetCheckTimeout(mInstance));
2395 }
2396 
HandlePropertySet(void)2397 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CHILD_SUPERVISION_CHECK_TIMEOUT>(void)
2398 {
2399     otError  error = OT_ERROR_NONE;
2400     uint16_t timeout;
2401 
2402     SuccessOrExit(error = mDecoder.ReadUint16(timeout));
2403     otChildSupervisionSetCheckTimeout(mInstance, timeout);
2404 
2405 exit:
2406     return error;
2407 }
2408 
2409 #if OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE
2410 
HandlePropertyGet(void)2411 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MONITOR_SAMPLE_INTERVAL>(void)
2412 {
2413     return mEncoder.WriteUint32(otChannelMonitorGetSampleInterval(mInstance));
2414 }
2415 
HandlePropertyGet(void)2416 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MONITOR_RSSI_THRESHOLD>(void)
2417 {
2418     return mEncoder.WriteInt8(otChannelMonitorGetRssiThreshold(mInstance));
2419 }
2420 
HandlePropertyGet(void)2421 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MONITOR_SAMPLE_WINDOW>(void)
2422 {
2423     return mEncoder.WriteUint32(otChannelMonitorGetSampleWindow(mInstance));
2424 }
2425 
HandlePropertyGet(void)2426 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MONITOR_SAMPLE_COUNT>(void)
2427 {
2428     return mEncoder.WriteUint32(otChannelMonitorGetSampleCount(mInstance));
2429 }
2430 
HandlePropertyGet(void)2431 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CHANNEL_MONITOR_CHANNEL_OCCUPANCY>(void)
2432 {
2433     otError  error       = OT_ERROR_NONE;
2434     uint32_t channelMask = otLinkGetSupportedChannelMask(mInstance);
2435     uint8_t  channelNum  = sizeof(channelMask) * CHAR_BIT;
2436 
2437     for (uint8_t channel = 0; channel < channelNum; channel++)
2438     {
2439         if (!((1UL << channel) & channelMask))
2440         {
2441             continue;
2442         }
2443 
2444         SuccessOrExit(error = mEncoder.OpenStruct());
2445 
2446         SuccessOrExit(error = mEncoder.WriteUint8(channel));
2447         SuccessOrExit(error = mEncoder.WriteUint16(otChannelMonitorGetChannelOccupancy(mInstance, channel)));
2448 
2449         SuccessOrExit(error = mEncoder.CloseStruct());
2450     }
2451 
2452 exit:
2453     return error;
2454 }
2455 
2456 #endif // OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE
2457 
HandlePropertyGet(void)2458 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_CCA_FAILURE_RATE>(void)
2459 {
2460     return mEncoder.WriteUint16(otLinkGetCcaFailureRate(mInstance));
2461 }
2462 
HandlePropertyGet(void)2463 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_TOTAL>(void)
2464 {
2465     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxTotal);
2466 }
2467 
HandlePropertyGet(void)2468 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_ACK_REQ>(void)
2469 {
2470     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxAckRequested);
2471 }
2472 
HandlePropertyGet(void)2473 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_ACKED>(void)
2474 {
2475     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxAcked);
2476 }
2477 
HandlePropertyGet(void)2478 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_NO_ACK_REQ>(void)
2479 {
2480     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxNoAckRequested);
2481 }
2482 
HandlePropertyGet(void)2483 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_DATA>(void)
2484 {
2485     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxData);
2486 }
2487 
HandlePropertyGet(void)2488 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_DATA_POLL>(void)
2489 {
2490     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxDataPoll);
2491 }
2492 
HandlePropertyGet(void)2493 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_BEACON>(void)
2494 {
2495     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxBeacon);
2496 }
2497 
HandlePropertyGet(void)2498 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_BEACON_REQ>(void)
2499 {
2500     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxBeaconRequest);
2501 }
2502 
HandlePropertyGet(void)2503 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_OTHER>(void)
2504 {
2505     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxOther);
2506 }
2507 
HandlePropertyGet(void)2508 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_RETRY>(void)
2509 {
2510     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxRetry);
2511 }
2512 
HandlePropertyGet(void)2513 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_ERR_CCA>(void)
2514 {
2515     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxErrCca);
2516 }
2517 
HandlePropertyGet(void)2518 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_UNICAST>(void)
2519 {
2520     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxUnicast);
2521 }
2522 
HandlePropertyGet(void)2523 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_PKT_BROADCAST>(void)
2524 {
2525     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxBroadcast);
2526 }
2527 
HandlePropertyGet(void)2528 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_ERR_ABORT>(void)
2529 {
2530     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxErrAbort);
2531 }
2532 
HandlePropertyGet(void)2533 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_TOTAL>(void)
2534 {
2535     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxTotal);
2536 }
2537 
HandlePropertyGet(void)2538 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_DATA>(void)
2539 {
2540     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxData);
2541 }
2542 
HandlePropertyGet(void)2543 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_DATA_POLL>(void)
2544 {
2545     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxDataPoll);
2546 }
2547 
HandlePropertyGet(void)2548 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_BEACON>(void)
2549 {
2550     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxBeacon);
2551 }
2552 
HandlePropertyGet(void)2553 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_BEACON_REQ>(void)
2554 {
2555     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxBeaconRequest);
2556 }
2557 
HandlePropertyGet(void)2558 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_OTHER>(void)
2559 {
2560     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxOther);
2561 }
2562 
HandlePropertyGet(void)2563 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_FILT_WL>(void)
2564 {
2565     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxAddressFiltered);
2566 }
2567 
HandlePropertyGet(void)2568 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_FILT_DA>(void)
2569 {
2570     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxDestAddrFiltered);
2571 }
2572 
HandlePropertyGet(void)2573 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_DUP>(void)
2574 {
2575     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxDuplicated);
2576 }
2577 
HandlePropertyGet(void)2578 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_UNICAST>(void)
2579 {
2580     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxUnicast);
2581 }
2582 
HandlePropertyGet(void)2583 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_PKT_BROADCAST>(void)
2584 {
2585     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxBroadcast);
2586 }
2587 
HandlePropertyGet(void)2588 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_ERR_EMPTY>(void)
2589 {
2590     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrNoFrame);
2591 }
2592 
HandlePropertyGet(void)2593 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_ERR_UKWN_NBR>(void)
2594 {
2595     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrUnknownNeighbor);
2596 }
2597 
HandlePropertyGet(void)2598 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_ERR_NVLD_SADDR>(void)
2599 {
2600     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrInvalidSrcAddr);
2601 }
2602 
HandlePropertyGet(void)2603 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_ERR_SECURITY>(void)
2604 {
2605     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrSec);
2606 }
2607 
HandlePropertyGet(void)2608 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_ERR_BAD_FCS>(void)
2609 {
2610     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrFcs);
2611 }
2612 
HandlePropertyGet(void)2613 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_ERR_OTHER>(void)
2614 {
2615     return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrOther);
2616 }
2617 
HandlePropertyGet(void)2618 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_IP_SEC_TOTAL>(void)
2619 {
2620     return mEncoder.WriteUint32(mInboundSecureIpFrameCounter);
2621 }
2622 
HandlePropertyGet(void)2623 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_IP_INSEC_TOTAL>(void)
2624 {
2625     return mEncoder.WriteUint32(mInboundInsecureIpFrameCounter);
2626 }
2627 
HandlePropertyGet(void)2628 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_IP_DROPPED>(void)
2629 {
2630     return mEncoder.WriteUint32(mDroppedInboundIpFrameCounter);
2631 }
2632 
HandlePropertyGet(void)2633 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_IP_SEC_TOTAL>(void)
2634 {
2635     return mEncoder.WriteUint32(mOutboundSecureIpFrameCounter);
2636 }
2637 
HandlePropertyGet(void)2638 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_IP_INSEC_TOTAL>(void)
2639 {
2640     return mEncoder.WriteUint32(mOutboundInsecureIpFrameCounter);
2641 }
2642 
HandlePropertyGet(void)2643 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_IP_DROPPED>(void)
2644 {
2645     return mEncoder.WriteUint32(mDroppedOutboundIpFrameCounter);
2646 }
2647 
HandlePropertyGet(void)2648 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_TX_SPINEL_TOTAL>(void)
2649 {
2650     return mEncoder.WriteUint32(mTxSpinelFrameCounter);
2651 }
2652 
HandlePropertyGet(void)2653 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_SPINEL_TOTAL>(void)
2654 {
2655     return mEncoder.WriteUint32(mRxSpinelFrameCounter);
2656 }
2657 
HandlePropertyGet(void)2658 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_SPINEL_OUT_OF_ORDER_TID>(void)
2659 {
2660     return mEncoder.WriteUint32(mRxSpinelOutOfOrderTidCounter);
2661 }
2662 
HandlePropertyGet(void)2663 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_RX_SPINEL_ERR>(void)
2664 {
2665     return mEncoder.WriteUint32(mFramingErrorCounter);
2666 }
2667 
HandlePropertyGet(void)2668 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_IP_TX_SUCCESS>(void)
2669 {
2670     return mEncoder.WriteUint32(otThreadGetIp6Counters(mInstance)->mTxSuccess);
2671 }
2672 
HandlePropertyGet(void)2673 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_IP_RX_SUCCESS>(void)
2674 {
2675     return mEncoder.WriteUint32(otThreadGetIp6Counters(mInstance)->mRxSuccess);
2676 }
2677 
HandlePropertyGet(void)2678 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_IP_TX_FAILURE>(void)
2679 {
2680     return mEncoder.WriteUint32(otThreadGetIp6Counters(mInstance)->mTxFailure);
2681 }
2682 
HandlePropertyGet(void)2683 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_IP_RX_FAILURE>(void)
2684 {
2685     return mEncoder.WriteUint32(otThreadGetIp6Counters(mInstance)->mRxFailure);
2686 }
2687 
HandlePropertyGet(void)2688 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MSG_BUFFER_COUNTERS>(void)
2689 {
2690     otError      error = OT_ERROR_NONE;
2691     otBufferInfo bufferInfo;
2692 
2693     otMessageGetBufferInfo(mInstance, &bufferInfo);
2694 
2695     SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mTotalBuffers));
2696     SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mFreeBuffers));
2697 
2698     SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.m6loSendQueue.mNumMessages));
2699     SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.m6loSendQueue.mNumBuffers));
2700     SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.m6loReassemblyQueue.mNumMessages));
2701     SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.m6loReassemblyQueue.mNumBuffers));
2702     SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mIp6Queue.mNumMessages));
2703     SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mIp6Queue.mNumBuffers));
2704     SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mMplQueue.mNumMessages));
2705     SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mMplQueue.mNumBuffers));
2706     SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mMleQueue.mNumMessages));
2707     SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mMleQueue.mNumBuffers));
2708     SuccessOrExit(error = mEncoder.WriteUint16(0)); // Write zero for ARP for backward compatibility.
2709     SuccessOrExit(error = mEncoder.WriteUint16(0));
2710     SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mCoapQueue.mNumMessages));
2711     SuccessOrExit(error = mEncoder.WriteUint16(bufferInfo.mCoapQueue.mNumBuffers));
2712 
2713 exit:
2714     return error;
2715 }
2716 
HandlePropertyGet(void)2717 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_ALL_MAC_COUNTERS>(void)
2718 {
2719     otError              error    = OT_ERROR_NONE;
2720     const otMacCounters *counters = otLinkGetCounters(mInstance);
2721 
2722     // Encode Tx related counters
2723     SuccessOrExit(error = mEncoder.OpenStruct());
2724     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxTotal));
2725     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxUnicast));
2726     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxBroadcast));
2727     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxAckRequested));
2728     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxAcked));
2729     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxNoAckRequested));
2730     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxData));
2731     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxDataPoll));
2732     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxBeacon));
2733     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxBeaconRequest));
2734     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxOther));
2735     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxRetry));
2736     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxErrCca));
2737     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxErrAbort));
2738     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxErrBusyChannel));
2739     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxDirectMaxRetryExpiry));
2740     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxIndirectMaxRetryExpiry));
2741     SuccessOrExit(error = mEncoder.CloseStruct());
2742 
2743     // Encode Rx related counters
2744     SuccessOrExit(error = mEncoder.OpenStruct());
2745     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxTotal));
2746     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxUnicast));
2747     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxBroadcast));
2748     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxData));
2749     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxDataPoll));
2750     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxBeacon));
2751     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxBeaconRequest));
2752     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxOther));
2753     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxAddressFiltered));
2754     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxDestAddrFiltered));
2755     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxDuplicated));
2756     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxErrNoFrame));
2757     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxErrUnknownNeighbor));
2758     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxErrInvalidSrcAddr));
2759     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxErrSec));
2760     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxErrFcs));
2761     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxErrOther));
2762     SuccessOrExit(error = mEncoder.CloseStruct());
2763 
2764 exit:
2765     return error;
2766 }
2767 
HandlePropertySet(void)2768 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CNTR_ALL_MAC_COUNTERS>(void)
2769 {
2770     otLinkResetCounters(mInstance);
2771 
2772     return OT_ERROR_NONE;
2773 }
2774 
HandlePropertyGet(void)2775 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_MLE_COUNTERS>(void)
2776 {
2777     otError              error    = OT_ERROR_NONE;
2778     const otMleCounters *counters = otThreadGetMleCounters(mInstance);
2779 
2780     OT_ASSERT(counters != nullptr);
2781 
2782     SuccessOrExit(error = mEncoder.WriteUint16(counters->mDisabledRole));
2783     SuccessOrExit(error = mEncoder.WriteUint16(counters->mDetachedRole));
2784     SuccessOrExit(error = mEncoder.WriteUint16(counters->mChildRole));
2785     SuccessOrExit(error = mEncoder.WriteUint16(counters->mRouterRole));
2786     SuccessOrExit(error = mEncoder.WriteUint16(counters->mLeaderRole));
2787     SuccessOrExit(error = mEncoder.WriteUint16(counters->mAttachAttempts));
2788     SuccessOrExit(error = mEncoder.WriteUint16(counters->mPartitionIdChanges));
2789     SuccessOrExit(error = mEncoder.WriteUint16(counters->mBetterPartitionAttachAttempts));
2790     SuccessOrExit(error = mEncoder.WriteUint16(counters->mParentChanges));
2791 
2792 exit:
2793     return error;
2794 }
2795 
HandlePropertySet(void)2796 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CNTR_MLE_COUNTERS>(void)
2797 {
2798     otThreadResetMleCounters(mInstance);
2799 
2800     return OT_ERROR_NONE;
2801 }
2802 
HandlePropertyGet(void)2803 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_ALL_IP_COUNTERS>(void)
2804 {
2805     otError             error    = OT_ERROR_NONE;
2806     const otIpCounters *counters = otThreadGetIp6Counters(mInstance);
2807 
2808     OT_ASSERT(counters != nullptr);
2809 
2810     // Encode Tx related counters
2811     SuccessOrExit(error = mEncoder.OpenStruct());
2812     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxSuccess));
2813     SuccessOrExit(error = mEncoder.WriteUint32(counters->mTxFailure));
2814     SuccessOrExit(error = mEncoder.CloseStruct());
2815 
2816     // Encode Rx related counters
2817     SuccessOrExit(error = mEncoder.OpenStruct());
2818     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxSuccess));
2819     SuccessOrExit(error = mEncoder.WriteUint32(counters->mRxFailure));
2820     SuccessOrExit(error = mEncoder.CloseStruct());
2821 
2822 exit:
2823     return error;
2824 }
2825 
2826 #if OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE
HandlePropertyGet(void)2827 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CNTR_MAC_RETRY_HISTOGRAM>(void)
2828 {
2829     otError         error = OT_ERROR_NONE;
2830     const uint32_t *histogramDirect;
2831     const uint32_t *histogramIndirect;
2832     uint8_t         histogramDirectEntries;
2833     uint8_t         histogramIndirectEntries;
2834 
2835     histogramDirect   = otLinkGetTxDirectRetrySuccessHistogram(mInstance, &histogramDirectEntries);
2836     histogramIndirect = otLinkGetTxIndirectRetrySuccessHistogram(mInstance, &histogramIndirectEntries);
2837 
2838     OT_ASSERT((histogramDirectEntries == 0) || (histogramDirect != nullptr));
2839     OT_ASSERT((histogramIndirectEntries == 0) || (histogramIndirect != nullptr));
2840 
2841     // Encode direct message retries histogram
2842     SuccessOrExit(error = mEncoder.OpenStruct());
2843     for (uint8_t i = 0; i < histogramDirectEntries; i++)
2844     {
2845         SuccessOrExit(error = mEncoder.WriteUint32(histogramDirect[i]));
2846     }
2847     SuccessOrExit(error = mEncoder.CloseStruct());
2848 
2849     // Encode indirect message retries histogram
2850     SuccessOrExit(error = mEncoder.OpenStruct());
2851     for (uint8_t i = 0; i < histogramIndirectEntries; i++)
2852     {
2853         SuccessOrExit(error = mEncoder.WriteUint32(histogramIndirect[i]));
2854     }
2855     SuccessOrExit(error = mEncoder.CloseStruct());
2856 
2857 exit:
2858     return error;
2859 }
2860 
HandlePropertySet(void)2861 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CNTR_MAC_RETRY_HISTOGRAM>(void)
2862 {
2863     otLinkResetTxRetrySuccessHistogram(mInstance);
2864 
2865     return OT_ERROR_NONE;
2866 }
2867 #endif // OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE
2868 
HandlePropertySet(void)2869 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CNTR_ALL_IP_COUNTERS>(void)
2870 {
2871     otThreadResetIp6Counters(mInstance);
2872 
2873     return OT_ERROR_NONE;
2874 }
2875 
2876 #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
2877 
HandlePropertyGet(void)2878 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_ALLOWLIST>(void)
2879 {
2880     otMacFilterEntry    entry;
2881     otMacFilterIterator iterator = OT_MAC_FILTER_ITERATOR_INIT;
2882     otError             error    = OT_ERROR_NONE;
2883 
2884     while (otLinkFilterGetNextAddress(mInstance, &iterator, &entry) == OT_ERROR_NONE)
2885     {
2886         SuccessOrExit(error = mEncoder.OpenStruct());
2887 
2888         SuccessOrExit(error = mEncoder.WriteEui64(entry.mExtAddress));
2889         SuccessOrExit(error = mEncoder.WriteInt8(entry.mRssIn));
2890 
2891         SuccessOrExit(error = mEncoder.CloseStruct());
2892     }
2893 
2894 exit:
2895     return error;
2896 }
2897 
HandlePropertyGet(void)2898 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_ALLOWLIST_ENABLED>(void)
2899 {
2900     return mEncoder.WriteBool(otLinkFilterGetAddressMode(mInstance) == OT_MAC_FILTER_ADDRESS_MODE_ALLOWLIST);
2901 }
2902 
HandlePropertyGet(void)2903 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_DENYLIST>(void)
2904 {
2905     otMacFilterEntry    entry;
2906     otMacFilterIterator iterator = OT_MAC_FILTER_ITERATOR_INIT;
2907     otError             error    = OT_ERROR_NONE;
2908 
2909     while (otLinkFilterGetNextAddress(mInstance, &iterator, &entry) == OT_ERROR_NONE)
2910     {
2911         SuccessOrExit(error = mEncoder.OpenStruct());
2912         SuccessOrExit(error = mEncoder.WriteEui64(entry.mExtAddress));
2913         SuccessOrExit(error = mEncoder.CloseStruct());
2914     }
2915 
2916 exit:
2917     return error;
2918 }
2919 
HandlePropertyGet(void)2920 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_DENYLIST_ENABLED>(void)
2921 {
2922     return mEncoder.WriteBool(otLinkFilterGetAddressMode(mInstance) == OT_MAC_FILTER_ADDRESS_MODE_DENYLIST);
2923 }
2924 
HandlePropertyGet(void)2925 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_MAC_FIXED_RSS>(void)
2926 {
2927     otMacFilterEntry    entry;
2928     otMacFilterIterator iterator = OT_MAC_FILTER_ITERATOR_INIT;
2929     otError             error    = OT_ERROR_NONE;
2930 
2931     while (otLinkFilterGetNextRssIn(mInstance, &iterator, &entry) == OT_ERROR_NONE)
2932     {
2933         SuccessOrExit(error = mEncoder.OpenStruct());
2934 
2935         SuccessOrExit(error = mEncoder.WriteEui64(entry.mExtAddress));
2936         SuccessOrExit(error = mEncoder.WriteInt8(entry.mRssIn));
2937 
2938         SuccessOrExit(error = mEncoder.CloseStruct());
2939     }
2940 
2941 exit:
2942     return error;
2943 }
2944 
HandlePropertySet(void)2945 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_ALLOWLIST>(void)
2946 {
2947     otError error = OT_ERROR_NONE;
2948 
2949     // First, clear the address filter entries.
2950     otLinkFilterClearAddresses(mInstance);
2951 
2952     while (mDecoder.GetRemainingLengthInStruct() > 0)
2953     {
2954         const otExtAddress *extAddress = nullptr;
2955         int8_t              rss;
2956 
2957         SuccessOrExit(error = mDecoder.OpenStruct());
2958         SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
2959 
2960         if (!mDecoder.IsAllReadInStruct())
2961         {
2962             SuccessOrExit(error = mDecoder.ReadInt8(rss));
2963         }
2964         else
2965         {
2966             rss = OT_MAC_FILTER_FIXED_RSS_DISABLED;
2967         }
2968 
2969         SuccessOrExit(error = mDecoder.CloseStruct());
2970 
2971         error = otLinkFilterAddAddress(mInstance, extAddress);
2972 
2973         if (error == OT_ERROR_ALREADY)
2974         {
2975             error = OT_ERROR_NONE;
2976         }
2977 
2978         SuccessOrExit(error);
2979 
2980         if (rss != OT_MAC_FILTER_FIXED_RSS_DISABLED)
2981         {
2982             SuccessOrExit(error = otLinkFilterAddRssIn(mInstance, extAddress, rss));
2983         }
2984     }
2985 
2986 exit:
2987     // If we had an error, we may have actually changed
2988     // the state of the allowlist, so we need to report
2989     // those incomplete changes via an asynchronous
2990     // change event.
2991 
2992     if (error != OT_ERROR_NONE)
2993     {
2994         IgnoreError(WritePropertyValueIsFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_PROP_MAC_ALLOWLIST));
2995     }
2996 
2997     return error;
2998 }
2999 
HandlePropertySet(void)3000 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_ALLOWLIST_ENABLED>(void)
3001 {
3002     bool                   enabled;
3003     otError                error = OT_ERROR_NONE;
3004     otMacFilterAddressMode mode  = OT_MAC_FILTER_ADDRESS_MODE_DISABLED;
3005 
3006     SuccessOrExit(error = mDecoder.ReadBool(enabled));
3007 
3008     if (enabled)
3009     {
3010         mode = OT_MAC_FILTER_ADDRESS_MODE_ALLOWLIST;
3011     }
3012 
3013     otLinkFilterSetAddressMode(mInstance, mode);
3014 
3015 exit:
3016     return error;
3017 }
3018 
HandlePropertySet(void)3019 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_DENYLIST>(void)
3020 {
3021     otError error = OT_ERROR_NONE;
3022 
3023     // First, clear the address filter entries.
3024     otLinkFilterClearAddresses(mInstance);
3025 
3026     while (mDecoder.GetRemainingLengthInStruct() > 0)
3027     {
3028         const otExtAddress *extAddress = nullptr;
3029 
3030         SuccessOrExit(error = mDecoder.OpenStruct());
3031         SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
3032         SuccessOrExit(error = mDecoder.CloseStruct());
3033 
3034         SuccessOrExit(error = otLinkFilterAddAddress(mInstance, extAddress));
3035     }
3036 
3037 exit:
3038     // If we had an error, we may have actually changed
3039     // the state of the denylist, so we need to report
3040     // those incomplete changes via an asynchronous
3041     // change event.
3042 
3043     if (error != OT_ERROR_NONE)
3044     {
3045         IgnoreError(WritePropertyValueIsFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_PROP_MAC_DENYLIST));
3046     }
3047 
3048     return error;
3049 }
3050 
HandlePropertySet(void)3051 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_DENYLIST_ENABLED>(void)
3052 {
3053     bool                   enabled;
3054     otError                error = OT_ERROR_NONE;
3055     otMacFilterAddressMode mode  = OT_MAC_FILTER_ADDRESS_MODE_DISABLED;
3056 
3057     SuccessOrExit(error = mDecoder.ReadBool(enabled));
3058 
3059     if (enabled)
3060     {
3061         mode = OT_MAC_FILTER_ADDRESS_MODE_DENYLIST;
3062     }
3063 
3064     otLinkFilterSetAddressMode(mInstance, mode);
3065 
3066 exit:
3067     return error;
3068 }
3069 
HandlePropertySet(void)3070 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_FIXED_RSS>(void)
3071 {
3072     otError error = OT_ERROR_NONE;
3073 
3074     // First, clear the address filter entries.
3075     otLinkFilterClearAllRssIn(mInstance);
3076 
3077     while (mDecoder.GetRemainingLengthInStruct() > 0)
3078     {
3079         const otExtAddress *extAddress;
3080         int8_t              rss;
3081 
3082         SuccessOrExit(error = mDecoder.OpenStruct());
3083 
3084         if (mDecoder.GetRemainingLengthInStruct() > sizeof(otExtAddress))
3085         {
3086             SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
3087         }
3088         else
3089         {
3090             extAddress = nullptr;
3091         }
3092 
3093         SuccessOrExit(error = mDecoder.ReadInt8(rss));
3094 
3095         SuccessOrExit(error = mDecoder.CloseStruct());
3096 
3097         if (extAddress != nullptr)
3098         {
3099             SuccessOrExit(error = otLinkFilterAddRssIn(mInstance, extAddress, rss));
3100         }
3101         else
3102         {
3103             otLinkFilterSetDefaultRssIn(mInstance, rss);
3104         }
3105     }
3106 
3107 exit:
3108     // If we had an error, we may have actually changed
3109     // the state of the RssIn filter, so we need to report
3110     // those incomplete changes via an asynchronous
3111     // change event.
3112 
3113     if (error != OT_ERROR_NONE)
3114     {
3115         IgnoreError(WritePropertyValueIsFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_PROP_MAC_FIXED_RSS));
3116     }
3117 
3118     return error;
3119 }
3120 #endif // OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
3121 
3122 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
HandlePropertySet(void)3123 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_LINK_METRICS_QUERY>(void)
3124 {
3125     otError             error = OT_ERROR_NONE;
3126     struct otIp6Address address;
3127     uint8_t             seriesId;
3128     otLinkMetrics       linkMetrics = {false, false, false, false, false};
3129 
3130     SuccessOrExit(error = mDecoder.ReadIp6Address(address));
3131     SuccessOrExit(error = mDecoder.ReadUint8(seriesId));
3132     SuccessOrExit(error = DecodeLinkMetrics(&linkMetrics, /* aAllowPduCount */ true));
3133 
3134     error =
3135         otLinkMetricsQuery(mInstance, &address, seriesId, &linkMetrics, &NcpBase::HandleLinkMetricsReport_Jump, this);
3136 
3137 exit:
3138     return error;
3139 }
3140 
HandlePropertySet(void)3141 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_LINK_METRICS_PROBE>(void)
3142 {
3143     otError             error = OT_ERROR_NONE;
3144     struct otIp6Address address;
3145     uint8_t             seriesId;
3146     uint8_t             length;
3147 
3148     SuccessOrExit(error = mDecoder.ReadIp6Address(address));
3149     SuccessOrExit(error = mDecoder.ReadUint8(seriesId));
3150     SuccessOrExit(error = mDecoder.ReadUint8(length));
3151 
3152     error = otLinkMetricsSendLinkProbe(mInstance, &address, seriesId, length);
3153 
3154 exit:
3155     return error;
3156 }
3157 
HandlePropertySet(void)3158 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_LINK_METRICS_MGMT_ENH_ACK>(void)
3159 {
3160     otError             error = OT_ERROR_NONE;
3161     struct otIp6Address address;
3162     uint8_t             controlFlags;
3163     otLinkMetrics       linkMetrics = {false, false, false, false, false};
3164 
3165     SuccessOrExit(error = mDecoder.ReadIp6Address(address));
3166     SuccessOrExit(error = mDecoder.ReadUint8(controlFlags));
3167     SuccessOrExit(error = DecodeLinkMetrics(&linkMetrics, /* aAllowPduCount */ false));
3168 
3169     error = otLinkMetricsConfigEnhAckProbing(mInstance, &address, static_cast<otLinkMetricsEnhAckFlags>(controlFlags),
3170                                              controlFlags ? &linkMetrics : nullptr,
3171                                              &NcpBase::HandleLinkMetricsMgmtResponse_Jump, this,
3172                                              &NcpBase::HandleLinkMetricsEnhAckProbingIeReport_Jump, this);
3173 
3174 exit:
3175     return error;
3176 }
3177 
HandlePropertySet(void)3178 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_LINK_METRICS_MGMT_FORWARD>(void)
3179 {
3180     otError                  error = OT_ERROR_NONE;
3181     struct otIp6Address      address;
3182     uint8_t                  seriesId;
3183     uint8_t                  types;
3184     otLinkMetrics            linkMetrics = {false, false, false, false, false};
3185     otLinkMetricsSeriesFlags seriesFlags = {false, false, false, false};
3186 
3187     SuccessOrExit(error = mDecoder.ReadIp6Address(address));
3188     SuccessOrExit(error = mDecoder.ReadUint8(seriesId));
3189     SuccessOrExit(error = mDecoder.ReadUint8(types));
3190 
3191     SuccessOrExit(error = DecodeLinkMetrics(&linkMetrics, /* aAllowPduCount */ true));
3192 
3193     if (types & SPINEL_THREAD_FRAME_TYPE_MLE_LINK_PROBE)
3194     {
3195         seriesFlags.mLinkProbe = true;
3196     }
3197 
3198     if (types & SPINEL_THREAD_FRAME_TYPE_MAC_DATA)
3199     {
3200         seriesFlags.mMacData = true;
3201     }
3202 
3203     if (types & SPINEL_THREAD_FRAME_TYPE_MAC_DATA_REQUEST)
3204     {
3205         seriesFlags.mMacDataRequest = true;
3206     }
3207 
3208     if (types & SPINEL_THREAD_FRAME_TYPE_MAC_ACK)
3209     {
3210         seriesFlags.mMacAck = true;
3211     }
3212 
3213     error = otLinkMetricsConfigForwardTrackingSeries(mInstance, &address, seriesId, seriesFlags, &linkMetrics,
3214                                                      &NcpBase::HandleLinkMetricsMgmtResponse_Jump, this);
3215 
3216 exit:
3217     return error;
3218 }
3219 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
3220 
HandlePropertyGet(void)3221 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_MODE>(void)
3222 {
3223     uint8_t          numericMode;
3224     otLinkModeConfig modeConfig = otThreadGetLinkMode(mInstance);
3225 
3226     numericMode = LinkFlagsToFlagByte(modeConfig.mRxOnWhenIdle, modeConfig.mDeviceType, modeConfig.mNetworkData);
3227 
3228     return mEncoder.WriteUint8(numericMode);
3229 }
3230 
HandlePropertySet(void)3231 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_MODE>(void)
3232 {
3233     uint8_t          numericMode = 0;
3234     otLinkModeConfig modeConfig;
3235     otError          error = OT_ERROR_NONE;
3236 
3237     SuccessOrExit(error = mDecoder.ReadUint8(numericMode));
3238 
3239     modeConfig.mRxOnWhenIdle =
3240         ((numericMode & SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE) == SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE);
3241     modeConfig.mDeviceType = ((numericMode & SPINEL_THREAD_MODE_FULL_THREAD_DEV) == SPINEL_THREAD_MODE_FULL_THREAD_DEV);
3242     modeConfig.mNetworkData =
3243         ((numericMode & SPINEL_THREAD_MODE_FULL_NETWORK_DATA) == SPINEL_THREAD_MODE_FULL_NETWORK_DATA);
3244 
3245     error = otThreadSetLinkMode(mInstance, modeConfig);
3246 
3247 exit:
3248     return error;
3249 }
3250 
HandlePropertyGet(void)3251 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_CHILD_TIMEOUT>(void)
3252 {
3253     return mEncoder.WriteUint32(otThreadGetChildTimeout(mInstance));
3254 }
3255 
HandlePropertySet(void)3256 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_CHILD_TIMEOUT>(void)
3257 {
3258     uint32_t timeout = 0;
3259     otError  error   = OT_ERROR_NONE;
3260 
3261     SuccessOrExit(error = mDecoder.ReadUint32(timeout));
3262 
3263     otThreadSetChildTimeout(mInstance, timeout);
3264 
3265 exit:
3266     return error;
3267 }
3268 
HandlePropertyGet(void)3269 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_RLOC16>(void)
3270 {
3271     return mEncoder.WriteUint16(otThreadGetRloc16(mInstance));
3272 }
3273 
HandlePropertyGet(void)3274 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NET_REQUIRE_JOIN_EXISTING>(void)
3275 {
3276     return mEncoder.WriteBool(mRequireJoinExistingNetwork);
3277 }
3278 
HandlePropertySet(void)3279 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_NET_REQUIRE_JOIN_EXISTING>(void)
3280 {
3281     return mDecoder.ReadBool(mRequireJoinExistingNetwork);
3282 }
3283 
HandlePropertySet(void)3284 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_STREAM_NET_INSECURE>(void)
3285 {
3286     const uint8_t    *framePtr    = nullptr;
3287     uint16_t          frameLen    = 0;
3288     const uint8_t    *metaPtr     = nullptr;
3289     uint16_t          metaLen     = 0;
3290     otMessage        *message     = nullptr;
3291     otError           error       = OT_ERROR_NONE;
3292     otMessageSettings msgSettings = {false, OT_MESSAGE_PRIORITY_NORMAL};
3293 
3294     SuccessOrExit(error = mDecoder.ReadDataWithLen(framePtr, frameLen));
3295     SuccessOrExit(error = mDecoder.ReadData(metaPtr, metaLen));
3296 
3297     // We ignore metadata for now.
3298     // May later include TX power, allow retransmits, etc...
3299 
3300     // STREAM_NET_INSECURE packets are not secured at layer 2.
3301     message = otIp6NewMessageFromBuffer(mInstance, framePtr, frameLen, &msgSettings);
3302     VerifyOrExit(message != nullptr, error = OT_ERROR_NO_BUFS);
3303 
3304     // Ensure the insecure message is forwarded using direct transmission.
3305     otMessageSetDirectTransmission(message, true);
3306 
3307     error = otIp6Send(mInstance, message);
3308 
3309 exit:
3310     if (error == OT_ERROR_NONE)
3311     {
3312         mInboundInsecureIpFrameCounter++;
3313     }
3314     else
3315     {
3316         mDroppedInboundIpFrameCounter++;
3317     }
3318 
3319     return error;
3320 }
3321 
HandlePropertySet(void)3322 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_CNTR_RESET>(void)
3323 {
3324     otLinkResetCounters(mInstance);
3325 #if OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE
3326     otLinkResetTxRetrySuccessHistogram(mInstance);
3327 #endif
3328     otThreadResetIp6Counters(mInstance);
3329     otThreadResetMleCounters(mInstance);
3330     ResetCounters();
3331 
3332     return OT_ERROR_NONE;
3333 }
3334 
HandlePropertyInsert(void)3335 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_THREAD_ASSISTING_PORTS>(void)
3336 {
3337     otError  error = OT_ERROR_NONE;
3338     uint16_t port;
3339 
3340     SuccessOrExit(error = mDecoder.ReadUint16(port));
3341 
3342     error = otIp6AddUnsecurePort(mInstance, port);
3343 exit:
3344     return error;
3345 }
3346 
3347 #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
3348 
HandlePropertyInsert(void)3349 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_MAC_ALLOWLIST>(void)
3350 {
3351     otError             error = OT_ERROR_NONE;
3352     const otExtAddress *extAddress;
3353     int8_t              rss = OT_MAC_FILTER_FIXED_RSS_DISABLED;
3354 
3355     SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
3356 
3357     if (!mDecoder.IsAllRead())
3358     {
3359         SuccessOrExit(error = mDecoder.ReadInt8(rss));
3360     }
3361 
3362     error = otLinkFilterAddAddress(mInstance, extAddress);
3363 
3364     if (error == OT_ERROR_ALREADY)
3365     {
3366         error = OT_ERROR_NONE;
3367     }
3368 
3369     SuccessOrExit(error);
3370 
3371     if (rss != OT_MAC_FILTER_FIXED_RSS_DISABLED)
3372     {
3373         error = otLinkFilterAddRssIn(mInstance, extAddress, rss);
3374     }
3375 
3376 exit:
3377     return error;
3378 }
3379 
HandlePropertyInsert(void)3380 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_MAC_DENYLIST>(void)
3381 {
3382     otError             error = OT_ERROR_NONE;
3383     const otExtAddress *extAddress;
3384 
3385     SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
3386 
3387     error = otLinkFilterAddAddress(mInstance, extAddress);
3388 
3389     if (error == OT_ERROR_ALREADY)
3390     {
3391         error = OT_ERROR_NONE;
3392     }
3393 
3394 exit:
3395     return error;
3396 }
3397 
HandlePropertyInsert(void)3398 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_MAC_FIXED_RSS>(void)
3399 {
3400     otError             error      = OT_ERROR_NONE;
3401     const otExtAddress *extAddress = nullptr;
3402     int8_t              rss        = OT_MAC_FILTER_FIXED_RSS_DISABLED;
3403 
3404     if (mDecoder.GetRemainingLength() > sizeof(int8_t))
3405     {
3406         SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
3407     }
3408 
3409     SuccessOrExit(error = mDecoder.ReadInt8(rss));
3410 
3411     if (extAddress != nullptr)
3412     {
3413         error = otLinkFilterAddRssIn(mInstance, extAddress, rss);
3414     }
3415     else
3416     {
3417         otLinkFilterSetDefaultRssIn(mInstance, rss);
3418     }
3419 
3420 exit:
3421     return error;
3422 }
3423 
3424 #endif // OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
3425 
HandlePropertyRemove(void)3426 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_THREAD_ASSISTING_PORTS>(void)
3427 {
3428     otError  error = OT_ERROR_NONE;
3429     uint16_t port;
3430 
3431     SuccessOrExit(error = mDecoder.ReadUint16(port));
3432 
3433     error = otIp6RemoveUnsecurePort(mInstance, port);
3434 
3435     // If unsecure port was not on the list, "remove" command is successful.
3436     if (error == OT_ERROR_NOT_FOUND)
3437     {
3438         error = OT_ERROR_NONE;
3439     }
3440 
3441 exit:
3442     return error;
3443 }
3444 
3445 #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
3446 
HandlePropertyRemove(void)3447 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_MAC_ALLOWLIST>(void)
3448 {
3449     otError             error      = OT_ERROR_NONE;
3450     const otExtAddress *extAddress = nullptr;
3451 
3452     SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
3453 
3454     otLinkFilterRemoveAddress(mInstance, extAddress);
3455 
3456 exit:
3457     return error;
3458 }
3459 
HandlePropertyRemove(void)3460 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_MAC_DENYLIST>(void)
3461 {
3462     otError             error      = OT_ERROR_NONE;
3463     const otExtAddress *extAddress = nullptr;
3464 
3465     SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
3466 
3467     otLinkFilterRemoveAddress(mInstance, extAddress);
3468 
3469 exit:
3470     return error;
3471 }
3472 
HandlePropertyRemove(void)3473 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_MAC_FIXED_RSS>(void)
3474 {
3475     otError             error      = OT_ERROR_NONE;
3476     const otExtAddress *extAddress = nullptr;
3477 
3478     if (mDecoder.GetRemainingLength() > 0)
3479     {
3480         SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
3481     }
3482 
3483     if (extAddress != nullptr)
3484     {
3485         otLinkFilterRemoveRssIn(mInstance, extAddress);
3486     }
3487     else
3488     {
3489         otLinkFilterClearDefaultRssIn(mInstance);
3490     }
3491 
3492 exit:
3493     return error;
3494 }
3495 
3496 #endif // OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
3497 
3498 #if OPENTHREAD_PLATFORM_POSIX
3499 
HandlePropertyGet(void)3500 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_RCP_VERSION>(void)
3501 {
3502     return mEncoder.WriteUtf8(otGetRadioVersionString(mInstance));
3503 }
3504 
3505 #endif
3506 
3507 #if OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE
3508 
HandlePropertyGet(void)3509 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_SLAAC_ENABLED>(void)
3510 {
3511     return mEncoder.WriteBool(otIp6IsSlaacEnabled(mInstance));
3512 }
3513 
HandlePropertySet(void)3514 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_SLAAC_ENABLED>(void)
3515 {
3516     otError error = OT_ERROR_NONE;
3517     bool    enabled;
3518 
3519     SuccessOrExit(error = mDecoder.ReadBool(enabled));
3520     otIp6SetSlaacEnabled(mInstance, enabled);
3521 
3522 exit:
3523     return error;
3524 }
3525 
3526 #endif // OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE
3527 
HandlePropertyGet(void)3528 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_SUPPORTED_RADIO_LINKS>(void)
3529 {
3530     otError error;
3531 
3532 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
3533     SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_RADIO_LINK_IEEE_802_15_4));
3534 #endif
3535 
3536 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
3537     SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_RADIO_LINK_TREL_UDP6));
3538 #endif
3539 
3540 exit:
3541     return error;
3542 }
3543 
3544 #if OPENTHREAD_CONFIG_MULTI_RADIO
3545 
EncodeNeighborMultiRadioInfo(uint32_t aSpinelRadioLink,const otRadioLinkInfo & aInfo)3546 otError NcpBase::EncodeNeighborMultiRadioInfo(uint32_t aSpinelRadioLink, const otRadioLinkInfo &aInfo)
3547 {
3548     otError error;
3549 
3550     SuccessOrExit(error = mEncoder.OpenStruct());
3551     SuccessOrExit(error = mEncoder.WriteUintPacked(aSpinelRadioLink));
3552     SuccessOrExit(error = mEncoder.WriteUint8(aInfo.mPreference));
3553     SuccessOrExit(error = mEncoder.CloseStruct());
3554 
3555 exit:
3556     return error;
3557 }
3558 
HandlePropertyGet(void)3559 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_NEIGHBOR_TABLE_MULTI_RADIO_INFO>(void)
3560 {
3561     otError                  error = OT_ERROR_NONE;
3562     otNeighborInfoIterator   iter  = OT_NEIGHBOR_INFO_ITERATOR_INIT;
3563     otNeighborInfo           neighInfo;
3564     otMultiRadioNeighborInfo multiRadioInfo;
3565 
3566     while (otThreadGetNextNeighborInfo(mInstance, &iter, &neighInfo) == OT_ERROR_NONE)
3567     {
3568         SuccessOrExit(error = mEncoder.OpenStruct());
3569 
3570         SuccessOrExit(error = mEncoder.WriteEui64(neighInfo.mExtAddress));
3571         SuccessOrExit(error = mEncoder.WriteUint16(neighInfo.mRloc16));
3572 
3573         if (otMultiRadioGetNeighborInfo(mInstance, &neighInfo.mExtAddress, &multiRadioInfo) == OT_ERROR_NONE)
3574         {
3575             if (multiRadioInfo.mSupportsIeee802154)
3576             {
3577                 SuccessOrExit(error = EncodeNeighborMultiRadioInfo(SPINEL_RADIO_LINK_IEEE_802_15_4,
3578                                                                    multiRadioInfo.mIeee802154Info));
3579             }
3580 
3581             if (multiRadioInfo.mSupportsTrelUdp6)
3582             {
3583                 SuccessOrExit(
3584                     error = EncodeNeighborMultiRadioInfo(SPINEL_RADIO_LINK_TREL_UDP6, multiRadioInfo.mTrelUdp6Info));
3585             }
3586         }
3587 
3588         SuccessOrExit(error = mEncoder.CloseStruct());
3589     }
3590 
3591 exit:
3592     return error;
3593 }
3594 #endif // OPENTHREAD_CONFIG_MULTI_RADIO
3595 
3596 // ----------------------------------------------------------------------------
3597 // SRP Client
3598 // ----------------------------------------------------------------------------
3599 
3600 #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
3601 
HandlePropertySet(void)3602 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_SRP_CLIENT_START>(void)
3603 {
3604     otError    error = OT_ERROR_NONE;
3605     bool       start;
3606     bool       callbackEnabled;
3607     otSockAddr serverAddr;
3608 
3609     SuccessOrExit(error = mDecoder.ReadBool(start));
3610 
3611     if (!start)
3612     {
3613         otSrpClientStop(mInstance);
3614         ExitNow();
3615     }
3616 
3617     SuccessOrExit(error = mDecoder.ReadIp6Address(serverAddr.mAddress));
3618     SuccessOrExit(error = mDecoder.ReadUint16(serverAddr.mPort));
3619     SuccessOrExit(error = mDecoder.ReadBool(callbackEnabled));
3620 
3621     SuccessOrExit(error = otSrpClientStart(mInstance, &serverAddr));
3622     mSrpClientCallbackEnabled = callbackEnabled;
3623 
3624 exit:
3625     return error;
3626 }
3627 
HandlePropertyGet(void)3628 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_SRP_CLIENT_LEASE_INTERVAL>(void)
3629 {
3630     return mEncoder.WriteUint32(otSrpClientGetLeaseInterval(mInstance));
3631 }
3632 
HandlePropertySet(void)3633 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_SRP_CLIENT_LEASE_INTERVAL>(void)
3634 {
3635     otError  error;
3636     uint32_t interval;
3637 
3638     SuccessOrExit(error = mDecoder.ReadUint32(interval));
3639     otSrpClientSetLeaseInterval(mInstance, interval);
3640 
3641 exit:
3642     return error;
3643 }
3644 
HandlePropertyGet(void)3645 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_SRP_CLIENT_KEY_LEASE_INTERVAL>(void)
3646 {
3647     return mEncoder.WriteUint32(otSrpClientGetKeyLeaseInterval(mInstance));
3648 }
3649 
HandlePropertySet(void)3650 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_SRP_CLIENT_KEY_LEASE_INTERVAL>(void)
3651 {
3652     otError  error;
3653     uint32_t interval;
3654 
3655     SuccessOrExit(error = mDecoder.ReadUint32(interval));
3656     otSrpClientSetKeyLeaseInterval(mInstance, interval);
3657 
3658 exit:
3659     return error;
3660 }
3661 
SrpClientItemStateToSpinel(otSrpClientItemState aItemState)3662 static spinel_srp_client_item_state_t SrpClientItemStateToSpinel(otSrpClientItemState aItemState)
3663 {
3664     spinel_srp_client_item_state_t state = SPINEL_SRP_CLIENT_ITEM_STATE_REMOVED;
3665 
3666     switch (aItemState)
3667     {
3668     case OT_SRP_CLIENT_ITEM_STATE_TO_ADD:
3669         state = SPINEL_SRP_CLIENT_ITEM_STATE_TO_ADD;
3670         break;
3671     case OT_SRP_CLIENT_ITEM_STATE_ADDING:
3672         state = SPINEL_SRP_CLIENT_ITEM_STATE_ADDING;
3673         break;
3674     case OT_SRP_CLIENT_ITEM_STATE_TO_REFRESH:
3675         state = SPINEL_SRP_CLIENT_ITEM_STATE_TO_REFRESH;
3676         break;
3677     case OT_SRP_CLIENT_ITEM_STATE_REFRESHING:
3678         state = SPINEL_SRP_CLIENT_ITEM_STATE_REFRESHING;
3679         break;
3680     case OT_SRP_CLIENT_ITEM_STATE_TO_REMOVE:
3681         state = SPINEL_SRP_CLIENT_ITEM_STATE_TO_REMOVE;
3682         break;
3683     case OT_SRP_CLIENT_ITEM_STATE_REMOVING:
3684         state = SPINEL_SRP_CLIENT_ITEM_STATE_REMOVING;
3685         break;
3686     case OT_SRP_CLIENT_ITEM_STATE_REGISTERED:
3687         state = SPINEL_SRP_CLIENT_ITEM_STATE_REGISTERED;
3688         break;
3689     case OT_SRP_CLIENT_ITEM_STATE_REMOVED:
3690         state = SPINEL_SRP_CLIENT_ITEM_STATE_REMOVED;
3691         break;
3692     }
3693 
3694     return state;
3695 }
3696 
EncodeSrpClientHostInfo(const otSrpClientHostInfo & aHostInfo)3697 otError NcpBase::EncodeSrpClientHostInfo(const otSrpClientHostInfo &aHostInfo)
3698 {
3699     otError error;
3700 
3701     SuccessOrExit(error = mEncoder.WriteUtf8(aHostInfo.mName != nullptr ? aHostInfo.mName : ""));
3702     SuccessOrExit(error = mEncoder.WriteUint8(SrpClientItemStateToSpinel(aHostInfo.mState)));
3703 
3704     SuccessOrExit(error = mEncoder.OpenStruct());
3705 
3706     for (uint8_t index = 0; index < aHostInfo.mNumAddresses; index++)
3707     {
3708         SuccessOrExit(error = mEncoder.WriteIp6Address(aHostInfo.mAddresses[index]));
3709     }
3710 
3711     SuccessOrExit(error = mEncoder.CloseStruct());
3712 
3713 exit:
3714     return error;
3715 }
3716 
HandlePropertyGet(void)3717 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_SRP_CLIENT_HOST_INFO>(void)
3718 {
3719     return EncodeSrpClientHostInfo(*otSrpClientGetHostInfo(mInstance));
3720 }
3721 
HandlePropertyGet(void)3722 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_SRP_CLIENT_HOST_NAME>(void)
3723 {
3724     const char *name = otSrpClientGetHostInfo(mInstance)->mName;
3725 
3726     return mEncoder.WriteUtf8(name != nullptr ? name : "");
3727 }
3728 
HandlePropertySet(void)3729 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_SRP_CLIENT_HOST_NAME>(void)
3730 {
3731     otError     error;
3732     const char *name;
3733     uint16_t    size;
3734     char       *hostNameBuffer;
3735 
3736     SuccessOrExit(error = mDecoder.ReadUtf8(name));
3737 
3738     hostNameBuffer = otSrpClientBuffersGetHostNameString(mInstance, &size);
3739 
3740     VerifyOrExit(StringLength(name, size) < size, error = OT_ERROR_INVALID_ARGS);
3741 
3742     // We first make sure we can set the name, and if so
3743     // we copy it to the persisted buffer and set
3744     // the host name again now with the persisted buffer.
3745     // This ensures that we do not overwrite a previous
3746     // buffer with a host name that cannot be set.
3747 
3748     SuccessOrExit(error = otSrpClientSetHostName(mInstance, name));
3749 
3750     strcpy(hostNameBuffer, name);
3751     SuccessOrAssert(error = otSrpClientSetHostName(mInstance, hostNameBuffer));
3752 
3753 exit:
3754     return error;
3755 }
3756 
HandlePropertyGet(void)3757 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_SRP_CLIENT_HOST_ADDRESSES>(void)
3758 {
3759     otError                    error    = OT_ERROR_NONE;
3760     const otSrpClientHostInfo *hostInfo = otSrpClientGetHostInfo(mInstance);
3761 
3762     for (uint8_t index = 0; index < hostInfo->mNumAddresses; index++)
3763     {
3764         SuccessOrExit(error = mEncoder.WriteIp6Address(hostInfo->mAddresses[index]));
3765     }
3766 
3767 exit:
3768     return error;
3769 }
3770 
HandlePropertySet(void)3771 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_SRP_CLIENT_HOST_ADDRESSES>(void)
3772 {
3773     otError       error;
3774     otIp6Address  addresses[kSrpClientMaxHostAddresses];
3775     uint8_t       numAddresses = 0;
3776     otIp6Address *hostAddressArray;
3777     uint8_t       hostAddressArrayLength;
3778 
3779     hostAddressArray = otSrpClientBuffersGetHostAddressesArray(mInstance, &hostAddressArrayLength);
3780     OT_ASSERT(hostAddressArrayLength <= kSrpClientMaxHostAddresses);
3781 
3782     while (!mDecoder.IsAllReadInStruct())
3783     {
3784         VerifyOrExit(numAddresses < kSrpClientMaxHostAddresses, error = OT_ERROR_NO_BUFS);
3785 
3786         SuccessOrExit(error = mDecoder.ReadIp6Address(addresses[numAddresses]));
3787         numAddresses++;
3788     }
3789 
3790     // We first make sure we can set the addresses, and if so we copy
3791     // the address list into `hostAddressArray` and set it again. This
3792     // ensures that we do not overwrite a previous list before we know
3793     // it is safe to set/change the address list.
3794 
3795     SuccessOrExit(error = otSrpClientSetHostAddresses(mInstance, addresses, numAddresses));
3796 
3797     memcpy(hostAddressArray, addresses, sizeof(addresses));
3798 
3799     SuccessOrAssert(error = otSrpClientSetHostAddresses(mInstance, hostAddressArray, numAddresses));
3800 
3801 exit:
3802     return error;
3803 }
3804 
EncodeSrpClientServices(const otSrpClientService * aServices)3805 otError NcpBase::EncodeSrpClientServices(const otSrpClientService *aServices)
3806 {
3807     otError error = OT_ERROR_NONE;
3808 
3809     for (; aServices != nullptr; aServices = aServices->mNext)
3810     {
3811         SuccessOrExit(error = mEncoder.OpenStruct());
3812 
3813         SuccessOrExit(error = mEncoder.WriteUtf8(aServices->mName));
3814         SuccessOrExit(error = mEncoder.WriteUtf8(aServices->mInstanceName));
3815         SuccessOrExit(error = mEncoder.WriteUint16(aServices->mPort));
3816         SuccessOrExit(error = mEncoder.WriteUint16(aServices->mPriority));
3817         SuccessOrExit(error = mEncoder.WriteUint16(aServices->mWeight));
3818 
3819         SuccessOrExit(error = mEncoder.CloseStruct());
3820     }
3821 
3822 exit:
3823     return error;
3824 }
3825 
HandlePropertyGet(void)3826 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_SRP_CLIENT_SERVICES>(void)
3827 {
3828     return EncodeSrpClientServices(otSrpClientGetServices(mInstance));
3829 }
3830 
HandlePropertyInsert(void)3831 template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_SRP_CLIENT_SERVICES>(void)
3832 {
3833     otError                         error = OT_ERROR_NONE;
3834     otSrpClientBuffersServiceEntry *entry = nullptr;
3835     const char                     *serviceName;
3836     const char                     *instanceName;
3837     char                           *stringBuffer;
3838     uint16_t                        size;
3839 
3840     entry = otSrpClientBuffersAllocateService(mInstance);
3841     VerifyOrExit(entry != nullptr, error = OT_ERROR_NO_BUFS);
3842 
3843     stringBuffer = otSrpClientBuffersGetServiceEntryServiceNameString(entry, &size);
3844     SuccessOrExit(error = mDecoder.ReadUtf8(serviceName));
3845     VerifyOrExit(StringLength(serviceName, size) < size, error = OT_ERROR_INVALID_ARGS);
3846     strcpy(stringBuffer, serviceName);
3847 
3848     stringBuffer = otSrpClientBuffersGetServiceEntryInstanceNameString(entry, &size);
3849     SuccessOrExit(error = mDecoder.ReadUtf8(instanceName));
3850     VerifyOrExit(StringLength(instanceName, size) < size, error = OT_ERROR_INVALID_ARGS);
3851     strcpy(stringBuffer, instanceName);
3852 
3853     SuccessOrExit(error = mDecoder.ReadUint16(entry->mService.mPort));
3854     SuccessOrExit(error = mDecoder.ReadUint16(entry->mService.mPriority));
3855     SuccessOrExit(error = mDecoder.ReadUint16(entry->mService.mWeight));
3856 
3857     SuccessOrExit(error = otSrpClientAddService(mInstance, &entry->mService));
3858     entry = nullptr;
3859 
3860 exit:
3861     if (entry != nullptr)
3862     {
3863         otSrpClientBuffersFreeService(mInstance, entry);
3864     }
3865 
3866     return error;
3867 }
3868 
HandlePropertyRemove(void)3869 template <> otError NcpBase::HandlePropertyRemove<SPINEL_PROP_SRP_CLIENT_SERVICES>(void)
3870 {
3871     otError                   error = OT_ERROR_NONE;
3872     const char               *serviceName;
3873     const char               *instanceName;
3874     bool                      toClear = false;
3875     const otSrpClientService *service;
3876 
3877     SuccessOrExit(error = mDecoder.ReadUtf8(serviceName));
3878     SuccessOrExit(error = mDecoder.ReadUtf8(instanceName));
3879 
3880     if (!mDecoder.IsAllReadInStruct())
3881     {
3882         SuccessOrExit(error = mDecoder.ReadBool(toClear));
3883     }
3884 
3885     for (service = otSrpClientGetServices(mInstance); service != nullptr; service = service->mNext)
3886     {
3887         if ((strcmp(serviceName, service->mName) == 0) || (strcmp(instanceName, service->mInstanceName) == 0))
3888         {
3889             break;
3890         }
3891     }
3892 
3893     VerifyOrExit(service != nullptr, error = OT_ERROR_NOT_FOUND);
3894 
3895     if (toClear)
3896     {
3897         SuccessOrExit(error = otSrpClientClearService(mInstance, const_cast<otSrpClientService *>(service)));
3898         otSrpClientBuffersFreeService(
3899             mInstance, reinterpret_cast<otSrpClientBuffersServiceEntry *>(const_cast<otSrpClientService *>(service)));
3900     }
3901     else
3902     {
3903         error = otSrpClientRemoveService(mInstance, const_cast<otSrpClientService *>(service));
3904     }
3905 
3906 exit:
3907     return error;
3908 }
3909 
HandlePropertySet(void)3910 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_SRP_CLIENT_HOST_SERVICES_REMOVE>(void)
3911 {
3912     otError error = OT_ERROR_NONE;
3913     bool    removeKeyLease;
3914     bool    sendUnregToServer;
3915 
3916     SuccessOrExit(error = mDecoder.ReadBool(removeKeyLease));
3917     SuccessOrExit(error = mDecoder.ReadBool(sendUnregToServer));
3918 
3919     error = otSrpClientRemoveHostAndServices(mInstance, removeKeyLease, sendUnregToServer);
3920 
3921 exit:
3922     return error;
3923 }
3924 
HandlePropertySet(void)3925 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_SRP_CLIENT_HOST_SERVICES_CLEAR>(void)
3926 {
3927     otSrpClientClearHostAndServices(mInstance);
3928 
3929     return OT_ERROR_NONE;
3930 }
3931 
SrpClientErrorToSpinelError(otError aError)3932 static spinel_srp_client_error_t SrpClientErrorToSpinelError(otError aError)
3933 {
3934     spinel_srp_client_error_t error = SPINEL_SRP_CLIENT_ERROR_FAILED;
3935 
3936     switch (aError)
3937     {
3938     case OT_ERROR_NONE:
3939         error = SPINEL_SRP_CLIENT_ERROR_NONE;
3940         break;
3941     case OT_ERROR_PARSE:
3942         error = SPINEL_SRP_CLIENT_ERROR_PARSE;
3943         break;
3944     case OT_ERROR_NOT_FOUND:
3945         error = SPINEL_SRP_CLIENT_ERROR_NOT_FOUND;
3946         break;
3947     case OT_ERROR_NOT_IMPLEMENTED:
3948         error = SPINEL_SRP_CLIENT_ERROR_NOT_IMPLEMENTED;
3949         break;
3950     case OT_ERROR_SECURITY:
3951         error = SPINEL_SRP_CLIENT_ERROR_SECURITY;
3952         break;
3953     case OT_ERROR_DUPLICATED:
3954         error = SPINEL_SRP_CLIENT_ERROR_DUPLICATED;
3955         break;
3956     case OT_ERROR_RESPONSE_TIMEOUT:
3957         error = SPINEL_SRP_CLIENT_ERROR_RESPONSE_TIMEOUT;
3958         break;
3959     case OT_ERROR_INVALID_ARGS:
3960         error = SPINEL_SRP_CLIENT_ERROR_INVALID_ARGS;
3961         break;
3962     case OT_ERROR_NO_BUFS:
3963         error = SPINEL_SRP_CLIENT_ERROR_NO_BUFS;
3964         break;
3965     case OT_ERROR_FAILED:
3966     default:
3967         error = SPINEL_SRP_CLIENT_ERROR_FAILED;
3968         break;
3969     }
3970 
3971     return error;
3972 }
3973 
HandleSrpClientCallback(otError aError,const otSrpClientHostInfo * aHostInfo,const otSrpClientService * aServices,const otSrpClientService * aRemovedServices,void * aContext)3974 void NcpBase::HandleSrpClientCallback(otError                    aError,
3975                                       const otSrpClientHostInfo *aHostInfo,
3976                                       const otSrpClientService  *aServices,
3977                                       const otSrpClientService  *aRemovedServices,
3978                                       void                      *aContext)
3979 {
3980     static_cast<NcpBase *>(aContext)->HandleSrpClientCallback(aError, aHostInfo, aServices, aRemovedServices);
3981 }
3982 
HandleSrpClientCallback(otError aError,const otSrpClientHostInfo * aHostInfo,const otSrpClientService * aServices,const otSrpClientService * aRemovedServices)3983 void NcpBase::HandleSrpClientCallback(otError                    aError,
3984                                       const otSrpClientHostInfo *aHostInfo,
3985                                       const otSrpClientService  *aServices,
3986                                       const otSrpClientService  *aRemovedServices)
3987 {
3988     otError                   error = OT_ERROR_NONE;
3989     const otSrpClientService *service;
3990     const otSrpClientService *next;
3991 
3992     VerifyOrExit(mSrpClientCallbackEnabled);
3993 
3994     SuccessOrExit(error = mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_PROP_VALUE_IS,
3995                                               SPINEL_PROP_SRP_CLIENT_EVENT));
3996 
3997     SuccessOrExit(error = mEncoder.WriteUint16(SrpClientErrorToSpinelError(aError)));
3998 
3999     SuccessOrExit(error = mEncoder.OpenStruct());
4000     SuccessOrExit(error = EncodeSrpClientHostInfo(*aHostInfo));
4001     SuccessOrExit(error = mEncoder.CloseStruct());
4002 
4003     SuccessOrExit(error = mEncoder.OpenStruct());
4004     SuccessOrExit(error = EncodeSrpClientServices(aServices));
4005     SuccessOrExit(error = mEncoder.CloseStruct());
4006 
4007     SuccessOrExit(error = mEncoder.OpenStruct());
4008     SuccessOrExit(error = EncodeSrpClientServices(aRemovedServices));
4009     SuccessOrExit(error = mEncoder.CloseStruct());
4010 
4011     SuccessOrExit(error = mEncoder.EndFrame());
4012 
4013 exit:
4014 
4015     if (error != OT_ERROR_NONE)
4016     {
4017         // Emit a NONMEM status if we fail to send the event.
4018         mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM);
4019         mUpdateChangedPropsTask.Post();
4020     }
4021 
4022     for (service = aRemovedServices; service != nullptr; service = next)
4023     {
4024         next = service->mNext;
4025 
4026         otSrpClientBuffersFreeService(
4027             mInstance, reinterpret_cast<otSrpClientBuffersServiceEntry *>(const_cast<otSrpClientService *>(service)));
4028     }
4029 }
4030 
4031 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
HandlePropertyGet(void)4032 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_SRP_CLIENT_SERVICE_KEY_ENABLED>(void)
4033 {
4034     return mEncoder.WriteBool(otSrpClientIsServiceKeyRecordEnabled(mInstance));
4035 }
4036 
HandlePropertySet(void)4037 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_SRP_CLIENT_SERVICE_KEY_ENABLED>(void)
4038 {
4039     otError error = OT_ERROR_NONE;
4040     bool    enabled;
4041 
4042     SuccessOrExit(error = mDecoder.ReadBool(enabled));
4043     otSrpClientSetServiceKeyRecordEnabled(mInstance, enabled);
4044 
4045 exit:
4046     return error;
4047 }
4048 #endif
4049 
4050 #endif // OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
4051 
4052 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
HandlePropertyGet(void)4053 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_DEBUG_TREL_TEST_MODE_ENABLE>(void)
4054 {
4055     return mEncoder.WriteBool(!otTrelIsFilterEnabled(mInstance));
4056 }
4057 
HandlePropertySet(void)4058 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_DEBUG_TREL_TEST_MODE_ENABLE>(void)
4059 {
4060     otError error = OT_ERROR_NONE;
4061     bool    testMode;
4062 
4063     SuccessOrExit(error = mDecoder.ReadBool(testMode));
4064 
4065     // Note that `TEST_MODE` being `true` indicates that the TREL
4066     // interface should be enabled and functional, so filtering
4067     // should be disabled.
4068 
4069     otTrelSetFilterEnabled(mInstance, !testMode);
4070 
4071 exit:
4072     return error;
4073 }
4074 #endif
4075 
4076 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
HandlePropertyGet(void)4077 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_NETWORK_TIME>(void)
4078 {
4079     otError             error = OT_ERROR_NONE;
4080     otNetworkTimeStatus networkTimeStatus;
4081     uint64_t            time;
4082 
4083     networkTimeStatus = otNetworkTimeGet(mInstance, &time);
4084 
4085     SuccessOrExit(error = mEncoder.WriteUint64(time));
4086     SuccessOrExit(error = mEncoder.WriteInt8((int8_t)networkTimeStatus));
4087 
4088 exit:
4089     return error;
4090 }
4091 
HandleTimeSyncUpdate(void * aContext)4092 void NcpBase::HandleTimeSyncUpdate(void *aContext) { static_cast<NcpBase *>(aContext)->HandleTimeSyncUpdate(); }
4093 
HandleTimeSyncUpdate(void)4094 void NcpBase::HandleTimeSyncUpdate(void)
4095 {
4096     mChangedPropsSet.AddProperty(SPINEL_PROP_THREAD_NETWORK_TIME);
4097     mUpdateChangedPropsTask.Post();
4098 }
4099 #endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
4100 
HandleActiveScanResult_Jump(otActiveScanResult * aResult,void * aContext)4101 void NcpBase::HandleActiveScanResult_Jump(otActiveScanResult *aResult, void *aContext)
4102 {
4103     static_cast<NcpBase *>(aContext)->HandleActiveScanResult(aResult);
4104 }
4105 
4106 // ----------------------------------------------------------------------------
4107 // MARK: Scan Results Glue
4108 // ----------------------------------------------------------------------------
4109 
HandleActiveScanResult(otActiveScanResult * aResult)4110 void NcpBase::HandleActiveScanResult(otActiveScanResult *aResult)
4111 {
4112     otError error = OT_ERROR_NONE;
4113 
4114     if (aResult)
4115     {
4116         uint8_t flags = static_cast<uint8_t>(aResult->mVersion << SPINEL_BEACON_THREAD_FLAG_VERSION_SHIFT);
4117 
4118         if (aResult->mIsNative)
4119         {
4120             flags |= SPINEL_BEACON_THREAD_FLAG_NATIVE;
4121         }
4122 
4123         SuccessOrExit(error = mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
4124                                                   SPINEL_CMD_PROP_VALUE_INSERTED, SPINEL_PROP_MAC_SCAN_BEACON));
4125         SuccessOrExit(error = mEncoder.WriteUint8(aResult->mChannel));
4126         SuccessOrExit(error = mEncoder.WriteInt8(aResult->mRssi));
4127 
4128         SuccessOrExit(error = mEncoder.OpenStruct()); // "mac-layer data"
4129         SuccessOrExit(error = mEncoder.WriteEui64(aResult->mExtAddress));
4130         SuccessOrExit(error = mEncoder.WriteUint16(0xffff)); // short address, not given
4131         SuccessOrExit(error = mEncoder.WriteUint16(aResult->mPanId));
4132         SuccessOrExit(error = mEncoder.WriteUint8(aResult->mLqi));
4133         SuccessOrExit(error = mEncoder.CloseStruct());
4134 
4135         SuccessOrExit(error = mEncoder.OpenStruct());                                 // "net-layer data"
4136         SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROTOCOL_TYPE_THREAD)); // type
4137         SuccessOrExit(error = mEncoder.WriteUint8(flags));
4138         SuccessOrExit(error = mEncoder.WriteUtf8(aResult->mNetworkName.m8));
4139         SuccessOrExit(error = mEncoder.WriteDataWithLen(aResult->mExtendedPanId.m8, OT_EXT_PAN_ID_SIZE));
4140         SuccessOrExit(error = mEncoder.WriteDataWithLen(aResult->mSteeringData.m8, aResult->mSteeringData.mLength));
4141         SuccessOrExit(error = mEncoder.CloseStruct());
4142 
4143         SuccessOrExit(error = mEncoder.EndFrame());
4144     }
4145     else
4146     {
4147         // We are finished with the scan, send an unsolicited
4148         // scan state update.
4149         mChangedPropsSet.AddProperty(SPINEL_PROP_MAC_SCAN_STATE);
4150         mUpdateChangedPropsTask.Post();
4151     }
4152 
4153 exit:
4154 
4155     if (error != OT_ERROR_NONE)
4156     {
4157         // We ran out of buffer adding a scan result so remember to send
4158         // an async `LAST_STATUS(NOMEM)` when buffer space becomes
4159         // available.
4160         mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM);
4161         mUpdateChangedPropsTask.Post();
4162     }
4163 }
4164 
HandleEnergyScanResult_Jump(otEnergyScanResult * aResult,void * aContext)4165 void NcpBase::HandleEnergyScanResult_Jump(otEnergyScanResult *aResult, void *aContext)
4166 {
4167     static_cast<NcpBase *>(aContext)->HandleEnergyScanResult(aResult);
4168 }
4169 
HandleEnergyScanResult(otEnergyScanResult * aResult)4170 void NcpBase::HandleEnergyScanResult(otEnergyScanResult *aResult)
4171 {
4172     otError error = OT_ERROR_NONE;
4173 
4174     if (aResult)
4175     {
4176         SuccessOrExit(error = mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
4177                                                   SPINEL_CMD_PROP_VALUE_INSERTED, SPINEL_PROP_MAC_ENERGY_SCAN_RESULT));
4178         SuccessOrExit(error = mEncoder.WriteUint8(aResult->mChannel));
4179         SuccessOrExit(error = mEncoder.WriteInt8(aResult->mMaxRssi));
4180         SuccessOrExit(error = mEncoder.EndFrame());
4181     }
4182     else
4183     {
4184         // We are finished with the scan, send an unsolicited
4185         // scan state update.
4186         mChangedPropsSet.AddProperty(SPINEL_PROP_MAC_SCAN_STATE);
4187         mUpdateChangedPropsTask.Post();
4188     }
4189 
4190 exit:
4191 
4192     if (error != OT_ERROR_NONE)
4193     {
4194         mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM);
4195         mUpdateChangedPropsTask.Post();
4196     }
4197 }
4198 
4199 #if OPENTHREAD_CONFIG_JOINER_ENABLE
HandleJoinerCallback_Jump(otError aError,void * aContext)4200 void NcpBase::HandleJoinerCallback_Jump(otError aError, void *aContext)
4201 {
4202     static_cast<NcpBase *>(aContext)->HandleJoinerCallback(aError);
4203 }
4204 
HandleJoinerCallback(otError aError)4205 void NcpBase::HandleJoinerCallback(otError aError)
4206 {
4207     switch (aError)
4208     {
4209     case OT_ERROR_NONE:
4210         mChangedPropsSet.AddLastStatus(SPINEL_STATUS_JOIN_SUCCESS);
4211         break;
4212     case OT_ERROR_SECURITY:
4213         mChangedPropsSet.AddLastStatus(SPINEL_STATUS_JOIN_SECURITY);
4214         break;
4215     case OT_ERROR_NOT_FOUND:
4216         mChangedPropsSet.AddLastStatus(SPINEL_STATUS_JOIN_NO_PEERS);
4217         break;
4218     case OT_ERROR_RESPONSE_TIMEOUT:
4219         mChangedPropsSet.AddLastStatus(SPINEL_STATUS_JOIN_RSP_TIMEOUT);
4220         break;
4221     default:
4222         mChangedPropsSet.AddLastStatus(SPINEL_STATUS_JOIN_FAILURE);
4223         break;
4224     }
4225 
4226     mUpdateChangedPropsTask.Post();
4227 }
4228 #endif
4229 
4230 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
HandleLinkMetricsReport_Jump(const otIp6Address * aSource,const otLinkMetricsValues * aMetricsValues,otLinkMetricsStatus aStatus,void * aContext)4231 void NcpBase::HandleLinkMetricsReport_Jump(const otIp6Address        *aSource,
4232                                            const otLinkMetricsValues *aMetricsValues,
4233                                            otLinkMetricsStatus        aStatus,
4234                                            void                      *aContext)
4235 {
4236     static_cast<NcpBase *>(aContext)->HandleLinkMetricsReport(aSource, aMetricsValues, aStatus);
4237 }
4238 
HandleLinkMetricsReport(const otIp6Address * aSource,const otLinkMetricsValues * aMetricsValues,otLinkMetricsStatus aStatus)4239 void NcpBase::HandleLinkMetricsReport(const otIp6Address        *aSource,
4240                                       const otLinkMetricsValues *aMetricsValues,
4241                                       otLinkMetricsStatus        aStatus)
4242 {
4243     SuccessOrExit(mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_PROP_VALUE_IS,
4244                                       SPINEL_PROP_THREAD_LINK_METRICS_QUERY_RESULT));
4245 
4246     SuccessOrExit(mEncoder.WriteIp6Address(*aSource));
4247     SuccessOrExit(mEncoder.WriteUint8(aStatus));
4248     SuccessOrExit(EncodeLinkMetricsValues(aMetricsValues));
4249 
4250     SuccessOrExit(mEncoder.EndFrame());
4251 
4252 exit:
4253     return;
4254 }
4255 
HandleLinkMetricsMgmtResponse_Jump(const otIp6Address * aSource,otLinkMetricsStatus aStatus,void * aContext)4256 void NcpBase::HandleLinkMetricsMgmtResponse_Jump(const otIp6Address *aSource,
4257                                                  otLinkMetricsStatus aStatus,
4258                                                  void               *aContext)
4259 {
4260     static_cast<NcpBase *>(aContext)->HandleLinkMetricsMgmtResponse(aSource, aStatus);
4261 }
4262 
HandleLinkMetricsMgmtResponse(const otIp6Address * aSource,otLinkMetricsStatus aStatus)4263 void NcpBase::HandleLinkMetricsMgmtResponse(const otIp6Address *aSource, otLinkMetricsStatus aStatus)
4264 {
4265     SuccessOrExit(mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_PROP_VALUE_IS,
4266                                       SPINEL_PROP_THREAD_LINK_METRICS_MGMT_RESPONSE));
4267 
4268     SuccessOrExit(mEncoder.WriteIp6Address(*aSource));
4269     SuccessOrExit(mEncoder.WriteUint8(aStatus));
4270 
4271     SuccessOrExit(mEncoder.EndFrame());
4272 
4273 exit:
4274     return;
4275 }
4276 
HandleLinkMetricsEnhAckProbingIeReport_Jump(otShortAddress aShortAddress,const otExtAddress * aExtAddress,const otLinkMetricsValues * aMetricsValues,void * aContext)4277 void NcpBase::HandleLinkMetricsEnhAckProbingIeReport_Jump(otShortAddress             aShortAddress,
4278                                                           const otExtAddress        *aExtAddress,
4279                                                           const otLinkMetricsValues *aMetricsValues,
4280                                                           void                      *aContext)
4281 {
4282     static_cast<NcpBase *>(aContext)->HandleLinkMetricsEnhAckProbingIeReport(aShortAddress, aExtAddress,
4283                                                                              aMetricsValues);
4284 }
4285 
HandleLinkMetricsEnhAckProbingIeReport(otShortAddress aShortAddress,const otExtAddress * aExtAddress,const otLinkMetricsValues * aMetricsValues)4286 void NcpBase::HandleLinkMetricsEnhAckProbingIeReport(otShortAddress             aShortAddress,
4287                                                      const otExtAddress        *aExtAddress,
4288                                                      const otLinkMetricsValues *aMetricsValues)
4289 {
4290     SuccessOrExit(mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_PROP_VALUE_IS,
4291                                       SPINEL_PROP_THREAD_LINK_METRICS_MGMT_ENH_ACK_IE));
4292 
4293     SuccessOrExit(mEncoder.WriteUint16(aShortAddress));
4294     SuccessOrExit(mEncoder.WriteEui64(*aExtAddress));
4295     SuccessOrExit(EncodeLinkMetricsValues(aMetricsValues));
4296 
4297     SuccessOrExit(mEncoder.EndFrame());
4298 
4299 exit:
4300     return;
4301 }
4302 #endif
4303 
4304 // ----------------------------------------------------------------------------
4305 // MARK: Outbound Datagram Handling
4306 // ----------------------------------------------------------------------------
4307 
HandleDatagramFromStack(otMessage * aMessage,void * aContext)4308 void NcpBase::HandleDatagramFromStack(otMessage *aMessage, void *aContext)
4309 {
4310     static_cast<NcpBase *>(aContext)->HandleDatagramFromStack(aMessage);
4311 }
4312 
HandleDatagramFromStack(otMessage * aMessage)4313 void NcpBase::HandleDatagramFromStack(otMessage *aMessage)
4314 {
4315     VerifyOrExit(aMessage != nullptr);
4316 
4317     // Do not forward frames larger than SPINEL payload size.
4318     VerifyOrExit(otMessageGetLength(aMessage) <= SPINEL_FRAME_MAX_COMMAND_PAYLOAD_SIZE, otMessageFree(aMessage));
4319 
4320     otMessageQueueEnqueue(&mMessageQueue, aMessage);
4321 
4322     // If there is no queued spinel command response, try to write/send
4323     // the datagram message immediately. If there is a queued response
4324     // or if currently out of buffer space, the IPv6 datagram message
4325     // will be sent from `HandleFrameRemovedFromNcpBuffer()` when buffer
4326     //  space becomes available and after any pending spinel command
4327     // response.
4328 
4329     if (IsResponseQueueEmpty())
4330     {
4331         IgnoreError(SendQueuedDatagramMessages());
4332     }
4333 
4334 exit:
4335     return;
4336 }
4337 
SendDatagramMessage(otMessage * aMessage)4338 otError NcpBase::SendDatagramMessage(otMessage *aMessage)
4339 {
4340     otError           error    = OT_ERROR_NONE;
4341     uint8_t           header   = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
4342     bool              isSecure = otMessageIsLinkSecurityEnabled(aMessage);
4343     spinel_prop_key_t propKey  = isSecure ? SPINEL_PROP_STREAM_NET : SPINEL_PROP_STREAM_NET_INSECURE;
4344 
4345     SuccessOrExit(error = mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, propKey));
4346     SuccessOrExit(error = mEncoder.WriteUint16(otMessageGetLength(aMessage)));
4347     SuccessOrExit(error = mEncoder.WriteMessage(aMessage));
4348 
4349     // Append any metadata (rssi, lqi, channel, etc) here!
4350 
4351     SuccessOrExit(error = mEncoder.EndFrame());
4352 
4353     if (isSecure)
4354     {
4355         mOutboundSecureIpFrameCounter++;
4356     }
4357     else
4358     {
4359         mOutboundInsecureIpFrameCounter++;
4360     }
4361 
4362 exit:
4363     return error;
4364 }
4365 
SendQueuedDatagramMessages(void)4366 otError NcpBase::SendQueuedDatagramMessages(void)
4367 {
4368     otError    error = OT_ERROR_NONE;
4369     otMessage *message;
4370 
4371     while ((message = otMessageQueueGetHead(&mMessageQueue)) != nullptr)
4372     {
4373         // Since an `otMessage` instance can be in one queue at a time,
4374         // it is first dequeued from `mMessageQueue` before attempting
4375         // to include it in a spinel frame by calling `SendDatagramMessage()`
4376         // If forming of the spinel frame fails, the message is enqueued
4377         // back at the front of `mMessageQueue`.
4378 
4379         otMessageQueueDequeue(&mMessageQueue, message);
4380 
4381         error = SendDatagramMessage(message);
4382 
4383         if (error != OT_ERROR_NONE)
4384         {
4385             otMessageQueueEnqueueAtHead(&mMessageQueue, message);
4386         }
4387 
4388         SuccessOrExit(error);
4389     }
4390 
4391 exit:
4392     return error;
4393 }
4394 
4395 #if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE
HandlePropertySet(void)4396 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_UDP_FORWARD_STREAM>(void)
4397 {
4398     const uint8_t      *framePtr = nullptr;
4399     uint16_t            frameLen = 0;
4400     const otIp6Address *peerAddr;
4401     uint16_t            peerPort;
4402     uint16_t            sockPort;
4403     otMessage          *message;
4404     otError             error       = OT_ERROR_NONE;
4405     otMessageSettings   msgSettings = {false, OT_MESSAGE_PRIORITY_NORMAL};
4406 
4407     message = otIp6NewMessage(mInstance, &msgSettings);
4408     VerifyOrExit(message != nullptr, error = OT_ERROR_NO_BUFS);
4409 
4410     SuccessOrExit(error = mDecoder.ReadDataWithLen(framePtr, frameLen));
4411     SuccessOrExit(error = mDecoder.ReadUint16(peerPort));
4412     SuccessOrExit(error = mDecoder.ReadIp6Address(peerAddr));
4413     SuccessOrExit(error = mDecoder.ReadUint16(sockPort));
4414 
4415     SuccessOrExit(error = otMessageAppend(message, framePtr, static_cast<uint16_t>(frameLen)));
4416 
4417     otUdpForwardReceive(mInstance, message, peerPort, peerAddr, sockPort);
4418 
4419     // `otUdpForwardReceive()` takes ownership of `message` (in both success
4420     // or failure cases). `message` is set to nullptr so it is not freed at
4421     // exit.
4422     message = nullptr;
4423 
4424 exit:
4425     if (message != nullptr)
4426     {
4427         otMessageFree(message);
4428     }
4429 
4430     return error;
4431 }
4432 
HandleUdpForwardStream(otMessage * aMessage,uint16_t aPeerPort,otIp6Address * aPeerAddr,uint16_t aSockPort,void * aContext)4433 void NcpBase::HandleUdpForwardStream(otMessage    *aMessage,
4434                                      uint16_t      aPeerPort,
4435                                      otIp6Address *aPeerAddr,
4436                                      uint16_t      aSockPort,
4437                                      void         *aContext)
4438 {
4439     static_cast<NcpBase *>(aContext)->HandleUdpForwardStream(aMessage, aPeerPort, *aPeerAddr, aSockPort);
4440 }
4441 
HandleUdpForwardStream(otMessage * aMessage,uint16_t aPeerPort,otIp6Address & aPeerAddr,uint16_t aPort)4442 void NcpBase::HandleUdpForwardStream(otMessage *aMessage, uint16_t aPeerPort, otIp6Address &aPeerAddr, uint16_t aPort)
4443 {
4444     uint16_t length = otMessageGetLength(aMessage);
4445     uint8_t  header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
4446 
4447     SuccessOrExit(mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_THREAD_UDP_FORWARD_STREAM));
4448     SuccessOrExit(mEncoder.WriteUint16(length));
4449     SuccessOrExit(mEncoder.WriteMessage(aMessage));
4450 
4451     SuccessOrExit(mEncoder.WriteUint16(aPeerPort));
4452     SuccessOrExit(mEncoder.WriteIp6Address(aPeerAddr));
4453     SuccessOrExit(mEncoder.WriteUint16(aPort));
4454     SuccessOrExit(mEncoder.EndFrame());
4455 
4456     // The `aMessage` is owned by the outbound frame and NCP buffer
4457     // after frame was finished/ended successfully. It will be freed
4458     // when the frame is successfully sent and removed.
4459 
4460     aMessage = nullptr;
4461 
4462 exit:
4463 
4464     if (aMessage != nullptr)
4465     {
4466         otMessageFree(aMessage);
4467     }
4468 }
4469 #endif // OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE
4470 
4471 // ----------------------------------------------------------------------------
4472 // MARK: Pcap frame handling
4473 // ----------------------------------------------------------------------------
4474 
HandlePcapFrame(const otRadioFrame * aFrame,bool aIsTx,void * aContext)4475 void NcpBase::HandlePcapFrame(const otRadioFrame *aFrame, bool aIsTx, void *aContext)
4476 {
4477     static_cast<NcpBase *>(aContext)->HandlePcapFrame(aFrame, aIsTx);
4478 }
4479 
HandlePcapFrame(const otRadioFrame * aFrame,bool aIsTx)4480 void NcpBase::HandlePcapFrame(const otRadioFrame *aFrame, bool aIsTx)
4481 {
4482     uint16_t flags  = 0;
4483     uint8_t  header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
4484 
4485     VerifyOrExit(mPcapEnabled);
4486 
4487     if (aIsTx)
4488     {
4489         flags |= SPINEL_MD_FLAG_TX;
4490     }
4491 
4492     SuccessOrExit(mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_STREAM_RAW));
4493     SuccessOrExit(mEncoder.WriteUint16(aFrame->mLength));
4494 
4495     SuccessOrExit(mEncoder.WriteData(aFrame->mPsdu, aFrame->mLength));
4496 
4497     // Append metadata (rssi, etc)
4498     SuccessOrExit(mEncoder.WriteInt8(aFrame->mInfo.mRxInfo.mRssi)); // RSSI
4499     SuccessOrExit(mEncoder.WriteInt8(-128));                        // Noise floor (Currently unused)
4500     SuccessOrExit(mEncoder.WriteUint16(flags));                     // Flags
4501 
4502     SuccessOrExit(mEncoder.OpenStruct()); // PHY-data
4503     // Empty for now
4504     SuccessOrExit(mEncoder.CloseStruct());
4505 
4506     SuccessOrExit(mEncoder.OpenStruct()); // Vendor-data
4507     // Empty for now
4508     SuccessOrExit(mEncoder.CloseStruct());
4509 
4510     SuccessOrExit(mEncoder.EndFrame());
4511 
4512 exit:
4513     return;
4514 }
4515 
HandlePropertyGet(void)4516 template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_PHY_PCAP_ENABLED>(void)
4517 {
4518     return mEncoder.WriteBool(mPcapEnabled);
4519 }
4520 
HandlePropertySet(void)4521 template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_PHY_PCAP_ENABLED>(void)
4522 {
4523     otError error = OT_ERROR_NONE;
4524     bool    enabled;
4525 
4526     SuccessOrExit(error = mDecoder.ReadBool(enabled));
4527     VerifyOrExit(enabled != mPcapEnabled);
4528 
4529     mPcapEnabled = enabled;
4530 
4531     if (mPcapEnabled)
4532     {
4533         otLinkSetPcapCallback(mInstance, &NcpBase::HandlePcapFrame, static_cast<void *>(this));
4534     }
4535     else
4536     {
4537         otLinkSetPcapCallback(mInstance, nullptr, nullptr);
4538     }
4539 
4540 exit:
4541     return error;
4542 }
4543 
4544 // ----------------------------------------------------------------------------
4545 // MARK: Property/Status Changed
4546 // ----------------------------------------------------------------------------
4547 
HandleStateChanged(otChangedFlags aFlags,void * aContext)4548 void NcpBase::HandleStateChanged(otChangedFlags aFlags, void *aContext)
4549 {
4550     NcpBase *ncp = static_cast<NcpBase *>(aContext);
4551 
4552     ncp->mThreadChangedFlags |= aFlags;
4553     ncp->mUpdateChangedPropsTask.Post();
4554 }
4555 
ProcessThreadChangedFlags(void)4556 void NcpBase::ProcessThreadChangedFlags(void)
4557 {
4558     static const struct
4559     {
4560         otChangedFlags    mThreadFlag;
4561         spinel_prop_key_t mPropKey;
4562     } kFlags[] = {
4563         {OT_CHANGED_IP6_ADDRESS_ADDED, SPINEL_PROP_IPV6_ADDRESS_TABLE},
4564         {OT_CHANGED_IP6_ADDRESS_REMOVED, SPINEL_PROP_IPV6_ADDRESS_TABLE},
4565         {OT_CHANGED_THREAD_ROLE, SPINEL_PROP_NET_ROLE},
4566         {OT_CHANGED_THREAD_LL_ADDR, SPINEL_PROP_IPV6_LL_ADDR},
4567         {OT_CHANGED_THREAD_ML_ADDR, SPINEL_PROP_IPV6_ML_ADDR},
4568         {OT_CHANGED_THREAD_PARTITION_ID, SPINEL_PROP_NET_PARTITION_ID},
4569         {OT_CHANGED_THREAD_KEY_SEQUENCE_COUNTER, SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER},
4570         {OT_CHANGED_THREAD_NETDATA, SPINEL_PROP_THREAD_LEADER_NETWORK_DATA},
4571         {OT_CHANGED_THREAD_CHILD_ADDED, SPINEL_PROP_THREAD_CHILD_TABLE},
4572         {OT_CHANGED_THREAD_CHILD_REMOVED, SPINEL_PROP_THREAD_CHILD_TABLE},
4573         {OT_CHANGED_IP6_MULTICAST_SUBSCRIBED, SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE},
4574         {OT_CHANGED_IP6_MULTICAST_UNSUBSCRIBED, SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE},
4575         {OT_CHANGED_THREAD_CHANNEL, SPINEL_PROP_PHY_CHAN},
4576         {OT_CHANGED_THREAD_PANID, SPINEL_PROP_MAC_15_4_PANID},
4577         {OT_CHANGED_THREAD_NETWORK_NAME, SPINEL_PROP_NET_NETWORK_NAME},
4578         {OT_CHANGED_THREAD_EXT_PANID, SPINEL_PROP_NET_XPANID},
4579         {OT_CHANGED_THREAD_RLOC_ADDED, SPINEL_PROP_IPV6_ADDRESS_TABLE},
4580         {OT_CHANGED_THREAD_RLOC_REMOVED, SPINEL_PROP_IPV6_ADDRESS_TABLE},
4581         {OT_CHANGED_NETWORK_KEY, SPINEL_PROP_NET_NETWORK_KEY},
4582         {OT_CHANGED_PSKC, SPINEL_PROP_NET_PSKC},
4583         {OT_CHANGED_CHANNEL_MANAGER_NEW_CHANNEL, SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL},
4584         {OT_CHANGED_SUPPORTED_CHANNEL_MASK, SPINEL_PROP_PHY_CHAN_SUPPORTED},
4585     };
4586 
4587     VerifyOrExit(mThreadChangedFlags != 0);
4588 
4589     // If thread role has changed, check for possible "join" error.
4590 
4591     if ((mThreadChangedFlags & OT_CHANGED_THREAD_ROLE) != 0)
4592     {
4593         if (mRequireJoinExistingNetwork)
4594         {
4595             switch (otThreadGetDeviceRole(mInstance))
4596             {
4597             case OT_DEVICE_ROLE_DETACHED:
4598             case OT_DEVICE_ROLE_DISABLED:
4599                 break;
4600 
4601             default:
4602                 mRequireJoinExistingNetwork = false;
4603                 mChangedPropsSet.AddProperty(SPINEL_PROP_NET_REQUIRE_JOIN_EXISTING);
4604                 break;
4605             }
4606 
4607             if ((otThreadGetDeviceRole(mInstance) == OT_DEVICE_ROLE_LEADER) && otThreadIsSingleton(mInstance))
4608             {
4609                 mThreadChangedFlags &= ~static_cast<uint32_t>(OT_CHANGED_THREAD_PARTITION_ID);
4610                 IgnoreError(otThreadSetEnabled(mInstance, false));
4611 
4612                 mChangedPropsSet.AddProperty(SPINEL_PROP_NET_STACK_UP);
4613                 mChangedPropsSet.AddLastStatus(SPINEL_STATUS_JOIN_FAILURE);
4614             }
4615         }
4616     }
4617 
4618     // Convert OT_CHANGED flags to corresponding NCP property update.
4619 
4620     for (auto &flag : kFlags)
4621     {
4622         uint32_t threadFlag = flag.mThreadFlag;
4623 
4624         if (mThreadChangedFlags & threadFlag)
4625         {
4626             spinel_prop_key_t propKey           = flag.mPropKey;
4627             bool              shouldAddProperty = true;
4628 
4629             // Child table changes are reported using the `HandleChildAdded()` and
4630             // `HandleChildRemoved()` callbacks emitting spinel `VALUE_INSERTED` and
4631             // `VALUE_REMOVED` async spinel frames. If the spinel frames could not be
4632             // added (e.g., out of NCP buffer) from the above callbacks, the flag
4633             // `mShouldEmitChildTableUpdate` is set to `true` so that the entire
4634             // child table is emitted as an unsolicited `VALUE_IS` update.
4635 
4636             if (propKey == SPINEL_PROP_THREAD_CHILD_TABLE)
4637             {
4638                 shouldAddProperty           = mShouldEmitChildTableUpdate;
4639                 mShouldEmitChildTableUpdate = false;
4640             }
4641 
4642             if (shouldAddProperty)
4643             {
4644                 mChangedPropsSet.AddProperty(propKey);
4645             }
4646 
4647             if (threadFlag == OT_CHANGED_THREAD_NETDATA)
4648             {
4649                 mChangedPropsSet.AddProperty(SPINEL_PROP_THREAD_ON_MESH_NETS);
4650                 mChangedPropsSet.AddProperty(SPINEL_PROP_THREAD_OFF_MESH_ROUTES);
4651             }
4652 
4653             mThreadChangedFlags &= ~threadFlag;
4654             VerifyOrExit(mThreadChangedFlags != 0);
4655         }
4656     }
4657 
4658     // Clear any remaining ThreadFlag that has no matching
4659     // NCP property update (e.g., OT_CHANGED_SECURITY_POLICY)
4660 
4661     mThreadChangedFlags = 0;
4662 
4663 exit:
4664     return;
4665 }
4666 
4667 } // namespace Ncp
4668 } // namespace ot
4669 
4670 #endif // OPENTHREAD_MTD || OPENTHREAD_FTD
4671