1 /*
2 * Copyright (c) 2024, 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"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #define OTBR_LOG_TAG "NcpSpinel"
30
31 #include "ncp_spinel.hpp"
32
33 #include <stdarg.h>
34
35 #include <algorithm>
36
37 #include <openthread/dataset.h>
38 #include <openthread/thread.h>
39 #include <openthread/platform/dnssd.h>
40
41 #include "common/code_utils.hpp"
42 #include "common/logging.hpp"
43 #include "lib/spinel/spinel.h"
44 #include "lib/spinel/spinel_decoder.hpp"
45 #include "lib/spinel/spinel_driver.hpp"
46 #include "lib/spinel/spinel_encoder.hpp"
47 #include "lib/spinel/spinel_helper.hpp"
48 #include "lib/spinel/spinel_prop_codec.hpp"
49
50 namespace otbr {
51 namespace Host {
52
53 static constexpr char kSpinelDataUnpackFormat[] = "CiiD";
54
NcpSpinel(void)55 NcpSpinel::NcpSpinel(void)
56 : mSpinelDriver(nullptr)
57 , mCmdTidsInUse(0)
58 , mCmdNextTid(1)
59 , mNcpBuffer(mTxBuffer, kTxBufferSize)
60 , mEncoder(mNcpBuffer)
61 , mIid(SPINEL_HEADER_INVALID_IID)
62 , mPropsObserver(nullptr)
63 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
64 , mPublisher(nullptr)
65 #endif
66 {
67 std::fill_n(mWaitingKeyTable, SPINEL_PROP_LAST_STATUS, sizeof(mWaitingKeyTable));
68 memset(mCmdTable, 0, sizeof(mCmdTable));
69 }
70
Init(ot::Spinel::SpinelDriver & aSpinelDriver,PropsObserver & aObserver)71 void NcpSpinel::Init(ot::Spinel::SpinelDriver &aSpinelDriver, PropsObserver &aObserver)
72 {
73 mSpinelDriver = &aSpinelDriver;
74 mPropsObserver = &aObserver;
75 mIid = mSpinelDriver->GetIid();
76 mSpinelDriver->SetFrameHandler(&HandleReceivedFrame, &HandleSavedFrame, this);
77 }
78
Deinit(void)79 void NcpSpinel::Deinit(void)
80 {
81 mSpinelDriver = nullptr;
82 mIp6AddressTableCallback = nullptr;
83 mNetifStateChangedCallback = nullptr;
84 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
85 mPublisher = nullptr;
86 #endif
87 }
88
SpinelDataUnpack(const uint8_t * aDataIn,spinel_size_t aDataLen,const char * aPackFormat,...)89 otbrError NcpSpinel::SpinelDataUnpack(const uint8_t *aDataIn, spinel_size_t aDataLen, const char *aPackFormat, ...)
90 {
91 otbrError error = OTBR_ERROR_NONE;
92 spinel_ssize_t unpacked;
93 va_list args;
94
95 va_start(args, aPackFormat);
96 unpacked = spinel_datatype_vunpack(aDataIn, aDataLen, aPackFormat, args);
97 va_end(args);
98
99 VerifyOrExit(unpacked > 0, error = OTBR_ERROR_PARSE);
100
101 exit:
102 return error;
103 }
104
DatasetSetActiveTlvs(const otOperationalDatasetTlvs & aActiveOpDatasetTlvs,AsyncTaskPtr aAsyncTask)105 void NcpSpinel::DatasetSetActiveTlvs(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs, AsyncTaskPtr aAsyncTask)
106 {
107 otError error = OT_ERROR_NONE;
108 EncodingFunc encodingFunc = [&aActiveOpDatasetTlvs](ot::Spinel::Encoder &aEncoder) {
109 return aEncoder.WriteData(aActiveOpDatasetTlvs.mTlvs, aActiveOpDatasetTlvs.mLength);
110 };
111
112 VerifyOrExit(mDatasetSetActiveTask == nullptr, error = OT_ERROR_BUSY);
113
114 SuccessOrExit(error = SetProperty(SPINEL_PROP_THREAD_ACTIVE_DATASET_TLVS, encodingFunc));
115 mDatasetSetActiveTask = aAsyncTask;
116
117 exit:
118 if (error != OT_ERROR_NONE)
119 {
120 mTaskRunner.Post([aAsyncTask, error](void) { aAsyncTask->SetResult(error, "Failed to set active dataset!"); });
121 }
122 }
123
DatasetMgmtSetPending(std::shared_ptr<otOperationalDatasetTlvs> aPendingOpDatasetTlvsPtr,AsyncTaskPtr aAsyncTask)124 void NcpSpinel::DatasetMgmtSetPending(std::shared_ptr<otOperationalDatasetTlvs> aPendingOpDatasetTlvsPtr,
125 AsyncTaskPtr aAsyncTask)
126 {
127 otError error = OT_ERROR_NONE;
128 EncodingFunc encodingFunc = [aPendingOpDatasetTlvsPtr](ot::Spinel::Encoder &aEncoder) {
129 return aEncoder.WriteData(aPendingOpDatasetTlvsPtr->mTlvs, aPendingOpDatasetTlvsPtr->mLength);
130 };
131
132 VerifyOrExit(mDatasetMgmtSetPendingTask == nullptr, error = OT_ERROR_BUSY);
133
134 SuccessOrExit(error = SetProperty(SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS, encodingFunc));
135 mDatasetMgmtSetPendingTask = aAsyncTask;
136
137 exit:
138 if (error != OT_ERROR_NONE)
139 {
140 mTaskRunner.Post([aAsyncTask, error] { aAsyncTask->SetResult(error, "Failed to set pending dataset!"); });
141 }
142 }
143
Ip6SetEnabled(bool aEnable,AsyncTaskPtr aAsyncTask)144 void NcpSpinel::Ip6SetEnabled(bool aEnable, AsyncTaskPtr aAsyncTask)
145 {
146 otError error = OT_ERROR_NONE;
147 EncodingFunc encodingFunc = [aEnable](ot::Spinel::Encoder &aEncoder) { return aEncoder.WriteBool(aEnable); };
148
149 VerifyOrExit(mIp6SetEnabledTask == nullptr, error = OT_ERROR_BUSY);
150
151 SuccessOrExit(error = SetProperty(SPINEL_PROP_NET_IF_UP, encodingFunc));
152 mIp6SetEnabledTask = aAsyncTask;
153
154 exit:
155 if (error != OT_ERROR_NONE)
156 {
157 mTaskRunner.Post(
158 [aAsyncTask, error](void) { aAsyncTask->SetResult(error, "Failed to enable the network interface!"); });
159 }
160 return;
161 }
162
Ip6Send(const uint8_t * aData,uint16_t aLength)163 otbrError NcpSpinel::Ip6Send(const uint8_t *aData, uint16_t aLength)
164 {
165 otbrError error = OTBR_ERROR_NONE;
166 EncodingFunc encodingFunc = [aData, aLength](ot::Spinel::Encoder &aEncoder) {
167 return aEncoder.WriteDataWithLen(aData, aLength);
168 };
169
170 SuccessOrExit(SetProperty(SPINEL_PROP_STREAM_NET, encodingFunc), error = OTBR_ERROR_OPENTHREAD);
171
172 exit:
173 return error;
174 }
175
ThreadSetEnabled(bool aEnable,AsyncTaskPtr aAsyncTask)176 void NcpSpinel::ThreadSetEnabled(bool aEnable, AsyncTaskPtr aAsyncTask)
177 {
178 otError error = OT_ERROR_NONE;
179 EncodingFunc encodingFunc = [aEnable](ot::Spinel::Encoder &aEncoder) { return aEncoder.WriteBool(aEnable); };
180
181 VerifyOrExit(mThreadSetEnabledTask == nullptr, error = OT_ERROR_BUSY);
182
183 SuccessOrExit(error = SetProperty(SPINEL_PROP_NET_STACK_UP, encodingFunc));
184 mThreadSetEnabledTask = aAsyncTask;
185
186 exit:
187 if (error != OT_ERROR_NONE)
188 {
189 mTaskRunner.Post(
190 [aAsyncTask, error](void) { aAsyncTask->SetResult(error, "Failed to enable the Thread network!"); });
191 }
192 return;
193 }
194
ThreadDetachGracefully(AsyncTaskPtr aAsyncTask)195 void NcpSpinel::ThreadDetachGracefully(AsyncTaskPtr aAsyncTask)
196 {
197 otError error = OT_ERROR_NONE;
198 EncodingFunc encodingFunc = [](ot::Spinel::Encoder &) { return OT_ERROR_NONE; };
199
200 VerifyOrExit(mThreadDetachGracefullyTask == nullptr, error = OT_ERROR_BUSY);
201
202 SuccessOrExit(error = SetProperty(SPINEL_PROP_NET_LEAVE_GRACEFULLY, encodingFunc));
203 mThreadDetachGracefullyTask = aAsyncTask;
204
205 exit:
206 if (error != OT_ERROR_NONE)
207 {
208 mTaskRunner.Post([aAsyncTask, error](void) { aAsyncTask->SetResult(error, "Failed to detach gracefully!"); });
209 }
210 return;
211 }
212
ThreadErasePersistentInfo(AsyncTaskPtr aAsyncTask)213 void NcpSpinel::ThreadErasePersistentInfo(AsyncTaskPtr aAsyncTask)
214 {
215 otError error = OT_ERROR_NONE;
216 spinel_tid_t tid = GetNextTid();
217
218 VerifyOrExit(mThreadErasePersistentInfoTask == nullptr, error = OT_ERROR_BUSY);
219
220 SuccessOrExit(error = mSpinelDriver->SendCommand(SPINEL_CMD_NET_CLEAR, SPINEL_PROP_LAST_STATUS, tid));
221
222 mWaitingKeyTable[tid] = SPINEL_PROP_LAST_STATUS;
223 mCmdTable[tid] = SPINEL_CMD_NET_CLEAR;
224 mThreadErasePersistentInfoTask = aAsyncTask;
225
226 exit:
227 if (error != OT_ERROR_NONE)
228 {
229 FreeTidTableItem(tid);
230 mTaskRunner.Post(
231 [aAsyncTask, error](void) { aAsyncTask->SetResult(error, "Failed to erase persistent info!"); });
232 }
233 }
234
235 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
SrpServerSetAutoEnableMode(bool aEnabled)236 void NcpSpinel::SrpServerSetAutoEnableMode(bool aEnabled)
237 {
238 otError error;
239 EncodingFunc encodingFunc = [aEnabled](ot::Spinel::Encoder &aEncoder) { return aEncoder.WriteBool(aEnabled); };
240
241 error = SetProperty(SPINEL_PROP_SRP_SERVER_AUTO_ENABLE_MODE, encodingFunc);
242 if (error != OT_ERROR_NONE)
243 {
244 otbrLogWarning("Failed to call SrpServerSetAutoEnableMode, %s", otThreadErrorToString(error));
245 }
246 }
247
SrpServerSetEnabled(bool aEnabled)248 void NcpSpinel::SrpServerSetEnabled(bool aEnabled)
249 {
250 otError error;
251 EncodingFunc encodingFunc = [aEnabled](ot::Spinel::Encoder &aEncoder) { return aEncoder.WriteBool(aEnabled); };
252
253 error = SetProperty(SPINEL_PROP_SRP_SERVER_ENABLED, encodingFunc);
254 if (error != OT_ERROR_NONE)
255 {
256 otbrLogWarning("Failed to call SrpServerSetEnabled, %s", otThreadErrorToString(error));
257 }
258 }
259
DnssdSetState(Mdns::Publisher::State aState)260 void NcpSpinel::DnssdSetState(Mdns::Publisher::State aState)
261 {
262 otError error;
263 otPlatDnssdState state = (aState == Mdns::Publisher::State::kReady) ? OT_PLAT_DNSSD_READY : OT_PLAT_DNSSD_STOPPED;
264 EncodingFunc encodingFunc = [state](ot::Spinel::Encoder &aEncoder) { return aEncoder.WriteUint8(state); };
265
266 error = SetProperty(SPINEL_PROP_DNSSD_STATE, encodingFunc);
267 if (error != OT_ERROR_NONE)
268 {
269 otbrLogWarning("Failed to call DnssdSetState, %s", otThreadErrorToString(error));
270 }
271 }
272 #endif // OTBR_ENABLE_SRP_ADVERTISING_PROXY
273
HandleReceivedFrame(const uint8_t * aFrame,uint16_t aLength,uint8_t aHeader,bool & aSave,void * aContext)274 void NcpSpinel::HandleReceivedFrame(const uint8_t *aFrame,
275 uint16_t aLength,
276 uint8_t aHeader,
277 bool &aSave,
278 void *aContext)
279 {
280 static_cast<NcpSpinel *>(aContext)->HandleReceivedFrame(aFrame, aLength, aHeader, aSave);
281 }
282
HandleReceivedFrame(const uint8_t * aFrame,uint16_t aLength,uint8_t aHeader,bool & aShouldSaveFrame)283 void NcpSpinel::HandleReceivedFrame(const uint8_t *aFrame, uint16_t aLength, uint8_t aHeader, bool &aShouldSaveFrame)
284 {
285 spinel_tid_t tid = SPINEL_HEADER_GET_TID(aHeader);
286
287 if (tid == 0)
288 {
289 HandleNotification(aFrame, aLength);
290 }
291 else if (tid < kMaxTids)
292 {
293 HandleResponse(tid, aFrame, aLength);
294 }
295 else
296 {
297 otbrLogCrit("Received unexpected tid: %u", tid);
298 }
299
300 aShouldSaveFrame = false;
301 }
302
HandleSavedFrame(const uint8_t * aFrame,uint16_t aLength,void * aContext)303 void NcpSpinel::HandleSavedFrame(const uint8_t *aFrame, uint16_t aLength, void *aContext)
304 {
305 /* Intentionally Empty */
306 OT_UNUSED_VARIABLE(aFrame);
307 OT_UNUSED_VARIABLE(aLength);
308 OT_UNUSED_VARIABLE(aContext);
309 }
310
HandleNotification(const uint8_t * aFrame,uint16_t aLength)311 void NcpSpinel::HandleNotification(const uint8_t *aFrame, uint16_t aLength)
312 {
313 spinel_prop_key_t key;
314 spinel_size_t len = 0;
315 uint8_t *data = nullptr;
316 uint32_t cmd;
317 uint8_t header;
318 otbrError error = OTBR_ERROR_NONE;
319
320 SuccessOrExit(error = SpinelDataUnpack(aFrame, aLength, kSpinelDataUnpackFormat, &header, &cmd, &key, &data, &len));
321 VerifyOrExit(SPINEL_HEADER_GET_TID(header) == 0, error = OTBR_ERROR_PARSE);
322
323 switch (cmd)
324 {
325 case SPINEL_CMD_PROP_VALUE_IS:
326 HandleValueIs(key, data, static_cast<uint16_t>(len));
327 break;
328 case SPINEL_CMD_PROP_VALUE_INSERTED:
329 HandleValueInserted(key, data, static_cast<uint16_t>(len));
330 break;
331 case SPINEL_CMD_PROP_VALUE_REMOVED:
332 HandleValueRemoved(key, data, static_cast<uint16_t>(len));
333 break;
334 }
335
336 exit:
337 otbrLogResult(error, "%s", __FUNCTION__);
338 }
339
HandleResponse(spinel_tid_t aTid,const uint8_t * aFrame,uint16_t aLength)340 void NcpSpinel::HandleResponse(spinel_tid_t aTid, const uint8_t *aFrame, uint16_t aLength)
341 {
342 spinel_prop_key_t key;
343 spinel_size_t len = 0;
344 uint8_t *data = nullptr;
345 uint32_t cmd;
346 uint8_t header;
347 otbrError error = OTBR_ERROR_NONE;
348 FailureHandler failureHandler = nullptr;
349
350 SuccessOrExit(error = SpinelDataUnpack(aFrame, aLength, kSpinelDataUnpackFormat, &header, &cmd, &key, &data, &len));
351
352 switch (mCmdTable[aTid])
353 {
354 case SPINEL_CMD_PROP_VALUE_SET:
355 {
356 error = HandleResponseForPropSet(aTid, key, data, len);
357 break;
358 }
359 case SPINEL_CMD_PROP_VALUE_INSERT:
360 {
361 error = HandleResponseForPropInsert(aTid, cmd, key, data, len);
362 break;
363 }
364 case SPINEL_CMD_PROP_VALUE_REMOVE:
365 {
366 error = HandleResponseForPropRemove(aTid, cmd, key, data, len);
367 break;
368 }
369 case SPINEL_CMD_NET_CLEAR:
370 {
371 spinel_status_t status = SPINEL_STATUS_OK;
372
373 SuccessOrExit(error = SpinelDataUnpack(data, len, SPINEL_DATATYPE_UINT_PACKED_S, &status));
374 CallAndClear(mThreadErasePersistentInfoTask, ot::Spinel::SpinelStatusToOtError(status));
375 break;
376 }
377 default:
378 break;
379 }
380
381 exit:
382 if (error == OTBR_ERROR_INVALID_STATE)
383 {
384 otbrLogCrit("Received unexpected response with (cmd:%u, key:%u), waiting (cmd:%u, key:%u) for tid:%u", cmd, key,
385 mCmdTable[aTid], mWaitingKeyTable[aTid], aTid);
386 }
387 else if (error == OTBR_ERROR_PARSE)
388 {
389 otbrLogCrit("Error parsing response with tid:%u", aTid);
390 }
391 FreeTidTableItem(aTid);
392 }
393
HandleValueIs(spinel_prop_key_t aKey,const uint8_t * aBuffer,uint16_t aLength)394 void NcpSpinel::HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength)
395 {
396 otbrError error = OTBR_ERROR_NONE;
397
398 switch (aKey)
399 {
400 case SPINEL_PROP_LAST_STATUS:
401 {
402 spinel_status_t status = SPINEL_STATUS_OK;
403
404 SuccessOrExit(error = SpinelDataUnpack(aBuffer, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status));
405
406 otbrLogInfo("NCP last status: %s", spinel_status_to_cstr(status));
407 break;
408 }
409
410 case SPINEL_PROP_NET_ROLE:
411 {
412 spinel_net_role_t role = SPINEL_NET_ROLE_DISABLED;
413 otDeviceRole deviceRole;
414
415 SuccessOrExit(error = SpinelDataUnpack(aBuffer, aLength, SPINEL_DATATYPE_UINT8_S, &role));
416
417 deviceRole = SpinelRoleToDeviceRole(role);
418 mPropsObserver->SetDeviceRole(deviceRole);
419
420 otbrLogInfo("Device role changed to %s", otThreadDeviceRoleToString(deviceRole));
421 break;
422 }
423
424 case SPINEL_PROP_NET_LEAVE_GRACEFULLY:
425 {
426 CallAndClear(mThreadDetachGracefullyTask, OT_ERROR_NONE);
427 break;
428 }
429
430 case SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS:
431 {
432 spinel_status_t status = SPINEL_STATUS_OK;
433
434 SuccessOrExit(error = SpinelDataUnpack(aBuffer, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status));
435 CallAndClear(mDatasetMgmtSetPendingTask, ot::Spinel::SpinelStatusToOtError(status));
436 break;
437 }
438
439 case SPINEL_PROP_IPV6_ADDRESS_TABLE:
440 {
441 std::vector<Ip6AddressInfo> addressInfoTable;
442
443 VerifyOrExit(ParseIp6AddressTable(aBuffer, aLength, addressInfoTable) == OT_ERROR_NONE,
444 error = OTBR_ERROR_PARSE);
445 SafeInvoke(mIp6AddressTableCallback, addressInfoTable);
446 break;
447 }
448
449 case SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE:
450 {
451 std::vector<Ip6Address> addressTable;
452
453 VerifyOrExit(ParseIp6MulticastAddresses(aBuffer, aLength, addressTable) == OT_ERROR_NONE,
454 error = OTBR_ERROR_PARSE);
455 SafeInvoke(mIp6MulticastAddressTableCallback, addressTable);
456 break;
457 }
458
459 case SPINEL_PROP_NET_IF_UP:
460 {
461 bool isUp;
462 SuccessOrExit(error = SpinelDataUnpack(aBuffer, aLength, SPINEL_DATATYPE_BOOL_S, &isUp));
463 SafeInvoke(mNetifStateChangedCallback, isUp);
464 break;
465 }
466
467 case SPINEL_PROP_THREAD_CHILD_TABLE:
468 case SPINEL_PROP_THREAD_ON_MESH_NETS:
469 case SPINEL_PROP_THREAD_OFF_MESH_ROUTES:
470 case SPINEL_PROP_THREAD_LEADER_NETWORK_DATA:
471 case SPINEL_PROP_IPV6_LL_ADDR:
472 break;
473
474 case SPINEL_PROP_STREAM_NET:
475 {
476 const uint8_t *data;
477 uint16_t dataLen;
478
479 SuccessOrExit(ParseIp6StreamNet(aBuffer, aLength, data, dataLen), error = OTBR_ERROR_PARSE);
480 SafeInvoke(mIp6ReceiveCallback, data, dataLen);
481 break;
482 }
483
484 case SPINEL_PROP_INFRA_IF_SEND_ICMP6:
485 {
486 uint32_t infraIfIndex;
487 const otIp6Address *destAddress;
488 const uint8_t *data;
489 uint16_t dataLen;
490
491 SuccessOrExit(ParseInfraIfIcmp6Nd(aBuffer, aLength, infraIfIndex, destAddress, data, dataLen),
492 error = OTBR_ERROR_PARSE);
493 SafeInvoke(mInfraIfIcmp6NdCallback, infraIfIndex, *destAddress, data, dataLen);
494 break;
495 }
496
497 default:
498 otbrLogWarning("Received uncognized key: %u", aKey);
499 break;
500 }
501
502 exit:
503 otbrLogResult(error, "NcpSpinel: %s", __FUNCTION__);
504 return;
505 }
506
507 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
KeyNameFor(const otPlatDnssdKey & aKey)508 static std::string KeyNameFor(const otPlatDnssdKey &aKey)
509 {
510 std::string name(aKey.mName);
511
512 if (aKey.mServiceType != nullptr)
513 {
514 // TODO: current code would not work with service instance labels that include a '.'
515 name += ".";
516 name += aKey.mServiceType;
517 }
518 return name;
519 }
520 #endif
521
HandleValueInserted(spinel_prop_key_t aKey,const uint8_t * aBuffer,uint16_t aLength)522 void NcpSpinel::HandleValueInserted(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength)
523 {
524 otbrError error = OTBR_ERROR_NONE;
525 ot::Spinel::Decoder decoder;
526
527 VerifyOrExit(aBuffer != nullptr, error = OTBR_ERROR_INVALID_ARGS);
528 decoder.Init(aBuffer, aLength);
529
530 switch (aKey)
531 {
532 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
533 case SPINEL_PROP_DNSSD_HOST:
534 {
535 Mdns::Publisher::AddressList addressList;
536 otPlatDnssdHost host;
537 otPlatDnssdRequestId requestId;
538 const uint8_t *callbackData;
539 uint16_t callbackDataSize;
540 std::vector<uint8_t> callbackDataCopy;
541
542 SuccessOrExit(ot::Spinel::DecodeDnssdHost(decoder, host, requestId, callbackData, callbackDataSize));
543 for (uint16_t i = 0; i < host.mAddressesLength; i++)
544 {
545 addressList.push_back(Ip6Address(host.mAddresses[i].mFields.m8));
546 }
547 callbackDataCopy.assign(callbackData, callbackData + callbackDataSize);
548
549 mPublisher->PublishHost(host.mHostName, addressList, [this, requestId, callbackDataCopy](otbrError aError) {
550 OT_UNUSED_VARIABLE(SendDnssdResult(requestId, callbackDataCopy, OtbrErrorToOtError(aError)));
551 });
552 break;
553 }
554 case SPINEL_PROP_DNSSD_SERVICE:
555 {
556 otPlatDnssdService service;
557 Mdns::Publisher::SubTypeList subTypeList;
558 const char *subTypeArray[kMaxSubTypes];
559 uint16_t subTypeCount;
560 Mdns::Publisher::TxtData txtData;
561 otPlatDnssdRequestId requestId;
562 const uint8_t *callbackData;
563 uint16_t callbackDataSize;
564 std::vector<uint8_t> callbackDataCopy;
565
566 SuccessOrExit(ot::Spinel::DecodeDnssdService(decoder, service, subTypeArray, subTypeCount, requestId,
567 callbackData, callbackDataSize));
568 for (uint16_t i = 0; i < subTypeCount; i++)
569 {
570 subTypeList.push_back(subTypeArray[i]);
571 }
572 txtData.assign(service.mTxtData, service.mTxtData + service.mTxtDataLength);
573 callbackDataCopy.assign(callbackData, callbackData + callbackDataSize);
574
575 mPublisher->PublishService(service.mHostName, service.mServiceInstance, service.mServiceType, subTypeList,
576 service.mPort, txtData, [this, requestId, callbackDataCopy](otbrError aError) {
577 OT_UNUSED_VARIABLE(
578 SendDnssdResult(requestId, callbackDataCopy, OtbrErrorToOtError(aError)));
579 });
580 break;
581 }
582 case SPINEL_PROP_DNSSD_KEY_RECORD:
583 {
584 otPlatDnssdKey key;
585 Mdns::Publisher::KeyData keyData;
586 otPlatDnssdRequestId requestId;
587 const uint8_t *callbackData;
588 uint16_t callbackDataSize;
589 std::vector<uint8_t> callbackDataCopy;
590
591 SuccessOrExit(ot::Spinel::DecodeDnssdKey(decoder, key, requestId, callbackData, callbackDataSize));
592 keyData.assign(key.mKeyData, key.mKeyData + key.mKeyDataLength);
593 callbackDataCopy.assign(callbackData, callbackData + callbackDataSize);
594
595 mPublisher->PublishKey(KeyNameFor(key), keyData, [this, requestId, callbackDataCopy](otbrError aError) {
596 OT_UNUSED_VARIABLE(SendDnssdResult(requestId, callbackDataCopy, OtbrErrorToOtError(aError)));
597 });
598 break;
599 }
600 #endif // OTBR_ENABLE_SRP_ADVERTISING_PROXY
601 default:
602 error = OTBR_ERROR_DROPPED;
603 break;
604 }
605
606 exit:
607 otbrLogResult(error, "HandleValueInserted, key:%u", aKey);
608 return;
609 }
610
HandleValueRemoved(spinel_prop_key_t aKey,const uint8_t * aBuffer,uint16_t aLength)611 void NcpSpinel::HandleValueRemoved(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength)
612 {
613 otbrError error = OTBR_ERROR_NONE;
614 ot::Spinel::Decoder decoder;
615
616 VerifyOrExit(aBuffer != nullptr, error = OTBR_ERROR_INVALID_ARGS);
617 decoder.Init(aBuffer, aLength);
618
619 switch (aKey)
620 {
621 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
622 case SPINEL_PROP_DNSSD_HOST:
623 {
624 otPlatDnssdHost host;
625 otPlatDnssdRequestId requestId;
626 const uint8_t *callbackData;
627 uint16_t callbackDataSize;
628 std::vector<uint8_t> callbackDataCopy;
629
630 SuccessOrExit(ot::Spinel::DecodeDnssdHost(decoder, host, requestId, callbackData, callbackDataSize));
631 callbackDataCopy.assign(callbackData, callbackData + callbackDataSize);
632
633 mPublisher->UnpublishHost(host.mHostName, [this, requestId, callbackDataCopy](otbrError aError) {
634 OT_UNUSED_VARIABLE(SendDnssdResult(requestId, callbackDataCopy, OtbrErrorToOtError(aError)));
635 });
636 break;
637 }
638 case SPINEL_PROP_DNSSD_SERVICE:
639 {
640 otPlatDnssdService service;
641 const char *subTypeArray[kMaxSubTypes];
642 uint16_t subTypeCount;
643 otPlatDnssdRequestId requestId;
644 const uint8_t *callbackData;
645 uint16_t callbackDataSize;
646 std::vector<uint8_t> callbackDataCopy;
647
648 SuccessOrExit(ot::Spinel::DecodeDnssdService(decoder, service, subTypeArray, subTypeCount, requestId,
649 callbackData, callbackDataSize));
650 callbackDataCopy.assign(callbackData, callbackData + callbackDataSize);
651
652 mPublisher->UnpublishService(
653 service.mHostName, service.mServiceType, [this, requestId, callbackDataCopy](otbrError aError) {
654 OT_UNUSED_VARIABLE(SendDnssdResult(requestId, callbackDataCopy, OtbrErrorToOtError(aError)));
655 });
656 break;
657 }
658 case SPINEL_PROP_DNSSD_KEY_RECORD:
659 {
660 otPlatDnssdKey key;
661 otPlatDnssdRequestId requestId;
662 const uint8_t *callbackData;
663 uint16_t callbackDataSize;
664 std::vector<uint8_t> callbackDataCopy;
665
666 SuccessOrExit(ot::Spinel::DecodeDnssdKey(decoder, key, requestId, callbackData, callbackDataSize));
667 callbackDataCopy.assign(callbackData, callbackData + callbackDataSize);
668
669 mPublisher->UnpublishKey(KeyNameFor(key), [this, requestId, callbackDataCopy](otbrError aError) {
670 OT_UNUSED_VARIABLE(SendDnssdResult(requestId, callbackDataCopy, OtbrErrorToOtError(aError)));
671 });
672 break;
673 }
674 #endif // OTBR_ENABLE_SRP_ADVERTISING_PROXY
675 default:
676 error = OTBR_ERROR_DROPPED;
677 break;
678 }
679
680 exit:
681 otbrLogResult(error, "HandleValueRemoved, key:%u", aKey);
682 return;
683 }
684
HandleResponseForPropSet(spinel_tid_t aTid,spinel_prop_key_t aKey,const uint8_t * aData,uint16_t aLength)685 otbrError NcpSpinel::HandleResponseForPropSet(spinel_tid_t aTid,
686 spinel_prop_key_t aKey,
687 const uint8_t *aData,
688 uint16_t aLength)
689 {
690 OTBR_UNUSED_VARIABLE(aData);
691 OTBR_UNUSED_VARIABLE(aLength);
692
693 otbrError error = OTBR_ERROR_NONE;
694 spinel_status_t status = SPINEL_STATUS_OK;
695
696 switch (mWaitingKeyTable[aTid])
697 {
698 case SPINEL_PROP_THREAD_ACTIVE_DATASET_TLVS:
699 VerifyOrExit(aKey == SPINEL_PROP_THREAD_ACTIVE_DATASET_TLVS, error = OTBR_ERROR_INVALID_STATE);
700 CallAndClear(mDatasetSetActiveTask, OT_ERROR_NONE);
701 {
702 otOperationalDatasetTlvs datasetTlvs;
703 VerifyOrExit(ParseOperationalDatasetTlvs(aData, aLength, datasetTlvs) == OT_ERROR_NONE,
704 error = OTBR_ERROR_PARSE);
705 mPropsObserver->SetDatasetActiveTlvs(datasetTlvs);
706 }
707 break;
708
709 case SPINEL_PROP_NET_IF_UP:
710 VerifyOrExit(aKey == SPINEL_PROP_NET_IF_UP, error = OTBR_ERROR_INVALID_STATE);
711 CallAndClear(mIp6SetEnabledTask, OT_ERROR_NONE);
712 {
713 bool isUp;
714 SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_BOOL_S, &isUp));
715 SafeInvoke(mNetifStateChangedCallback, isUp);
716 }
717 break;
718
719 case SPINEL_PROP_NET_STACK_UP:
720 VerifyOrExit(aKey == SPINEL_PROP_NET_STACK_UP, error = OTBR_ERROR_INVALID_STATE);
721 CallAndClear(mThreadSetEnabledTask, OT_ERROR_NONE);
722 break;
723
724 case SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS:
725 if (aKey == SPINEL_PROP_LAST_STATUS)
726 { // Failed case
727 SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status));
728 CallAndClear(mDatasetMgmtSetPendingTask, ot::Spinel::SpinelStatusToOtError(status));
729 }
730 else if (aKey != SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS)
731 {
732 ExitNow(error = OTBR_ERROR_INVALID_STATE);
733 }
734 break;
735
736 case SPINEL_PROP_STREAM_NET:
737 break;
738
739 case SPINEL_PROP_INFRA_IF_STATE:
740 VerifyOrExit(aKey == SPINEL_PROP_LAST_STATUS, error = OTBR_ERROR_INVALID_STATE);
741 SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status));
742 otbrLogInfo("Infra If state update result: %s", spinel_status_to_cstr(status));
743 break;
744
745 case SPINEL_PROP_INFRA_IF_RECV_ICMP6:
746 VerifyOrExit(aKey == SPINEL_PROP_LAST_STATUS, error = OTBR_ERROR_INVALID_STATE);
747 SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status));
748 otbrLogInfo("Infra If handle ICMP6 ND result: %s", spinel_status_to_cstr(status));
749 break;
750
751 case SPINEL_PROP_DNSSD_STATE:
752 VerifyOrExit(aKey == SPINEL_PROP_LAST_STATUS, error = OTBR_ERROR_INVALID_STATE);
753 SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status));
754 otbrLogInfo("Update dnssd state result: %s", spinel_status_to_cstr(status));
755 break;
756
757 default:
758 VerifyOrExit(aKey == mWaitingKeyTable[aTid], error = OTBR_ERROR_INVALID_STATE);
759 break;
760 }
761
762 exit:
763 return error;
764 }
765
HandleResponseForPropInsert(spinel_tid_t aTid,spinel_command_t aCmd,spinel_prop_key_t aKey,const uint8_t * aData,uint16_t aLength)766 otbrError NcpSpinel::HandleResponseForPropInsert(spinel_tid_t aTid,
767 spinel_command_t aCmd,
768 spinel_prop_key_t aKey,
769 const uint8_t *aData,
770 uint16_t aLength)
771 {
772 otbrError error = OTBR_ERROR_NONE;
773
774 switch (mWaitingKeyTable[aTid])
775 {
776 case SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE:
777 if (aCmd == SPINEL_CMD_PROP_VALUE_IS)
778 {
779 spinel_status_t status = SPINEL_STATUS_OK;
780
781 VerifyOrExit(aKey == SPINEL_PROP_LAST_STATUS, error = OTBR_ERROR_INVALID_STATE);
782 SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status));
783 otbrLogInfo("Failed to subscribe to multicast address on NCP, error:%s", spinel_status_to_cstr(status));
784 }
785 else
786 {
787 error = aCmd == SPINEL_CMD_PROP_VALUE_INSERTED ? OTBR_ERROR_NONE : OTBR_ERROR_INVALID_STATE;
788 }
789 break;
790 default:
791 break;
792 }
793
794 exit:
795 otbrLogResult(error, "HandleResponseForPropInsert, key:%u", mWaitingKeyTable[aTid]);
796 return error;
797 }
798
HandleResponseForPropRemove(spinel_tid_t aTid,spinel_command_t aCmd,spinel_prop_key_t aKey,const uint8_t * aData,uint16_t aLength)799 otbrError NcpSpinel::HandleResponseForPropRemove(spinel_tid_t aTid,
800 spinel_command_t aCmd,
801 spinel_prop_key_t aKey,
802 const uint8_t *aData,
803 uint16_t aLength)
804 {
805 otbrError error = OTBR_ERROR_NONE;
806
807 switch (mWaitingKeyTable[aTid])
808 {
809 case SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE:
810 if (aCmd == SPINEL_CMD_PROP_VALUE_IS)
811 {
812 spinel_status_t status = SPINEL_STATUS_OK;
813
814 VerifyOrExit(aKey == SPINEL_PROP_LAST_STATUS, error = OTBR_ERROR_INVALID_STATE);
815 SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status));
816 otbrLogInfo("Failed to unsubscribe to multicast address on NCP, error:%s", spinel_status_to_cstr(status));
817 }
818 else
819 {
820 error = aCmd == SPINEL_CMD_PROP_VALUE_REMOVED ? OTBR_ERROR_NONE : OTBR_ERROR_INVALID_STATE;
821 }
822 break;
823 default:
824 break;
825 }
826
827 exit:
828 otbrLogResult(error, "HandleResponseForPropRemove, key:%u", mWaitingKeyTable[aTid]);
829 return error;
830 }
831
Ip6MulAddrUpdateSubscription(const otIp6Address & aAddress,bool aIsAdded)832 otbrError NcpSpinel::Ip6MulAddrUpdateSubscription(const otIp6Address &aAddress, bool aIsAdded)
833 {
834 otbrError error = OTBR_ERROR_NONE;
835 EncodingFunc encodingFunc = [&aAddress](ot::Spinel::Encoder &aEncoder) {
836 return aEncoder.WriteIp6Address(aAddress);
837 };
838
839 if (aIsAdded)
840 {
841 SuccessOrExit(InsertProperty(SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE, encodingFunc),
842 error = OTBR_ERROR_OPENTHREAD);
843 }
844 else
845 {
846 SuccessOrExit(RemoveProperty(SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE, encodingFunc),
847 error = OTBR_ERROR_OPENTHREAD);
848 }
849
850 exit:
851 return error;
852 }
853
GetNextTid(void)854 spinel_tid_t NcpSpinel::GetNextTid(void)
855 {
856 spinel_tid_t tid = mCmdNextTid;
857
858 while (((1 << tid) & mCmdTidsInUse) != 0)
859 {
860 tid = SPINEL_GET_NEXT_TID(tid);
861
862 if (tid == mCmdNextTid)
863 {
864 // We looped back to `mCmdNextTid` indicating that all
865 // TIDs are in-use.
866
867 ExitNow(tid = 0);
868 }
869 }
870
871 mCmdTidsInUse |= (1 << tid);
872 mCmdNextTid = SPINEL_GET_NEXT_TID(tid);
873
874 exit:
875 return tid;
876 }
877
FreeTidTableItem(spinel_tid_t aTid)878 void NcpSpinel::FreeTidTableItem(spinel_tid_t aTid)
879 {
880 mCmdTidsInUse &= ~(1 << aTid);
881
882 mCmdTable[aTid] = SPINEL_CMD_NOOP;
883 mWaitingKeyTable[aTid] = SPINEL_PROP_LAST_STATUS;
884 }
885
SendCommand(spinel_command_t aCmd,spinel_prop_key_t aKey,const EncodingFunc & aEncodingFunc)886 otError NcpSpinel::SendCommand(spinel_command_t aCmd, spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc)
887 {
888 otError error = OT_ERROR_NONE;
889 spinel_tid_t tid = GetNextTid();
890 uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID(mIid) | tid;
891
892 VerifyOrExit(tid != 0, error = OT_ERROR_BUSY);
893 SuccessOrExit(error = mEncoder.BeginFrame(header, aCmd, aKey));
894 SuccessOrExit(error = aEncodingFunc(mEncoder));
895 SuccessOrExit(error = mEncoder.EndFrame());
896 SuccessOrExit(error = SendEncodedFrame());
897
898 mCmdTable[tid] = aCmd;
899 mWaitingKeyTable[tid] = aKey;
900 exit:
901 if (error != OT_ERROR_NONE)
902 {
903 FreeTidTableItem(tid);
904 }
905 return error;
906 }
907
SetProperty(spinel_prop_key_t aKey,const EncodingFunc & aEncodingFunc)908 otError NcpSpinel::SetProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc)
909 {
910 return SendCommand(SPINEL_CMD_PROP_VALUE_SET, aKey, aEncodingFunc);
911 }
912
InsertProperty(spinel_prop_key_t aKey,const EncodingFunc & aEncodingFunc)913 otError NcpSpinel::InsertProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc)
914 {
915 return SendCommand(SPINEL_CMD_PROP_VALUE_INSERT, aKey, aEncodingFunc);
916 }
917
RemoveProperty(spinel_prop_key_t aKey,const EncodingFunc & aEncodingFunc)918 otError NcpSpinel::RemoveProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc)
919 {
920 return SendCommand(SPINEL_CMD_PROP_VALUE_REMOVE, aKey, aEncodingFunc);
921 }
922
SendEncodedFrame(void)923 otError NcpSpinel::SendEncodedFrame(void)
924 {
925 otError error = OT_ERROR_NONE;
926 uint8_t frame[kTxBufferSize];
927 uint16_t frameLength;
928
929 SuccessOrExit(error = mNcpBuffer.OutFrameBegin());
930 frameLength = mNcpBuffer.OutFrameGetLength();
931 VerifyOrExit(mNcpBuffer.OutFrameRead(frameLength, frame) == frameLength, error = OT_ERROR_FAILED);
932 SuccessOrExit(error = mSpinelDriver->GetSpinelInterface()->SendFrame(frame, frameLength));
933
934 exit:
935 error = mNcpBuffer.OutFrameRemove();
936 return error;
937 }
938
ParseIp6AddressTable(const uint8_t * aBuf,uint16_t aLength,std::vector<Ip6AddressInfo> & aAddressTable)939 otError NcpSpinel::ParseIp6AddressTable(const uint8_t *aBuf,
940 uint16_t aLength,
941 std::vector<Ip6AddressInfo> &aAddressTable)
942 {
943 otError error = OT_ERROR_NONE;
944 ot::Spinel::Decoder decoder;
945
946 VerifyOrExit(aBuf != nullptr, error = OT_ERROR_INVALID_ARGS);
947 decoder.Init(aBuf, aLength);
948
949 while (!decoder.IsAllReadInStruct())
950 {
951 Ip6AddressInfo cur;
952 const otIp6Address *addr;
953 uint8_t prefixLength;
954 uint32_t preferredLifetime;
955 uint32_t validLifetime;
956
957 SuccessOrExit(error = decoder.OpenStruct());
958 SuccessOrExit(error = decoder.ReadIp6Address(addr));
959 memcpy(&cur.mAddress, addr, sizeof(otIp6Address));
960 SuccessOrExit(error = decoder.ReadUint8(prefixLength));
961 cur.mPrefixLength = prefixLength;
962 SuccessOrExit(error = decoder.ReadUint32(preferredLifetime));
963 cur.mPreferred = preferredLifetime ? true : false;
964 SuccessOrExit(error = decoder.ReadUint32(validLifetime));
965 OTBR_UNUSED_VARIABLE(validLifetime);
966 SuccessOrExit((error = decoder.CloseStruct()));
967
968 aAddressTable.push_back(cur);
969 }
970
971 exit:
972 return error;
973 }
974
ParseIp6MulticastAddresses(const uint8_t * aBuf,uint16_t aLen,std::vector<Ip6Address> & aAddressList)975 otError NcpSpinel::ParseIp6MulticastAddresses(const uint8_t *aBuf, uint16_t aLen, std::vector<Ip6Address> &aAddressList)
976 {
977 otError error = OT_ERROR_NONE;
978 ot::Spinel::Decoder decoder;
979
980 VerifyOrExit(aBuf != nullptr, error = OT_ERROR_INVALID_ARGS);
981
982 decoder.Init(aBuf, aLen);
983
984 while (!decoder.IsAllReadInStruct())
985 {
986 const otIp6Address *addr;
987
988 SuccessOrExit(error = decoder.OpenStruct());
989 SuccessOrExit(error = decoder.ReadIp6Address(addr));
990 aAddressList.emplace_back(Ip6Address(*addr));
991 SuccessOrExit((error = decoder.CloseStruct()));
992 }
993
994 exit:
995 return error;
996 }
997
ParseIp6StreamNet(const uint8_t * aBuf,uint16_t aLen,const uint8_t * & aData,uint16_t & aDataLen)998 otError NcpSpinel::ParseIp6StreamNet(const uint8_t *aBuf, uint16_t aLen, const uint8_t *&aData, uint16_t &aDataLen)
999 {
1000 otError error = OT_ERROR_NONE;
1001 ot::Spinel::Decoder decoder;
1002
1003 VerifyOrExit(aBuf != nullptr, error = OT_ERROR_INVALID_ARGS);
1004
1005 decoder.Init(aBuf, aLen);
1006 error = decoder.ReadDataWithLen(aData, aDataLen);
1007
1008 exit:
1009 return error;
1010 }
1011
ParseOperationalDatasetTlvs(const uint8_t * aBuf,uint16_t aLen,otOperationalDatasetTlvs & aDatasetTlvs)1012 otError NcpSpinel::ParseOperationalDatasetTlvs(const uint8_t *aBuf,
1013 uint16_t aLen,
1014 otOperationalDatasetTlvs &aDatasetTlvs)
1015 {
1016 otError error = OT_ERROR_NONE;
1017 ot::Spinel::Decoder decoder;
1018 const uint8_t *datasetTlvsData;
1019 uint16_t datasetTlvsLen;
1020
1021 decoder.Init(aBuf, aLen);
1022 SuccessOrExit(error = decoder.ReadData(datasetTlvsData, datasetTlvsLen));
1023 VerifyOrExit(datasetTlvsLen <= sizeof(aDatasetTlvs.mTlvs), error = OT_ERROR_PARSE);
1024
1025 memcpy(aDatasetTlvs.mTlvs, datasetTlvsData, datasetTlvsLen);
1026 aDatasetTlvs.mLength = datasetTlvsLen;
1027
1028 exit:
1029 return error;
1030 }
1031
ParseInfraIfIcmp6Nd(const uint8_t * aBuf,uint8_t aLen,uint32_t & aInfraIfIndex,const otIp6Address * & aAddr,const uint8_t * & aData,uint16_t & aDataLen)1032 otError NcpSpinel::ParseInfraIfIcmp6Nd(const uint8_t *aBuf,
1033 uint8_t aLen,
1034 uint32_t &aInfraIfIndex,
1035 const otIp6Address *&aAddr,
1036 const uint8_t *&aData,
1037 uint16_t &aDataLen)
1038 {
1039 otError error = OT_ERROR_NONE;
1040 ot::Spinel::Decoder decoder;
1041
1042 VerifyOrExit(aBuf != nullptr, error = OT_ERROR_INVALID_ARGS);
1043
1044 decoder.Init(aBuf, aLen);
1045 SuccessOrExit(error = decoder.ReadUint32(aInfraIfIndex));
1046 SuccessOrExit(error = decoder.ReadIp6Address(aAddr));
1047 SuccessOrExit(error = decoder.ReadDataWithLen(aData, aDataLen));
1048
1049 exit:
1050 return error;
1051 }
1052
SendDnssdResult(otPlatDnssdRequestId aRequestId,const std::vector<uint8_t> & aCallbackData,otError aError)1053 otError NcpSpinel::SendDnssdResult(otPlatDnssdRequestId aRequestId,
1054 const std::vector<uint8_t> &aCallbackData,
1055 otError aError)
1056 {
1057 otError error;
1058 EncodingFunc encodingFunc = [aRequestId, &aCallbackData, aError](ot::Spinel::Encoder &aEncoder) {
1059 otError error = OT_ERROR_NONE;
1060
1061 SuccessOrExit(aEncoder.WriteUint8(aError));
1062 SuccessOrExit(aEncoder.WriteUint32(aRequestId));
1063 SuccessOrExit(aEncoder.WriteData(aCallbackData.data(), aCallbackData.size()));
1064
1065 exit:
1066 return error;
1067 };
1068
1069 error = SetProperty(SPINEL_PROP_DNSSD_REQUEST_RESULT, encodingFunc);
1070 if (error != OT_ERROR_NONE)
1071 {
1072 otbrLogWarning("Failed to SendDnssdResult, %s", otThreadErrorToString(error));
1073 }
1074
1075 return error;
1076 }
1077
SetInfraIf(uint32_t aInfraIfIndex,bool aIsRunning,const std::vector<Ip6Address> & aIp6Addresses)1078 otbrError NcpSpinel::SetInfraIf(uint32_t aInfraIfIndex, bool aIsRunning, const std::vector<Ip6Address> &aIp6Addresses)
1079 {
1080 otbrError error = OTBR_ERROR_NONE;
1081 EncodingFunc encodingFunc = [aInfraIfIndex, aIsRunning, &aIp6Addresses](ot::Spinel::Encoder &aEncoder) {
1082 otError error = OT_ERROR_NONE;
1083 SuccessOrExit(error = aEncoder.WriteUint32(aInfraIfIndex));
1084 SuccessOrExit(error = aEncoder.WriteBool(aIsRunning));
1085 for (const Ip6Address &addr : aIp6Addresses)
1086 {
1087 SuccessOrExit(error = aEncoder.WriteIp6Address(reinterpret_cast<const otIp6Address &>(addr)));
1088 }
1089
1090 exit:
1091 return error;
1092 };
1093
1094 SuccessOrExit(SetProperty(SPINEL_PROP_INFRA_IF_STATE, encodingFunc), error = OTBR_ERROR_OPENTHREAD);
1095
1096 exit:
1097 return error;
1098 }
1099
HandleIcmp6Nd(uint32_t aInfraIfIndex,const Ip6Address & aIp6Address,const uint8_t * aData,uint16_t aDataLen)1100 otbrError NcpSpinel::HandleIcmp6Nd(uint32_t aInfraIfIndex,
1101 const Ip6Address &aIp6Address,
1102 const uint8_t *aData,
1103 uint16_t aDataLen)
1104 {
1105 otbrError error = OTBR_ERROR_NONE;
1106 EncodingFunc encodingFunc = [aInfraIfIndex, &aIp6Address, aData, aDataLen](ot::Spinel::Encoder &aEncoder) {
1107 otError error = OT_ERROR_NONE;
1108 SuccessOrExit(error = aEncoder.WriteUint32(aInfraIfIndex));
1109 SuccessOrExit(error = aEncoder.WriteIp6Address(reinterpret_cast<const otIp6Address &>(aIp6Address)));
1110 SuccessOrExit(error = aEncoder.WriteData(aData, aDataLen));
1111 exit:
1112 return error;
1113 };
1114
1115 SuccessOrExit(SetProperty(SPINEL_PROP_INFRA_IF_RECV_ICMP6, encodingFunc), error = OTBR_ERROR_OPENTHREAD);
1116
1117 exit:
1118 if (error != OTBR_ERROR_NONE)
1119 {
1120 otbrLogWarning("Failed to passthrough ICMP6 ND to NCP, %s", otbrErrorString(error));
1121 }
1122 return error;
1123 }
1124
SpinelRoleToDeviceRole(spinel_net_role_t aRole)1125 otDeviceRole NcpSpinel::SpinelRoleToDeviceRole(spinel_net_role_t aRole)
1126 {
1127 otDeviceRole role = OT_DEVICE_ROLE_DISABLED;
1128
1129 switch (aRole)
1130 {
1131 case SPINEL_NET_ROLE_DISABLED:
1132 role = OT_DEVICE_ROLE_DISABLED;
1133 break;
1134 case SPINEL_NET_ROLE_DETACHED:
1135 role = OT_DEVICE_ROLE_DETACHED;
1136 break;
1137 case SPINEL_NET_ROLE_CHILD:
1138 role = OT_DEVICE_ROLE_CHILD;
1139 break;
1140 case SPINEL_NET_ROLE_ROUTER:
1141 role = OT_DEVICE_ROLE_ROUTER;
1142 break;
1143 case SPINEL_NET_ROLE_LEADER:
1144 role = OT_DEVICE_ROLE_LEADER;
1145 break;
1146 default:
1147 otbrLogWarning("Unsupported spinel net role: %u", aRole);
1148 break;
1149 }
1150
1151 return role;
1152 }
1153
1154 } // namespace Host
1155 } // namespace otbr
1156