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