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