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