• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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