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