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