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