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