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