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