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