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