xref: /aosp_15_r20/external/ot-br-posix/src/ncp/ncp_spinel.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
1*4a64e381SAndroid Build Coastguard Worker /*
2*4a64e381SAndroid Build Coastguard Worker  *  Copyright (c) 2024, The OpenThread Authors.
3*4a64e381SAndroid Build Coastguard Worker  *  All rights reserved.
4*4a64e381SAndroid Build Coastguard Worker  *
5*4a64e381SAndroid Build Coastguard Worker  *  Redistribution and use in source and binary forms, with or without
6*4a64e381SAndroid Build Coastguard Worker  *  modification, are permitted provided that the following conditions are met:
7*4a64e381SAndroid Build Coastguard Worker  *  1. Redistributions of source code must retain the above copyright
8*4a64e381SAndroid Build Coastguard Worker  *     notice, this list of conditions and the following disclaimer.
9*4a64e381SAndroid Build Coastguard Worker  *  2. Redistributions in binary form must reproduce the above copyright
10*4a64e381SAndroid Build Coastguard Worker  *     notice, this list of conditions and the following disclaimer in the
11*4a64e381SAndroid Build Coastguard Worker  *     documentation and/or other materials provided with the distribution.
12*4a64e381SAndroid Build Coastguard Worker  *  3. Neither the name of the copyright holder nor the
13*4a64e381SAndroid Build Coastguard Worker  *     names of its contributors may be used to endorse or promote products
14*4a64e381SAndroid Build Coastguard Worker  *     derived from this software without specific prior written permission.
15*4a64e381SAndroid Build Coastguard Worker  *
16*4a64e381SAndroid Build Coastguard Worker  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17*4a64e381SAndroid Build Coastguard Worker  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*4a64e381SAndroid Build Coastguard Worker  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*4a64e381SAndroid Build Coastguard Worker  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20*4a64e381SAndroid Build Coastguard Worker  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*4a64e381SAndroid Build Coastguard Worker  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*4a64e381SAndroid Build Coastguard Worker  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*4a64e381SAndroid Build Coastguard Worker  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*4a64e381SAndroid Build Coastguard Worker  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*4a64e381SAndroid Build Coastguard Worker  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*4a64e381SAndroid Build Coastguard Worker  *  POSSIBILITY OF SUCH DAMAGE.
27*4a64e381SAndroid Build Coastguard Worker  */
28*4a64e381SAndroid Build Coastguard Worker 
29*4a64e381SAndroid Build Coastguard Worker #define OTBR_LOG_TAG "NcpSpinel"
30*4a64e381SAndroid Build Coastguard Worker 
31*4a64e381SAndroid Build Coastguard Worker #include "ncp_spinel.hpp"
32*4a64e381SAndroid Build Coastguard Worker 
33*4a64e381SAndroid Build Coastguard Worker #include <stdarg.h>
34*4a64e381SAndroid Build Coastguard Worker 
35*4a64e381SAndroid Build Coastguard Worker #include <algorithm>
36*4a64e381SAndroid Build Coastguard Worker 
37*4a64e381SAndroid Build Coastguard Worker #include <openthread/dataset.h>
38*4a64e381SAndroid Build Coastguard Worker #include <openthread/thread.h>
39*4a64e381SAndroid Build Coastguard Worker 
40*4a64e381SAndroid Build Coastguard Worker #include "common/code_utils.hpp"
41*4a64e381SAndroid Build Coastguard Worker #include "common/logging.hpp"
42*4a64e381SAndroid Build Coastguard Worker #include "lib/spinel/spinel.h"
43*4a64e381SAndroid Build Coastguard Worker #include "lib/spinel/spinel_decoder.hpp"
44*4a64e381SAndroid Build Coastguard Worker #include "lib/spinel/spinel_driver.hpp"
45*4a64e381SAndroid Build Coastguard Worker #include "lib/spinel/spinel_helper.hpp"
46*4a64e381SAndroid Build Coastguard Worker 
47*4a64e381SAndroid Build Coastguard Worker namespace otbr {
48*4a64e381SAndroid Build Coastguard Worker namespace Ncp {
49*4a64e381SAndroid Build Coastguard Worker 
50*4a64e381SAndroid Build Coastguard Worker static constexpr char kSpinelDataUnpackFormat[] = "CiiD";
51*4a64e381SAndroid Build Coastguard Worker 
NcpSpinel(void)52*4a64e381SAndroid Build Coastguard Worker NcpSpinel::NcpSpinel(void)
53*4a64e381SAndroid Build Coastguard Worker     : mSpinelDriver(nullptr)
54*4a64e381SAndroid Build Coastguard Worker     , mCmdTidsInUse(0)
55*4a64e381SAndroid Build Coastguard Worker     , mCmdNextTid(1)
56*4a64e381SAndroid Build Coastguard Worker     , mNcpBuffer(mTxBuffer, kTxBufferSize)
57*4a64e381SAndroid Build Coastguard Worker     , mEncoder(mNcpBuffer)
58*4a64e381SAndroid Build Coastguard Worker     , mIid(SPINEL_HEADER_INVALID_IID)
59*4a64e381SAndroid Build Coastguard Worker     , mPropsObserver(nullptr)
60*4a64e381SAndroid Build Coastguard Worker {
61*4a64e381SAndroid Build Coastguard Worker     std::fill_n(mWaitingKeyTable, SPINEL_PROP_LAST_STATUS, sizeof(mWaitingKeyTable));
62*4a64e381SAndroid Build Coastguard Worker     memset(mCmdTable, 0, sizeof(mCmdTable));
63*4a64e381SAndroid Build Coastguard Worker }
64*4a64e381SAndroid Build Coastguard Worker 
Init(ot::Spinel::SpinelDriver & aSpinelDriver,PropsObserver & aObserver)65*4a64e381SAndroid Build Coastguard Worker void NcpSpinel::Init(ot::Spinel::SpinelDriver &aSpinelDriver, PropsObserver &aObserver)
66*4a64e381SAndroid Build Coastguard Worker {
67*4a64e381SAndroid Build Coastguard Worker     mSpinelDriver  = &aSpinelDriver;
68*4a64e381SAndroid Build Coastguard Worker     mPropsObserver = &aObserver;
69*4a64e381SAndroid Build Coastguard Worker     mIid           = mSpinelDriver->GetIid();
70*4a64e381SAndroid Build Coastguard Worker     mSpinelDriver->SetFrameHandler(&HandleReceivedFrame, &HandleSavedFrame, this);
71*4a64e381SAndroid Build Coastguard Worker }
72*4a64e381SAndroid Build Coastguard Worker 
Deinit(void)73*4a64e381SAndroid Build Coastguard Worker void NcpSpinel::Deinit(void)
74*4a64e381SAndroid Build Coastguard Worker {
75*4a64e381SAndroid Build Coastguard Worker     mSpinelDriver              = nullptr;
76*4a64e381SAndroid Build Coastguard Worker     mIp6AddressTableCallback   = nullptr;
77*4a64e381SAndroid Build Coastguard Worker     mNetifStateChangedCallback = nullptr;
78*4a64e381SAndroid Build Coastguard Worker }
79*4a64e381SAndroid Build Coastguard Worker 
SpinelDataUnpack(const uint8_t * aDataIn,spinel_size_t aDataLen,const char * aPackFormat,...)80*4a64e381SAndroid Build Coastguard Worker otbrError NcpSpinel::SpinelDataUnpack(const uint8_t *aDataIn, spinel_size_t aDataLen, const char *aPackFormat, ...)
81*4a64e381SAndroid Build Coastguard Worker {
82*4a64e381SAndroid Build Coastguard Worker     otbrError      error = OTBR_ERROR_NONE;
83*4a64e381SAndroid Build Coastguard Worker     spinel_ssize_t unpacked;
84*4a64e381SAndroid Build Coastguard Worker     va_list        args;
85*4a64e381SAndroid Build Coastguard Worker 
86*4a64e381SAndroid Build Coastguard Worker     va_start(args, aPackFormat);
87*4a64e381SAndroid Build Coastguard Worker     unpacked = spinel_datatype_vunpack(aDataIn, aDataLen, aPackFormat, args);
88*4a64e381SAndroid Build Coastguard Worker     va_end(args);
89*4a64e381SAndroid Build Coastguard Worker 
90*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(unpacked > 0, error = OTBR_ERROR_PARSE);
91*4a64e381SAndroid Build Coastguard Worker 
92*4a64e381SAndroid Build Coastguard Worker exit:
93*4a64e381SAndroid Build Coastguard Worker     return error;
94*4a64e381SAndroid Build Coastguard Worker }
95*4a64e381SAndroid Build Coastguard Worker 
DatasetSetActiveTlvs(const otOperationalDatasetTlvs & aActiveOpDatasetTlvs,AsyncTaskPtr aAsyncTask)96*4a64e381SAndroid Build Coastguard Worker void NcpSpinel::DatasetSetActiveTlvs(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs, AsyncTaskPtr aAsyncTask)
97*4a64e381SAndroid Build Coastguard Worker {
98*4a64e381SAndroid Build Coastguard Worker     otError      error        = OT_ERROR_NONE;
99*4a64e381SAndroid Build Coastguard Worker     EncodingFunc encodingFunc = [this, &aActiveOpDatasetTlvs] {
100*4a64e381SAndroid Build Coastguard Worker         return mEncoder.WriteData(aActiveOpDatasetTlvs.mTlvs, aActiveOpDatasetTlvs.mLength);
101*4a64e381SAndroid Build Coastguard Worker     };
102*4a64e381SAndroid Build Coastguard Worker 
103*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mDatasetSetActiveTask == nullptr, error = OT_ERROR_BUSY);
104*4a64e381SAndroid Build Coastguard Worker 
105*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = SetProperty(SPINEL_PROP_THREAD_ACTIVE_DATASET_TLVS, encodingFunc));
106*4a64e381SAndroid Build Coastguard Worker     mDatasetSetActiveTask = aAsyncTask;
107*4a64e381SAndroid Build Coastguard Worker 
108*4a64e381SAndroid Build Coastguard Worker exit:
109*4a64e381SAndroid Build Coastguard Worker     if (error != OT_ERROR_NONE)
110*4a64e381SAndroid Build Coastguard Worker     {
111*4a64e381SAndroid Build Coastguard Worker         mTaskRunner.Post([aAsyncTask, error](void) { aAsyncTask->SetResult(error, "Failed to set active dataset!"); });
112*4a64e381SAndroid Build Coastguard Worker     }
113*4a64e381SAndroid Build Coastguard Worker }
114*4a64e381SAndroid Build Coastguard Worker 
DatasetMgmtSetPending(std::shared_ptr<otOperationalDatasetTlvs> aPendingOpDatasetTlvsPtr,AsyncTaskPtr aAsyncTask)115*4a64e381SAndroid Build Coastguard Worker void NcpSpinel::DatasetMgmtSetPending(std::shared_ptr<otOperationalDatasetTlvs> aPendingOpDatasetTlvsPtr,
116*4a64e381SAndroid Build Coastguard Worker                                       AsyncTaskPtr                              aAsyncTask)
117*4a64e381SAndroid Build Coastguard Worker {
118*4a64e381SAndroid Build Coastguard Worker     otError      error        = OT_ERROR_NONE;
119*4a64e381SAndroid Build Coastguard Worker     EncodingFunc encodingFunc = [this, aPendingOpDatasetTlvsPtr] {
120*4a64e381SAndroid Build Coastguard Worker         return mEncoder.WriteData(aPendingOpDatasetTlvsPtr->mTlvs, aPendingOpDatasetTlvsPtr->mLength);
121*4a64e381SAndroid Build Coastguard Worker     };
122*4a64e381SAndroid Build Coastguard Worker 
123*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mDatasetMgmtSetPendingTask == nullptr, error = OT_ERROR_BUSY);
124*4a64e381SAndroid Build Coastguard Worker 
125*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = SetProperty(SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS, encodingFunc));
126*4a64e381SAndroid Build Coastguard Worker     mDatasetMgmtSetPendingTask = aAsyncTask;
127*4a64e381SAndroid Build Coastguard Worker 
128*4a64e381SAndroid Build Coastguard Worker exit:
129*4a64e381SAndroid Build Coastguard Worker     if (error != OT_ERROR_NONE)
130*4a64e381SAndroid Build Coastguard Worker     {
131*4a64e381SAndroid Build Coastguard Worker         mTaskRunner.Post([aAsyncTask, error] { aAsyncTask->SetResult(error, "Failed to set pending dataset!"); });
132*4a64e381SAndroid Build Coastguard Worker     }
133*4a64e381SAndroid Build Coastguard Worker }
134*4a64e381SAndroid Build Coastguard Worker 
Ip6SetEnabled(bool aEnable,AsyncTaskPtr aAsyncTask)135*4a64e381SAndroid Build Coastguard Worker void NcpSpinel::Ip6SetEnabled(bool aEnable, AsyncTaskPtr aAsyncTask)
136*4a64e381SAndroid Build Coastguard Worker {
137*4a64e381SAndroid Build Coastguard Worker     otError      error        = OT_ERROR_NONE;
138*4a64e381SAndroid Build Coastguard Worker     EncodingFunc encodingFunc = [this, aEnable] { return mEncoder.WriteBool(aEnable); };
139*4a64e381SAndroid Build Coastguard Worker 
140*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mIp6SetEnabledTask == nullptr, error = OT_ERROR_BUSY);
141*4a64e381SAndroid Build Coastguard Worker 
142*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = SetProperty(SPINEL_PROP_NET_IF_UP, encodingFunc));
143*4a64e381SAndroid Build Coastguard Worker     mIp6SetEnabledTask = aAsyncTask;
144*4a64e381SAndroid Build Coastguard Worker 
145*4a64e381SAndroid Build Coastguard Worker exit:
146*4a64e381SAndroid Build Coastguard Worker     if (error != OT_ERROR_NONE)
147*4a64e381SAndroid Build Coastguard Worker     {
148*4a64e381SAndroid Build Coastguard Worker         mTaskRunner.Post(
149*4a64e381SAndroid Build Coastguard Worker             [aAsyncTask, error](void) { aAsyncTask->SetResult(error, "Failed to enable the network interface!"); });
150*4a64e381SAndroid Build Coastguard Worker     }
151*4a64e381SAndroid Build Coastguard Worker     return;
152*4a64e381SAndroid Build Coastguard Worker }
153*4a64e381SAndroid Build Coastguard Worker 
Ip6Send(const uint8_t * aData,uint16_t aLength)154*4a64e381SAndroid Build Coastguard Worker otbrError NcpSpinel::Ip6Send(const uint8_t *aData, uint16_t aLength)
155*4a64e381SAndroid Build Coastguard Worker {
156*4a64e381SAndroid Build Coastguard Worker     // TODO: Impelement this function.
157*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aData);
158*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aLength);
159*4a64e381SAndroid Build Coastguard Worker 
160*4a64e381SAndroid Build Coastguard Worker     return OTBR_ERROR_NONE;
161*4a64e381SAndroid Build Coastguard Worker }
162*4a64e381SAndroid Build Coastguard Worker 
ThreadSetEnabled(bool aEnable,AsyncTaskPtr aAsyncTask)163*4a64e381SAndroid Build Coastguard Worker void NcpSpinel::ThreadSetEnabled(bool aEnable, AsyncTaskPtr aAsyncTask)
164*4a64e381SAndroid Build Coastguard Worker {
165*4a64e381SAndroid Build Coastguard Worker     otError      error        = OT_ERROR_NONE;
166*4a64e381SAndroid Build Coastguard Worker     EncodingFunc encodingFunc = [this, aEnable] { return mEncoder.WriteBool(aEnable); };
167*4a64e381SAndroid Build Coastguard Worker 
168*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mThreadSetEnabledTask == nullptr, error = OT_ERROR_BUSY);
169*4a64e381SAndroid Build Coastguard Worker 
170*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = SetProperty(SPINEL_PROP_NET_STACK_UP, encodingFunc));
171*4a64e381SAndroid Build Coastguard Worker     mThreadSetEnabledTask = aAsyncTask;
172*4a64e381SAndroid Build Coastguard Worker 
173*4a64e381SAndroid Build Coastguard Worker exit:
174*4a64e381SAndroid Build Coastguard Worker     if (error != OT_ERROR_NONE)
175*4a64e381SAndroid Build Coastguard Worker     {
176*4a64e381SAndroid Build Coastguard Worker         mTaskRunner.Post(
177*4a64e381SAndroid Build Coastguard Worker             [aAsyncTask, error](void) { aAsyncTask->SetResult(error, "Failed to enable the Thread network!"); });
178*4a64e381SAndroid Build Coastguard Worker     }
179*4a64e381SAndroid Build Coastguard Worker     return;
180*4a64e381SAndroid Build Coastguard Worker }
181*4a64e381SAndroid Build Coastguard Worker 
ThreadDetachGracefully(AsyncTaskPtr aAsyncTask)182*4a64e381SAndroid Build Coastguard Worker void NcpSpinel::ThreadDetachGracefully(AsyncTaskPtr aAsyncTask)
183*4a64e381SAndroid Build Coastguard Worker {
184*4a64e381SAndroid Build Coastguard Worker     otError      error        = OT_ERROR_NONE;
185*4a64e381SAndroid Build Coastguard Worker     EncodingFunc encodingFunc = [] { return OT_ERROR_NONE; };
186*4a64e381SAndroid Build Coastguard Worker 
187*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mThreadDetachGracefullyTask == nullptr, error = OT_ERROR_BUSY);
188*4a64e381SAndroid Build Coastguard Worker 
189*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = SetProperty(SPINEL_PROP_NET_LEAVE_GRACEFULLY, encodingFunc));
190*4a64e381SAndroid Build Coastguard Worker     mThreadDetachGracefullyTask = aAsyncTask;
191*4a64e381SAndroid Build Coastguard Worker 
192*4a64e381SAndroid Build Coastguard Worker exit:
193*4a64e381SAndroid Build Coastguard Worker     if (error != OT_ERROR_NONE)
194*4a64e381SAndroid Build Coastguard Worker     {
195*4a64e381SAndroid Build Coastguard Worker         mTaskRunner.Post([aAsyncTask, error](void) { aAsyncTask->SetResult(error, "Failed to detach gracefully!"); });
196*4a64e381SAndroid Build Coastguard Worker     }
197*4a64e381SAndroid Build Coastguard Worker     return;
198*4a64e381SAndroid Build Coastguard Worker }
199*4a64e381SAndroid Build Coastguard Worker 
ThreadErasePersistentInfo(AsyncTaskPtr aAsyncTask)200*4a64e381SAndroid Build Coastguard Worker void NcpSpinel::ThreadErasePersistentInfo(AsyncTaskPtr aAsyncTask)
201*4a64e381SAndroid Build Coastguard Worker {
202*4a64e381SAndroid Build Coastguard Worker     otError      error = OT_ERROR_NONE;
203*4a64e381SAndroid Build Coastguard Worker     spinel_tid_t tid   = GetNextTid();
204*4a64e381SAndroid Build Coastguard Worker 
205*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mThreadErasePersistentInfoTask == nullptr, error = OT_ERROR_BUSY);
206*4a64e381SAndroid Build Coastguard Worker 
207*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = mSpinelDriver->SendCommand(SPINEL_CMD_NET_CLEAR, SPINEL_PROP_LAST_STATUS, tid));
208*4a64e381SAndroid Build Coastguard Worker 
209*4a64e381SAndroid Build Coastguard Worker     mWaitingKeyTable[tid]          = SPINEL_PROP_LAST_STATUS;
210*4a64e381SAndroid Build Coastguard Worker     mCmdTable[tid]                 = SPINEL_CMD_NET_CLEAR;
211*4a64e381SAndroid Build Coastguard Worker     mThreadErasePersistentInfoTask = aAsyncTask;
212*4a64e381SAndroid Build Coastguard Worker 
213*4a64e381SAndroid Build Coastguard Worker exit:
214*4a64e381SAndroid Build Coastguard Worker     if (error != OT_ERROR_NONE)
215*4a64e381SAndroid Build Coastguard Worker     {
216*4a64e381SAndroid Build Coastguard Worker         FreeTidTableItem(tid);
217*4a64e381SAndroid Build Coastguard Worker         mTaskRunner.Post(
218*4a64e381SAndroid Build Coastguard Worker             [aAsyncTask, error](void) { aAsyncTask->SetResult(error, "Failed to erase persistent info!"); });
219*4a64e381SAndroid Build Coastguard Worker     }
220*4a64e381SAndroid Build Coastguard Worker }
221*4a64e381SAndroid Build Coastguard Worker 
HandleReceivedFrame(const uint8_t * aFrame,uint16_t aLength,uint8_t aHeader,bool & aSave,void * aContext)222*4a64e381SAndroid Build Coastguard Worker void NcpSpinel::HandleReceivedFrame(const uint8_t *aFrame,
223*4a64e381SAndroid Build Coastguard Worker                                     uint16_t       aLength,
224*4a64e381SAndroid Build Coastguard Worker                                     uint8_t        aHeader,
225*4a64e381SAndroid Build Coastguard Worker                                     bool          &aSave,
226*4a64e381SAndroid Build Coastguard Worker                                     void          *aContext)
227*4a64e381SAndroid Build Coastguard Worker {
228*4a64e381SAndroid Build Coastguard Worker     static_cast<NcpSpinel *>(aContext)->HandleReceivedFrame(aFrame, aLength, aHeader, aSave);
229*4a64e381SAndroid Build Coastguard Worker }
230*4a64e381SAndroid Build Coastguard Worker 
HandleReceivedFrame(const uint8_t * aFrame,uint16_t aLength,uint8_t aHeader,bool & aShouldSaveFrame)231*4a64e381SAndroid Build Coastguard Worker void NcpSpinel::HandleReceivedFrame(const uint8_t *aFrame, uint16_t aLength, uint8_t aHeader, bool &aShouldSaveFrame)
232*4a64e381SAndroid Build Coastguard Worker {
233*4a64e381SAndroid Build Coastguard Worker     spinel_tid_t tid = SPINEL_HEADER_GET_TID(aHeader);
234*4a64e381SAndroid Build Coastguard Worker 
235*4a64e381SAndroid Build Coastguard Worker     if (tid == 0)
236*4a64e381SAndroid Build Coastguard Worker     {
237*4a64e381SAndroid Build Coastguard Worker         HandleNotification(aFrame, aLength);
238*4a64e381SAndroid Build Coastguard Worker     }
239*4a64e381SAndroid Build Coastguard Worker     else if (tid < kMaxTids)
240*4a64e381SAndroid Build Coastguard Worker     {
241*4a64e381SAndroid Build Coastguard Worker         HandleResponse(tid, aFrame, aLength);
242*4a64e381SAndroid Build Coastguard Worker     }
243*4a64e381SAndroid Build Coastguard Worker     else
244*4a64e381SAndroid Build Coastguard Worker     {
245*4a64e381SAndroid Build Coastguard Worker         otbrLogCrit("Received unexpected tid: %u", tid);
246*4a64e381SAndroid Build Coastguard Worker     }
247*4a64e381SAndroid Build Coastguard Worker 
248*4a64e381SAndroid Build Coastguard Worker     aShouldSaveFrame = false;
249*4a64e381SAndroid Build Coastguard Worker }
250*4a64e381SAndroid Build Coastguard Worker 
HandleSavedFrame(const uint8_t * aFrame,uint16_t aLength,void * aContext)251*4a64e381SAndroid Build Coastguard Worker void NcpSpinel::HandleSavedFrame(const uint8_t *aFrame, uint16_t aLength, void *aContext)
252*4a64e381SAndroid Build Coastguard Worker {
253*4a64e381SAndroid Build Coastguard Worker     /* Intentionally Empty */
254*4a64e381SAndroid Build Coastguard Worker     OT_UNUSED_VARIABLE(aFrame);
255*4a64e381SAndroid Build Coastguard Worker     OT_UNUSED_VARIABLE(aLength);
256*4a64e381SAndroid Build Coastguard Worker     OT_UNUSED_VARIABLE(aContext);
257*4a64e381SAndroid Build Coastguard Worker }
258*4a64e381SAndroid Build Coastguard Worker 
HandleNotification(const uint8_t * aFrame,uint16_t aLength)259*4a64e381SAndroid Build Coastguard Worker void NcpSpinel::HandleNotification(const uint8_t *aFrame, uint16_t aLength)
260*4a64e381SAndroid Build Coastguard Worker {
261*4a64e381SAndroid Build Coastguard Worker     spinel_prop_key_t key;
262*4a64e381SAndroid Build Coastguard Worker     spinel_size_t     len  = 0;
263*4a64e381SAndroid Build Coastguard Worker     uint8_t          *data = nullptr;
264*4a64e381SAndroid Build Coastguard Worker     uint32_t          cmd;
265*4a64e381SAndroid Build Coastguard Worker     uint8_t           header;
266*4a64e381SAndroid Build Coastguard Worker     otbrError         error = OTBR_ERROR_NONE;
267*4a64e381SAndroid Build Coastguard Worker 
268*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = SpinelDataUnpack(aFrame, aLength, kSpinelDataUnpackFormat, &header, &cmd, &key, &data, &len));
269*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(SPINEL_HEADER_GET_TID(header) == 0, error = OTBR_ERROR_PARSE);
270*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(cmd == SPINEL_CMD_PROP_VALUE_IS);
271*4a64e381SAndroid Build Coastguard Worker     HandleValueIs(key, data, static_cast<uint16_t>(len));
272*4a64e381SAndroid Build Coastguard Worker 
273*4a64e381SAndroid Build Coastguard Worker exit:
274*4a64e381SAndroid Build Coastguard Worker     otbrLogResult(error, "HandleNotification: %s", __FUNCTION__);
275*4a64e381SAndroid Build Coastguard Worker }
276*4a64e381SAndroid Build Coastguard Worker 
HandleResponse(spinel_tid_t aTid,const uint8_t * aFrame,uint16_t aLength)277*4a64e381SAndroid Build Coastguard Worker void NcpSpinel::HandleResponse(spinel_tid_t aTid, const uint8_t *aFrame, uint16_t aLength)
278*4a64e381SAndroid Build Coastguard Worker {
279*4a64e381SAndroid Build Coastguard Worker     spinel_prop_key_t key;
280*4a64e381SAndroid Build Coastguard Worker     spinel_size_t     len  = 0;
281*4a64e381SAndroid Build Coastguard Worker     uint8_t          *data = nullptr;
282*4a64e381SAndroid Build Coastguard Worker     uint32_t          cmd;
283*4a64e381SAndroid Build Coastguard Worker     uint8_t           header;
284*4a64e381SAndroid Build Coastguard Worker     otbrError         error          = OTBR_ERROR_NONE;
285*4a64e381SAndroid Build Coastguard Worker     FailureHandler    failureHandler = nullptr;
286*4a64e381SAndroid Build Coastguard Worker 
287*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = SpinelDataUnpack(aFrame, aLength, kSpinelDataUnpackFormat, &header, &cmd, &key, &data, &len));
288*4a64e381SAndroid Build Coastguard Worker 
289*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(cmd == SPINEL_CMD_PROP_VALUE_IS, error = OTBR_ERROR_INVALID_STATE);
290*4a64e381SAndroid Build Coastguard Worker 
291*4a64e381SAndroid Build Coastguard Worker     switch (mCmdTable[aTid])
292*4a64e381SAndroid Build Coastguard Worker     {
293*4a64e381SAndroid Build Coastguard Worker     case SPINEL_CMD_PROP_VALUE_SET:
294*4a64e381SAndroid Build Coastguard Worker     {
295*4a64e381SAndroid Build Coastguard Worker         error = HandleResponseForPropSet(aTid, key, data, len);
296*4a64e381SAndroid Build Coastguard Worker         break;
297*4a64e381SAndroid Build Coastguard Worker     }
298*4a64e381SAndroid Build Coastguard Worker     case SPINEL_CMD_NET_CLEAR:
299*4a64e381SAndroid Build Coastguard Worker     {
300*4a64e381SAndroid Build Coastguard Worker         spinel_status_t status = SPINEL_STATUS_OK;
301*4a64e381SAndroid Build Coastguard Worker 
302*4a64e381SAndroid Build Coastguard Worker         SuccessOrExit(error = SpinelDataUnpack(data, len, SPINEL_DATATYPE_UINT_PACKED_S, &status));
303*4a64e381SAndroid Build Coastguard Worker         CallAndClear(mThreadErasePersistentInfoTask, ot::Spinel::SpinelStatusToOtError(status));
304*4a64e381SAndroid Build Coastguard Worker         break;
305*4a64e381SAndroid Build Coastguard Worker     }
306*4a64e381SAndroid Build Coastguard Worker     default:
307*4a64e381SAndroid Build Coastguard Worker         break;
308*4a64e381SAndroid Build Coastguard Worker     }
309*4a64e381SAndroid Build Coastguard Worker 
310*4a64e381SAndroid Build Coastguard Worker exit:
311*4a64e381SAndroid Build Coastguard Worker     if (error == OTBR_ERROR_INVALID_STATE)
312*4a64e381SAndroid Build Coastguard Worker     {
313*4a64e381SAndroid Build Coastguard Worker         otbrLogCrit("Received unexpected response with (cmd:%u, key:%u), waiting (cmd:%u, key:%u) for tid:%u", cmd, key,
314*4a64e381SAndroid Build Coastguard Worker                     mCmdTable[aTid], mWaitingKeyTable[aTid], aTid);
315*4a64e381SAndroid Build Coastguard Worker     }
316*4a64e381SAndroid Build Coastguard Worker     else if (error == OTBR_ERROR_PARSE)
317*4a64e381SAndroid Build Coastguard Worker     {
318*4a64e381SAndroid Build Coastguard Worker         otbrLogCrit("Error parsing response with tid:%u", aTid);
319*4a64e381SAndroid Build Coastguard Worker     }
320*4a64e381SAndroid Build Coastguard Worker     FreeTidTableItem(aTid);
321*4a64e381SAndroid Build Coastguard Worker }
322*4a64e381SAndroid Build Coastguard Worker 
HandleValueIs(spinel_prop_key_t aKey,const uint8_t * aBuffer,uint16_t aLength)323*4a64e381SAndroid Build Coastguard Worker void NcpSpinel::HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength)
324*4a64e381SAndroid Build Coastguard Worker {
325*4a64e381SAndroid Build Coastguard Worker     otbrError error = OTBR_ERROR_NONE;
326*4a64e381SAndroid Build Coastguard Worker 
327*4a64e381SAndroid Build Coastguard Worker     switch (aKey)
328*4a64e381SAndroid Build Coastguard Worker     {
329*4a64e381SAndroid Build Coastguard Worker     case SPINEL_PROP_LAST_STATUS:
330*4a64e381SAndroid Build Coastguard Worker     {
331*4a64e381SAndroid Build Coastguard Worker         spinel_status_t status = SPINEL_STATUS_OK;
332*4a64e381SAndroid Build Coastguard Worker 
333*4a64e381SAndroid Build Coastguard Worker         SuccessOrExit(error = SpinelDataUnpack(aBuffer, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status));
334*4a64e381SAndroid Build Coastguard Worker 
335*4a64e381SAndroid Build Coastguard Worker         otbrLogInfo("NCP last status: %s", spinel_status_to_cstr(status));
336*4a64e381SAndroid Build Coastguard Worker         break;
337*4a64e381SAndroid Build Coastguard Worker     }
338*4a64e381SAndroid Build Coastguard Worker 
339*4a64e381SAndroid Build Coastguard Worker     case SPINEL_PROP_NET_ROLE:
340*4a64e381SAndroid Build Coastguard Worker     {
341*4a64e381SAndroid Build Coastguard Worker         spinel_net_role_t role = SPINEL_NET_ROLE_DISABLED;
342*4a64e381SAndroid Build Coastguard Worker         otDeviceRole      deviceRole;
343*4a64e381SAndroid Build Coastguard Worker 
344*4a64e381SAndroid Build Coastguard Worker         SuccessOrExit(error = SpinelDataUnpack(aBuffer, aLength, SPINEL_DATATYPE_UINT8_S, &role));
345*4a64e381SAndroid Build Coastguard Worker 
346*4a64e381SAndroid Build Coastguard Worker         deviceRole = SpinelRoleToDeviceRole(role);
347*4a64e381SAndroid Build Coastguard Worker         mPropsObserver->SetDeviceRole(deviceRole);
348*4a64e381SAndroid Build Coastguard Worker 
349*4a64e381SAndroid Build Coastguard Worker         otbrLogInfo("Device role changed to %s", otThreadDeviceRoleToString(deviceRole));
350*4a64e381SAndroid Build Coastguard Worker         break;
351*4a64e381SAndroid Build Coastguard Worker     }
352*4a64e381SAndroid Build Coastguard Worker 
353*4a64e381SAndroid Build Coastguard Worker     case SPINEL_PROP_NET_LEAVE_GRACEFULLY:
354*4a64e381SAndroid Build Coastguard Worker     {
355*4a64e381SAndroid Build Coastguard Worker         CallAndClear(mThreadDetachGracefullyTask, OT_ERROR_NONE);
356*4a64e381SAndroid Build Coastguard Worker         break;
357*4a64e381SAndroid Build Coastguard Worker     }
358*4a64e381SAndroid Build Coastguard Worker 
359*4a64e381SAndroid Build Coastguard Worker     case SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS:
360*4a64e381SAndroid Build Coastguard Worker     {
361*4a64e381SAndroid Build Coastguard Worker         spinel_status_t status = SPINEL_STATUS_OK;
362*4a64e381SAndroid Build Coastguard Worker 
363*4a64e381SAndroid Build Coastguard Worker         SuccessOrExit(error = SpinelDataUnpack(aBuffer, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status));
364*4a64e381SAndroid Build Coastguard Worker         CallAndClear(mDatasetMgmtSetPendingTask, ot::Spinel::SpinelStatusToOtError(status));
365*4a64e381SAndroid Build Coastguard Worker         break;
366*4a64e381SAndroid Build Coastguard Worker     }
367*4a64e381SAndroid Build Coastguard Worker 
368*4a64e381SAndroid Build Coastguard Worker     case SPINEL_PROP_IPV6_ADDRESS_TABLE:
369*4a64e381SAndroid Build Coastguard Worker     {
370*4a64e381SAndroid Build Coastguard Worker         std::vector<Ip6AddressInfo> addressInfoTable;
371*4a64e381SAndroid Build Coastguard Worker 
372*4a64e381SAndroid Build Coastguard Worker         VerifyOrExit(ParseIp6AddressTable(aBuffer, aLength, addressInfoTable) == OT_ERROR_NONE,
373*4a64e381SAndroid Build Coastguard Worker                      error = OTBR_ERROR_PARSE);
374*4a64e381SAndroid Build Coastguard Worker         SafeInvoke(mIp6AddressTableCallback, addressInfoTable);
375*4a64e381SAndroid Build Coastguard Worker         break;
376*4a64e381SAndroid Build Coastguard Worker     }
377*4a64e381SAndroid Build Coastguard Worker 
378*4a64e381SAndroid Build Coastguard Worker     case SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE:
379*4a64e381SAndroid Build Coastguard Worker     {
380*4a64e381SAndroid Build Coastguard Worker         std::vector<Ip6Address> addressTable;
381*4a64e381SAndroid Build Coastguard Worker 
382*4a64e381SAndroid Build Coastguard Worker         VerifyOrExit(ParseIp6MulticastAddresses(aBuffer, aLength, addressTable) == OT_ERROR_NONE,
383*4a64e381SAndroid Build Coastguard Worker                      error = OTBR_ERROR_PARSE);
384*4a64e381SAndroid Build Coastguard Worker         SafeInvoke(mIp6MulticastAddressTableCallback, addressTable);
385*4a64e381SAndroid Build Coastguard Worker         break;
386*4a64e381SAndroid Build Coastguard Worker     }
387*4a64e381SAndroid Build Coastguard Worker 
388*4a64e381SAndroid Build Coastguard Worker     case SPINEL_PROP_NET_IF_UP:
389*4a64e381SAndroid Build Coastguard Worker     {
390*4a64e381SAndroid Build Coastguard Worker         bool isUp;
391*4a64e381SAndroid Build Coastguard Worker         SuccessOrExit(error = SpinelDataUnpack(aBuffer, aLength, SPINEL_DATATYPE_BOOL_S, &isUp));
392*4a64e381SAndroid Build Coastguard Worker         SafeInvoke(mNetifStateChangedCallback, isUp);
393*4a64e381SAndroid Build Coastguard Worker         break;
394*4a64e381SAndroid Build Coastguard Worker     }
395*4a64e381SAndroid Build Coastguard Worker 
396*4a64e381SAndroid Build Coastguard Worker     default:
397*4a64e381SAndroid Build Coastguard Worker         otbrLogWarning("Received uncognized key: %u", aKey);
398*4a64e381SAndroid Build Coastguard Worker         break;
399*4a64e381SAndroid Build Coastguard Worker     }
400*4a64e381SAndroid Build Coastguard Worker 
401*4a64e381SAndroid Build Coastguard Worker exit:
402*4a64e381SAndroid Build Coastguard Worker     otbrLogResult(error, "NcpSpinel: %s", __FUNCTION__);
403*4a64e381SAndroid Build Coastguard Worker     return;
404*4a64e381SAndroid Build Coastguard Worker }
405*4a64e381SAndroid Build Coastguard Worker 
HandleResponseForPropSet(spinel_tid_t aTid,spinel_prop_key_t aKey,const uint8_t * aData,uint16_t aLength)406*4a64e381SAndroid Build Coastguard Worker otbrError NcpSpinel::HandleResponseForPropSet(spinel_tid_t      aTid,
407*4a64e381SAndroid Build Coastguard Worker                                               spinel_prop_key_t aKey,
408*4a64e381SAndroid Build Coastguard Worker                                               const uint8_t    *aData,
409*4a64e381SAndroid Build Coastguard Worker                                               uint16_t          aLength)
410*4a64e381SAndroid Build Coastguard Worker {
411*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aData);
412*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aLength);
413*4a64e381SAndroid Build Coastguard Worker 
414*4a64e381SAndroid Build Coastguard Worker     otbrError error = OTBR_ERROR_NONE;
415*4a64e381SAndroid Build Coastguard Worker 
416*4a64e381SAndroid Build Coastguard Worker     switch (mWaitingKeyTable[aTid])
417*4a64e381SAndroid Build Coastguard Worker     {
418*4a64e381SAndroid Build Coastguard Worker     case SPINEL_PROP_THREAD_ACTIVE_DATASET_TLVS:
419*4a64e381SAndroid Build Coastguard Worker         VerifyOrExit(aKey == SPINEL_PROP_THREAD_ACTIVE_DATASET_TLVS, error = OTBR_ERROR_INVALID_STATE);
420*4a64e381SAndroid Build Coastguard Worker         CallAndClear(mDatasetSetActiveTask, OT_ERROR_NONE);
421*4a64e381SAndroid Build Coastguard Worker         {
422*4a64e381SAndroid Build Coastguard Worker             otOperationalDatasetTlvs datasetTlvs;
423*4a64e381SAndroid Build Coastguard Worker             VerifyOrExit(ParseOperationalDatasetTlvs(aData, aLength, datasetTlvs) == OT_ERROR_NONE,
424*4a64e381SAndroid Build Coastguard Worker                          error = OTBR_ERROR_PARSE);
425*4a64e381SAndroid Build Coastguard Worker             mPropsObserver->SetDatasetActiveTlvs(datasetTlvs);
426*4a64e381SAndroid Build Coastguard Worker         }
427*4a64e381SAndroid Build Coastguard Worker         break;
428*4a64e381SAndroid Build Coastguard Worker 
429*4a64e381SAndroid Build Coastguard Worker     case SPINEL_PROP_NET_IF_UP:
430*4a64e381SAndroid Build Coastguard Worker         VerifyOrExit(aKey == SPINEL_PROP_NET_IF_UP, error = OTBR_ERROR_INVALID_STATE);
431*4a64e381SAndroid Build Coastguard Worker         CallAndClear(mIp6SetEnabledTask, OT_ERROR_NONE);
432*4a64e381SAndroid Build Coastguard Worker         {
433*4a64e381SAndroid Build Coastguard Worker             bool isUp;
434*4a64e381SAndroid Build Coastguard Worker             SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_BOOL_S, &isUp));
435*4a64e381SAndroid Build Coastguard Worker             SafeInvoke(mNetifStateChangedCallback, isUp);
436*4a64e381SAndroid Build Coastguard Worker         }
437*4a64e381SAndroid Build Coastguard Worker         break;
438*4a64e381SAndroid Build Coastguard Worker 
439*4a64e381SAndroid Build Coastguard Worker     case SPINEL_PROP_NET_STACK_UP:
440*4a64e381SAndroid Build Coastguard Worker         VerifyOrExit(aKey == SPINEL_PROP_NET_STACK_UP, error = OTBR_ERROR_INVALID_STATE);
441*4a64e381SAndroid Build Coastguard Worker         CallAndClear(mThreadSetEnabledTask, OT_ERROR_NONE);
442*4a64e381SAndroid Build Coastguard Worker         break;
443*4a64e381SAndroid Build Coastguard Worker 
444*4a64e381SAndroid Build Coastguard Worker     case SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS:
445*4a64e381SAndroid Build Coastguard Worker         if (aKey == SPINEL_PROP_LAST_STATUS)
446*4a64e381SAndroid Build Coastguard Worker         { // Failed case
447*4a64e381SAndroid Build Coastguard Worker             spinel_status_t status = SPINEL_STATUS_OK;
448*4a64e381SAndroid Build Coastguard Worker 
449*4a64e381SAndroid Build Coastguard Worker             SuccessOrExit(error = SpinelDataUnpack(aData, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status));
450*4a64e381SAndroid Build Coastguard Worker             CallAndClear(mDatasetMgmtSetPendingTask, ot::Spinel::SpinelStatusToOtError(status));
451*4a64e381SAndroid Build Coastguard Worker         }
452*4a64e381SAndroid Build Coastguard Worker         else if (aKey != SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS)
453*4a64e381SAndroid Build Coastguard Worker         {
454*4a64e381SAndroid Build Coastguard Worker             ExitNow(error = OTBR_ERROR_INVALID_STATE);
455*4a64e381SAndroid Build Coastguard Worker         }
456*4a64e381SAndroid Build Coastguard Worker         break;
457*4a64e381SAndroid Build Coastguard Worker 
458*4a64e381SAndroid Build Coastguard Worker     default:
459*4a64e381SAndroid Build Coastguard Worker         VerifyOrExit(aKey == mWaitingKeyTable[aTid], error = OTBR_ERROR_INVALID_STATE);
460*4a64e381SAndroid Build Coastguard Worker         break;
461*4a64e381SAndroid Build Coastguard Worker     }
462*4a64e381SAndroid Build Coastguard Worker 
463*4a64e381SAndroid Build Coastguard Worker exit:
464*4a64e381SAndroid Build Coastguard Worker     return error;
465*4a64e381SAndroid Build Coastguard Worker }
466*4a64e381SAndroid Build Coastguard Worker 
GetNextTid(void)467*4a64e381SAndroid Build Coastguard Worker spinel_tid_t NcpSpinel::GetNextTid(void)
468*4a64e381SAndroid Build Coastguard Worker {
469*4a64e381SAndroid Build Coastguard Worker     spinel_tid_t tid = mCmdNextTid;
470*4a64e381SAndroid Build Coastguard Worker 
471*4a64e381SAndroid Build Coastguard Worker     while (((1 << tid) & mCmdTidsInUse) != 0)
472*4a64e381SAndroid Build Coastguard Worker     {
473*4a64e381SAndroid Build Coastguard Worker         tid = SPINEL_GET_NEXT_TID(tid);
474*4a64e381SAndroid Build Coastguard Worker 
475*4a64e381SAndroid Build Coastguard Worker         if (tid == mCmdNextTid)
476*4a64e381SAndroid Build Coastguard Worker         {
477*4a64e381SAndroid Build Coastguard Worker             // We looped back to `mCmdNextTid` indicating that all
478*4a64e381SAndroid Build Coastguard Worker             // TIDs are in-use.
479*4a64e381SAndroid Build Coastguard Worker 
480*4a64e381SAndroid Build Coastguard Worker             ExitNow(tid = 0);
481*4a64e381SAndroid Build Coastguard Worker         }
482*4a64e381SAndroid Build Coastguard Worker     }
483*4a64e381SAndroid Build Coastguard Worker 
484*4a64e381SAndroid Build Coastguard Worker     mCmdTidsInUse |= (1 << tid);
485*4a64e381SAndroid Build Coastguard Worker     mCmdNextTid = SPINEL_GET_NEXT_TID(tid);
486*4a64e381SAndroid Build Coastguard Worker 
487*4a64e381SAndroid Build Coastguard Worker exit:
488*4a64e381SAndroid Build Coastguard Worker     return tid;
489*4a64e381SAndroid Build Coastguard Worker }
490*4a64e381SAndroid Build Coastguard Worker 
FreeTidTableItem(spinel_tid_t aTid)491*4a64e381SAndroid Build Coastguard Worker void NcpSpinel::FreeTidTableItem(spinel_tid_t aTid)
492*4a64e381SAndroid Build Coastguard Worker {
493*4a64e381SAndroid Build Coastguard Worker     mCmdTidsInUse &= ~(1 << aTid);
494*4a64e381SAndroid Build Coastguard Worker 
495*4a64e381SAndroid Build Coastguard Worker     mCmdTable[aTid]        = SPINEL_CMD_NOOP;
496*4a64e381SAndroid Build Coastguard Worker     mWaitingKeyTable[aTid] = SPINEL_PROP_LAST_STATUS;
497*4a64e381SAndroid Build Coastguard Worker }
498*4a64e381SAndroid Build Coastguard Worker 
SetProperty(spinel_prop_key_t aKey,const EncodingFunc & aEncodingFunc)499*4a64e381SAndroid Build Coastguard Worker otError NcpSpinel::SetProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc)
500*4a64e381SAndroid Build Coastguard Worker {
501*4a64e381SAndroid Build Coastguard Worker     otError      error  = OT_ERROR_NONE;
502*4a64e381SAndroid Build Coastguard Worker     spinel_tid_t tid    = GetNextTid();
503*4a64e381SAndroid Build Coastguard Worker     uint8_t      header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID(mIid) | tid;
504*4a64e381SAndroid Build Coastguard Worker 
505*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(tid != 0, error = OT_ERROR_BUSY);
506*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_SET, aKey));
507*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = aEncodingFunc());
508*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = mEncoder.EndFrame());
509*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = SendEncodedFrame());
510*4a64e381SAndroid Build Coastguard Worker 
511*4a64e381SAndroid Build Coastguard Worker     mCmdTable[tid]        = SPINEL_CMD_PROP_VALUE_SET;
512*4a64e381SAndroid Build Coastguard Worker     mWaitingKeyTable[tid] = aKey;
513*4a64e381SAndroid Build Coastguard Worker exit:
514*4a64e381SAndroid Build Coastguard Worker     if (error != OT_ERROR_NONE)
515*4a64e381SAndroid Build Coastguard Worker     {
516*4a64e381SAndroid Build Coastguard Worker         FreeTidTableItem(tid);
517*4a64e381SAndroid Build Coastguard Worker     }
518*4a64e381SAndroid Build Coastguard Worker     return error;
519*4a64e381SAndroid Build Coastguard Worker }
520*4a64e381SAndroid Build Coastguard Worker 
SendEncodedFrame(void)521*4a64e381SAndroid Build Coastguard Worker otError NcpSpinel::SendEncodedFrame(void)
522*4a64e381SAndroid Build Coastguard Worker {
523*4a64e381SAndroid Build Coastguard Worker     otError  error = OT_ERROR_NONE;
524*4a64e381SAndroid Build Coastguard Worker     uint8_t  frame[kTxBufferSize];
525*4a64e381SAndroid Build Coastguard Worker     uint16_t frameLength;
526*4a64e381SAndroid Build Coastguard Worker 
527*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = mNcpBuffer.OutFrameBegin());
528*4a64e381SAndroid Build Coastguard Worker     frameLength = mNcpBuffer.OutFrameGetLength();
529*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mNcpBuffer.OutFrameRead(frameLength, frame) == frameLength, error = OT_ERROR_FAILED);
530*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = mSpinelDriver->GetSpinelInterface()->SendFrame(frame, frameLength));
531*4a64e381SAndroid Build Coastguard Worker 
532*4a64e381SAndroid Build Coastguard Worker exit:
533*4a64e381SAndroid Build Coastguard Worker     error = mNcpBuffer.OutFrameRemove();
534*4a64e381SAndroid Build Coastguard Worker     return error;
535*4a64e381SAndroid Build Coastguard Worker }
536*4a64e381SAndroid Build Coastguard Worker 
ParseIp6AddressTable(const uint8_t * aBuf,uint16_t aLength,std::vector<Ip6AddressInfo> & aAddressTable)537*4a64e381SAndroid Build Coastguard Worker otError NcpSpinel::ParseIp6AddressTable(const uint8_t               *aBuf,
538*4a64e381SAndroid Build Coastguard Worker                                         uint16_t                     aLength,
539*4a64e381SAndroid Build Coastguard Worker                                         std::vector<Ip6AddressInfo> &aAddressTable)
540*4a64e381SAndroid Build Coastguard Worker {
541*4a64e381SAndroid Build Coastguard Worker     otError             error = OT_ERROR_NONE;
542*4a64e381SAndroid Build Coastguard Worker     ot::Spinel::Decoder decoder;
543*4a64e381SAndroid Build Coastguard Worker 
544*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(aBuf != nullptr, error = OT_ERROR_INVALID_ARGS);
545*4a64e381SAndroid Build Coastguard Worker     decoder.Init(aBuf, aLength);
546*4a64e381SAndroid Build Coastguard Worker 
547*4a64e381SAndroid Build Coastguard Worker     while (!decoder.IsAllReadInStruct())
548*4a64e381SAndroid Build Coastguard Worker     {
549*4a64e381SAndroid Build Coastguard Worker         Ip6AddressInfo      cur;
550*4a64e381SAndroid Build Coastguard Worker         const otIp6Address *addr;
551*4a64e381SAndroid Build Coastguard Worker         uint8_t             prefixLength;
552*4a64e381SAndroid Build Coastguard Worker         uint32_t            preferredLifetime;
553*4a64e381SAndroid Build Coastguard Worker         uint32_t            validLifetime;
554*4a64e381SAndroid Build Coastguard Worker 
555*4a64e381SAndroid Build Coastguard Worker         SuccessOrExit(error = decoder.OpenStruct());
556*4a64e381SAndroid Build Coastguard Worker         SuccessOrExit(error = decoder.ReadIp6Address(addr));
557*4a64e381SAndroid Build Coastguard Worker         memcpy(&cur.mAddress, addr, sizeof(otIp6Address));
558*4a64e381SAndroid Build Coastguard Worker         SuccessOrExit(error = decoder.ReadUint8(prefixLength));
559*4a64e381SAndroid Build Coastguard Worker         cur.mPrefixLength = prefixLength;
560*4a64e381SAndroid Build Coastguard Worker         SuccessOrExit(error = decoder.ReadUint32(preferredLifetime));
561*4a64e381SAndroid Build Coastguard Worker         cur.mPreferred = preferredLifetime ? true : false;
562*4a64e381SAndroid Build Coastguard Worker         SuccessOrExit(error = decoder.ReadUint32(validLifetime));
563*4a64e381SAndroid Build Coastguard Worker         OTBR_UNUSED_VARIABLE(validLifetime);
564*4a64e381SAndroid Build Coastguard Worker         SuccessOrExit((error = decoder.CloseStruct()));
565*4a64e381SAndroid Build Coastguard Worker 
566*4a64e381SAndroid Build Coastguard Worker         aAddressTable.push_back(cur);
567*4a64e381SAndroid Build Coastguard Worker     }
568*4a64e381SAndroid Build Coastguard Worker 
569*4a64e381SAndroid Build Coastguard Worker exit:
570*4a64e381SAndroid Build Coastguard Worker     return error;
571*4a64e381SAndroid Build Coastguard Worker }
572*4a64e381SAndroid Build Coastguard Worker 
ParseIp6MulticastAddresses(const uint8_t * aBuf,uint8_t aLen,std::vector<Ip6Address> & aAddressList)573*4a64e381SAndroid Build Coastguard Worker otError NcpSpinel::ParseIp6MulticastAddresses(const uint8_t *aBuf, uint8_t aLen, std::vector<Ip6Address> &aAddressList)
574*4a64e381SAndroid Build Coastguard Worker {
575*4a64e381SAndroid Build Coastguard Worker     otError             error = OT_ERROR_NONE;
576*4a64e381SAndroid Build Coastguard Worker     ot::Spinel::Decoder decoder;
577*4a64e381SAndroid Build Coastguard Worker 
578*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(aBuf != nullptr, error = OT_ERROR_INVALID_ARGS);
579*4a64e381SAndroid Build Coastguard Worker 
580*4a64e381SAndroid Build Coastguard Worker     decoder.Init(aBuf, aLen);
581*4a64e381SAndroid Build Coastguard Worker 
582*4a64e381SAndroid Build Coastguard Worker     while (!decoder.IsAllReadInStruct())
583*4a64e381SAndroid Build Coastguard Worker     {
584*4a64e381SAndroid Build Coastguard Worker         const otIp6Address *addr;
585*4a64e381SAndroid Build Coastguard Worker 
586*4a64e381SAndroid Build Coastguard Worker         SuccessOrExit(error = decoder.OpenStruct());
587*4a64e381SAndroid Build Coastguard Worker         SuccessOrExit(error = decoder.ReadIp6Address(addr));
588*4a64e381SAndroid Build Coastguard Worker         aAddressList.emplace_back(Ip6Address(*addr));
589*4a64e381SAndroid Build Coastguard Worker         SuccessOrExit((error = decoder.CloseStruct()));
590*4a64e381SAndroid Build Coastguard Worker     }
591*4a64e381SAndroid Build Coastguard Worker 
592*4a64e381SAndroid Build Coastguard Worker exit:
593*4a64e381SAndroid Build Coastguard Worker     return error;
594*4a64e381SAndroid Build Coastguard Worker }
595*4a64e381SAndroid Build Coastguard Worker 
ParseIp6StreamNet(const uint8_t * aBuf,uint8_t aLen,const uint8_t * & aData,uint16_t & aDataLen)596*4a64e381SAndroid Build Coastguard Worker otError NcpSpinel::ParseIp6StreamNet(const uint8_t *aBuf, uint8_t aLen, const uint8_t *&aData, uint16_t &aDataLen)
597*4a64e381SAndroid Build Coastguard Worker {
598*4a64e381SAndroid Build Coastguard Worker     otError             error = OT_ERROR_NONE;
599*4a64e381SAndroid Build Coastguard Worker     ot::Spinel::Decoder decoder;
600*4a64e381SAndroid Build Coastguard Worker 
601*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(aBuf != nullptr, error = OT_ERROR_INVALID_ARGS);
602*4a64e381SAndroid Build Coastguard Worker 
603*4a64e381SAndroid Build Coastguard Worker     decoder.Init(aBuf, aLen);
604*4a64e381SAndroid Build Coastguard Worker     error = decoder.ReadDataWithLen(aData, aDataLen);
605*4a64e381SAndroid Build Coastguard Worker 
606*4a64e381SAndroid Build Coastguard Worker exit:
607*4a64e381SAndroid Build Coastguard Worker     return error;
608*4a64e381SAndroid Build Coastguard Worker }
609*4a64e381SAndroid Build Coastguard Worker 
ParseOperationalDatasetTlvs(const uint8_t * aBuf,uint8_t aLen,otOperationalDatasetTlvs & aDatasetTlvs)610*4a64e381SAndroid Build Coastguard Worker otError NcpSpinel::ParseOperationalDatasetTlvs(const uint8_t            *aBuf,
611*4a64e381SAndroid Build Coastguard Worker                                                uint8_t                   aLen,
612*4a64e381SAndroid Build Coastguard Worker                                                otOperationalDatasetTlvs &aDatasetTlvs)
613*4a64e381SAndroid Build Coastguard Worker {
614*4a64e381SAndroid Build Coastguard Worker     otError             error = OT_ERROR_NONE;
615*4a64e381SAndroid Build Coastguard Worker     ot::Spinel::Decoder decoder;
616*4a64e381SAndroid Build Coastguard Worker     const uint8_t      *datasetTlvsData;
617*4a64e381SAndroid Build Coastguard Worker     uint16_t            datasetTlvsLen;
618*4a64e381SAndroid Build Coastguard Worker 
619*4a64e381SAndroid Build Coastguard Worker     decoder.Init(aBuf, aLen);
620*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(error = decoder.ReadData(datasetTlvsData, datasetTlvsLen));
621*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(datasetTlvsLen <= sizeof(aDatasetTlvs.mTlvs), error = OT_ERROR_PARSE);
622*4a64e381SAndroid Build Coastguard Worker 
623*4a64e381SAndroid Build Coastguard Worker     memcpy(aDatasetTlvs.mTlvs, datasetTlvsData, datasetTlvsLen);
624*4a64e381SAndroid Build Coastguard Worker     aDatasetTlvs.mLength = datasetTlvsLen;
625*4a64e381SAndroid Build Coastguard Worker 
626*4a64e381SAndroid Build Coastguard Worker exit:
627*4a64e381SAndroid Build Coastguard Worker     return error;
628*4a64e381SAndroid Build Coastguard Worker }
629*4a64e381SAndroid Build Coastguard Worker 
SpinelRoleToDeviceRole(spinel_net_role_t aRole)630*4a64e381SAndroid Build Coastguard Worker otDeviceRole NcpSpinel::SpinelRoleToDeviceRole(spinel_net_role_t aRole)
631*4a64e381SAndroid Build Coastguard Worker {
632*4a64e381SAndroid Build Coastguard Worker     otDeviceRole role = OT_DEVICE_ROLE_DISABLED;
633*4a64e381SAndroid Build Coastguard Worker 
634*4a64e381SAndroid Build Coastguard Worker     switch (aRole)
635*4a64e381SAndroid Build Coastguard Worker     {
636*4a64e381SAndroid Build Coastguard Worker     case SPINEL_NET_ROLE_DISABLED:
637*4a64e381SAndroid Build Coastguard Worker         role = OT_DEVICE_ROLE_DISABLED;
638*4a64e381SAndroid Build Coastguard Worker         break;
639*4a64e381SAndroid Build Coastguard Worker     case SPINEL_NET_ROLE_DETACHED:
640*4a64e381SAndroid Build Coastguard Worker         role = OT_DEVICE_ROLE_DETACHED;
641*4a64e381SAndroid Build Coastguard Worker         break;
642*4a64e381SAndroid Build Coastguard Worker     case SPINEL_NET_ROLE_CHILD:
643*4a64e381SAndroid Build Coastguard Worker         role = OT_DEVICE_ROLE_CHILD;
644*4a64e381SAndroid Build Coastguard Worker         break;
645*4a64e381SAndroid Build Coastguard Worker     case SPINEL_NET_ROLE_ROUTER:
646*4a64e381SAndroid Build Coastguard Worker         role = OT_DEVICE_ROLE_ROUTER;
647*4a64e381SAndroid Build Coastguard Worker         break;
648*4a64e381SAndroid Build Coastguard Worker     case SPINEL_NET_ROLE_LEADER:
649*4a64e381SAndroid Build Coastguard Worker         role = OT_DEVICE_ROLE_LEADER;
650*4a64e381SAndroid Build Coastguard Worker         break;
651*4a64e381SAndroid Build Coastguard Worker     default:
652*4a64e381SAndroid Build Coastguard Worker         otbrLogWarning("Unsupported spinel net role: %u", aRole);
653*4a64e381SAndroid Build Coastguard Worker         break;
654*4a64e381SAndroid Build Coastguard Worker     }
655*4a64e381SAndroid Build Coastguard Worker 
656*4a64e381SAndroid Build Coastguard Worker     return role;
657*4a64e381SAndroid Build Coastguard Worker }
658*4a64e381SAndroid Build Coastguard Worker 
659*4a64e381SAndroid Build Coastguard Worker } // namespace Ncp
660*4a64e381SAndroid Build Coastguard Worker } // namespace otbr
661