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