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