xref: /aosp_15_r20/external/openthread/src/ncp/ncp_hdlc.cpp (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
1*cfb92d14SAndroid Build Coastguard Worker /*
2*cfb92d14SAndroid Build Coastguard Worker  *    Copyright (c) 2016, The OpenThread Authors.
3*cfb92d14SAndroid Build Coastguard Worker  *    All rights reserved.
4*cfb92d14SAndroid Build Coastguard Worker  *
5*cfb92d14SAndroid Build Coastguard Worker  *    Redistribution and use in source and binary forms, with or without
6*cfb92d14SAndroid Build Coastguard Worker  *    modification, are permitted provided that the following conditions are met:
7*cfb92d14SAndroid Build Coastguard Worker  *    1. Redistributions of source code must retain the above copyright
8*cfb92d14SAndroid Build Coastguard Worker  *       notice, this list of conditions and the following disclaimer.
9*cfb92d14SAndroid Build Coastguard Worker  *    2. Redistributions in binary form must reproduce the above copyright
10*cfb92d14SAndroid Build Coastguard Worker  *       notice, this list of conditions and the following disclaimer in the
11*cfb92d14SAndroid Build Coastguard Worker  *       documentation and/or other materials provided with the distribution.
12*cfb92d14SAndroid Build Coastguard Worker  *    3. Neither the name of the copyright holder nor the
13*cfb92d14SAndroid Build Coastguard Worker  *       names of its contributors may be used to endorse or promote products
14*cfb92d14SAndroid Build Coastguard Worker  *       derived from this software without specific prior written permission.
15*cfb92d14SAndroid Build Coastguard Worker  *
16*cfb92d14SAndroid Build Coastguard Worker  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17*cfb92d14SAndroid Build Coastguard Worker  *    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18*cfb92d14SAndroid Build Coastguard Worker  *    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19*cfb92d14SAndroid Build Coastguard Worker  *    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20*cfb92d14SAndroid Build Coastguard Worker  *    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21*cfb92d14SAndroid Build Coastguard Worker  *    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22*cfb92d14SAndroid Build Coastguard Worker  *    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23*cfb92d14SAndroid Build Coastguard Worker  *    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*cfb92d14SAndroid Build Coastguard Worker  *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25*cfb92d14SAndroid Build Coastguard Worker  *    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*cfb92d14SAndroid Build Coastguard Worker  */
27*cfb92d14SAndroid Build Coastguard Worker 
28*cfb92d14SAndroid Build Coastguard Worker /**
29*cfb92d14SAndroid Build Coastguard Worker  * @file
30*cfb92d14SAndroid Build Coastguard Worker  *   This file contains definitions for a HDLC based NCP interface to the OpenThread stack.
31*cfb92d14SAndroid Build Coastguard Worker  */
32*cfb92d14SAndroid Build Coastguard Worker 
33*cfb92d14SAndroid Build Coastguard Worker #include "ncp_hdlc.hpp"
34*cfb92d14SAndroid Build Coastguard Worker 
35*cfb92d14SAndroid Build Coastguard Worker #include <stdio.h>
36*cfb92d14SAndroid Build Coastguard Worker 
37*cfb92d14SAndroid Build Coastguard Worker #include <openthread/ncp.h>
38*cfb92d14SAndroid Build Coastguard Worker #include <openthread/platform/logging.h>
39*cfb92d14SAndroid Build Coastguard Worker #include <openthread/platform/misc.h>
40*cfb92d14SAndroid Build Coastguard Worker 
41*cfb92d14SAndroid Build Coastguard Worker #include "openthread-core-config.h"
42*cfb92d14SAndroid Build Coastguard Worker #include "common/code_utils.hpp"
43*cfb92d14SAndroid Build Coastguard Worker #include "common/debug.hpp"
44*cfb92d14SAndroid Build Coastguard Worker #include "common/new.hpp"
45*cfb92d14SAndroid Build Coastguard Worker #include "instance/instance.hpp"
46*cfb92d14SAndroid Build Coastguard Worker #include "net/ip6.hpp"
47*cfb92d14SAndroid Build Coastguard Worker 
48*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_NCP_HDLC_ENABLE
49*cfb92d14SAndroid Build Coastguard Worker 
50*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_DIAG_ENABLE
51*cfb92d14SAndroid Build Coastguard Worker static_assert(OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE <= OPENTHREAD_CONFIG_NCP_HDLC_RX_BUFFER_SIZE -
52*cfb92d14SAndroid Build Coastguard Worker                                                                ot::Ncp::NcpBase::kSpinelCmdHeaderSize -
53*cfb92d14SAndroid Build Coastguard Worker                                                                ot::Ncp::NcpBase::kSpinelPropIdSize,
54*cfb92d14SAndroid Build Coastguard Worker               "diag output should be smaller than NCP HDLC rx buffer");
55*cfb92d14SAndroid Build Coastguard Worker 
56*cfb92d14SAndroid Build Coastguard Worker static_assert(OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE <= OPENTHREAD_CONFIG_NCP_HDLC_RX_BUFFER_SIZE,
57*cfb92d14SAndroid Build Coastguard Worker               "diag command line should be smaller than NCP HDLC rx buffer");
58*cfb92d14SAndroid Build Coastguard Worker #endif
59*cfb92d14SAndroid Build Coastguard Worker 
60*cfb92d14SAndroid Build Coastguard Worker namespace ot {
61*cfb92d14SAndroid Build Coastguard Worker namespace Ncp {
62*cfb92d14SAndroid Build Coastguard Worker 
63*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK == 0
64*cfb92d14SAndroid Build Coastguard Worker 
65*cfb92d14SAndroid Build Coastguard Worker static OT_DEFINE_ALIGNED_VAR(sNcpRaw, sizeof(NcpHdlc), uint64_t);
66*cfb92d14SAndroid Build Coastguard Worker 
otNcpHdlcInit(otInstance * aInstance,otNcpHdlcSendCallback aSendCallback)67*cfb92d14SAndroid Build Coastguard Worker extern "C" void otNcpHdlcInit(otInstance *aInstance, otNcpHdlcSendCallback aSendCallback)
68*cfb92d14SAndroid Build Coastguard Worker {
69*cfb92d14SAndroid Build Coastguard Worker     NcpHdlc  *ncpHdlc  = nullptr;
70*cfb92d14SAndroid Build Coastguard Worker     Instance *instance = static_cast<Instance *>(aInstance);
71*cfb92d14SAndroid Build Coastguard Worker 
72*cfb92d14SAndroid Build Coastguard Worker     ncpHdlc = new (&sNcpRaw) NcpHdlc(instance, aSendCallback);
73*cfb92d14SAndroid Build Coastguard Worker 
74*cfb92d14SAndroid Build Coastguard Worker     if (ncpHdlc == nullptr || ncpHdlc != NcpBase::GetNcpInstance())
75*cfb92d14SAndroid Build Coastguard Worker     {
76*cfb92d14SAndroid Build Coastguard Worker         OT_ASSERT(false);
77*cfb92d14SAndroid Build Coastguard Worker     }
78*cfb92d14SAndroid Build Coastguard Worker }
79*cfb92d14SAndroid Build Coastguard Worker 
80*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE && OPENTHREAD_RADIO
81*cfb92d14SAndroid Build Coastguard Worker 
otNcpHdlcInitMulti(otInstance ** aInstances,uint8_t aCount,otNcpHdlcSendCallback aSendCallback)82*cfb92d14SAndroid Build Coastguard Worker extern "C" void otNcpHdlcInitMulti(otInstance **aInstances, uint8_t aCount, otNcpHdlcSendCallback aSendCallback)
83*cfb92d14SAndroid Build Coastguard Worker {
84*cfb92d14SAndroid Build Coastguard Worker     NcpHdlc      *ncpHdlc = nullptr;
85*cfb92d14SAndroid Build Coastguard Worker     ot::Instance *instances[SPINEL_HEADER_IID_MAX];
86*cfb92d14SAndroid Build Coastguard Worker 
87*cfb92d14SAndroid Build Coastguard Worker     OT_ASSERT(aCount < SPINEL_HEADER_IID_MAX + 1);
88*cfb92d14SAndroid Build Coastguard Worker     OT_ASSERT(aCount > 0);
89*cfb92d14SAndroid Build Coastguard Worker     OT_ASSERT(aInstances[0] != nullptr);
90*cfb92d14SAndroid Build Coastguard Worker 
91*cfb92d14SAndroid Build Coastguard Worker     for (int i = 0; i < aCount; i++)
92*cfb92d14SAndroid Build Coastguard Worker     {
93*cfb92d14SAndroid Build Coastguard Worker         instances[i] = static_cast<ot::Instance *>(aInstances[i]);
94*cfb92d14SAndroid Build Coastguard Worker     }
95*cfb92d14SAndroid Build Coastguard Worker 
96*cfb92d14SAndroid Build Coastguard Worker     ncpHdlc = new (&sNcpRaw) NcpHdlc(instances, aCount, aSendCallback);
97*cfb92d14SAndroid Build Coastguard Worker 
98*cfb92d14SAndroid Build Coastguard Worker     if (ncpHdlc == nullptr || ncpHdlc != NcpBase::GetNcpInstance())
99*cfb92d14SAndroid Build Coastguard Worker     {
100*cfb92d14SAndroid Build Coastguard Worker         OT_ASSERT(false);
101*cfb92d14SAndroid Build Coastguard Worker     }
102*cfb92d14SAndroid Build Coastguard Worker }
103*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE && OPENTHREAD_RADIO
104*cfb92d14SAndroid Build Coastguard Worker 
105*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_ENABLE_NCP_VENDOR_HOOK == 0
106*cfb92d14SAndroid Build Coastguard Worker 
NcpHdlc(Instance * aInstance,otNcpHdlcSendCallback aSendCallback)107*cfb92d14SAndroid Build Coastguard Worker NcpHdlc::NcpHdlc(Instance *aInstance, otNcpHdlcSendCallback aSendCallback)
108*cfb92d14SAndroid Build Coastguard Worker     : NcpBase(aInstance)
109*cfb92d14SAndroid Build Coastguard Worker     , mSendCallback(aSendCallback)
110*cfb92d14SAndroid Build Coastguard Worker     , mFrameEncoder(mHdlcBuffer)
111*cfb92d14SAndroid Build Coastguard Worker     , mState(kStartingFrame)
112*cfb92d14SAndroid Build Coastguard Worker     , mByte(0)
113*cfb92d14SAndroid Build Coastguard Worker     , mHdlcSendImmediate(false)
114*cfb92d14SAndroid Build Coastguard Worker     , mHdlcSendTask(*aInstance, EncodeAndSend)
115*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
116*cfb92d14SAndroid Build Coastguard Worker     , mTxFrameBufferEncrypterReader(mTxFrameBuffer)
117*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
118*cfb92d14SAndroid Build Coastguard Worker {
119*cfb92d14SAndroid Build Coastguard Worker     mFrameDecoder.Init(mRxBuffer, &NcpHdlc::HandleFrame, this);
120*cfb92d14SAndroid Build Coastguard Worker     mTxFrameBuffer.SetFrameAddedCallback(HandleFrameAddedToNcpBuffer, this);
121*cfb92d14SAndroid Build Coastguard Worker }
122*cfb92d14SAndroid Build Coastguard Worker 
123*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE && OPENTHREAD_RADIO
124*cfb92d14SAndroid Build Coastguard Worker 
NcpHdlc(Instance ** aInstances,uint8_t aCount,otNcpHdlcSendCallback aSendCallback)125*cfb92d14SAndroid Build Coastguard Worker NcpHdlc::NcpHdlc(Instance **aInstances, uint8_t aCount, otNcpHdlcSendCallback aSendCallback)
126*cfb92d14SAndroid Build Coastguard Worker     : NcpBase(aInstances, aCount)
127*cfb92d14SAndroid Build Coastguard Worker     , mSendCallback(aSendCallback)
128*cfb92d14SAndroid Build Coastguard Worker     , mFrameEncoder(mHdlcBuffer)
129*cfb92d14SAndroid Build Coastguard Worker     , mState(kStartingFrame)
130*cfb92d14SAndroid Build Coastguard Worker     , mByte(0)
131*cfb92d14SAndroid Build Coastguard Worker     , mHdlcSendImmediate(false)
132*cfb92d14SAndroid Build Coastguard Worker     , mHdlcSendTask(*aInstances[0], EncodeAndSend)
133*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
134*cfb92d14SAndroid Build Coastguard Worker     , mTxFrameBufferEncrypterReader(mTxFrameBuffer)
135*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
136*cfb92d14SAndroid Build Coastguard Worker {
137*cfb92d14SAndroid Build Coastguard Worker     mFrameDecoder.Init(mRxBuffer, &NcpHdlc::HandleFrame, this);
138*cfb92d14SAndroid Build Coastguard Worker     mTxFrameBuffer.SetFrameAddedCallback(HandleFrameAddedToNcpBuffer, this);
139*cfb92d14SAndroid Build Coastguard Worker }
140*cfb92d14SAndroid Build Coastguard Worker 
141*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE && OPENTHREAD_RADIO
142*cfb92d14SAndroid Build Coastguard Worker 
HandleFrameAddedToNcpBuffer(void * aContext,Spinel::Buffer::FrameTag aTag,Spinel::Buffer::Priority aPriority,Spinel::Buffer * aBuffer)143*cfb92d14SAndroid Build Coastguard Worker void NcpHdlc::HandleFrameAddedToNcpBuffer(void                    *aContext,
144*cfb92d14SAndroid Build Coastguard Worker                                           Spinel::Buffer::FrameTag aTag,
145*cfb92d14SAndroid Build Coastguard Worker                                           Spinel::Buffer::Priority aPriority,
146*cfb92d14SAndroid Build Coastguard Worker                                           Spinel::Buffer          *aBuffer)
147*cfb92d14SAndroid Build Coastguard Worker {
148*cfb92d14SAndroid Build Coastguard Worker     OT_UNUSED_VARIABLE(aBuffer);
149*cfb92d14SAndroid Build Coastguard Worker     OT_UNUSED_VARIABLE(aTag);
150*cfb92d14SAndroid Build Coastguard Worker     OT_UNUSED_VARIABLE(aPriority);
151*cfb92d14SAndroid Build Coastguard Worker 
152*cfb92d14SAndroid Build Coastguard Worker     static_cast<NcpHdlc *>(aContext)->HandleFrameAddedToNcpBuffer();
153*cfb92d14SAndroid Build Coastguard Worker }
154*cfb92d14SAndroid Build Coastguard Worker 
HandleFrameAddedToNcpBuffer(void)155*cfb92d14SAndroid Build Coastguard Worker void NcpHdlc::HandleFrameAddedToNcpBuffer(void)
156*cfb92d14SAndroid Build Coastguard Worker {
157*cfb92d14SAndroid Build Coastguard Worker     if (mHdlcBuffer.IsEmpty())
158*cfb92d14SAndroid Build Coastguard Worker     {
159*cfb92d14SAndroid Build Coastguard Worker         mHdlcSendTask.Post();
160*cfb92d14SAndroid Build Coastguard Worker     }
161*cfb92d14SAndroid Build Coastguard Worker }
162*cfb92d14SAndroid Build Coastguard Worker 
EncodeAndSend(Tasklet & aTasklet)163*cfb92d14SAndroid Build Coastguard Worker void NcpHdlc::EncodeAndSend(Tasklet &aTasklet)
164*cfb92d14SAndroid Build Coastguard Worker {
165*cfb92d14SAndroid Build Coastguard Worker     OT_UNUSED_VARIABLE(aTasklet);
166*cfb92d14SAndroid Build Coastguard Worker     static_cast<NcpHdlc *>(GetNcpInstance())->EncodeAndSend();
167*cfb92d14SAndroid Build Coastguard Worker }
168*cfb92d14SAndroid Build Coastguard Worker 
169*cfb92d14SAndroid Build Coastguard Worker // This method encodes a frame from the tx frame buffer (mTxFrameBuffer) into the uart buffer and sends it over uart.
170*cfb92d14SAndroid Build Coastguard Worker // If the uart buffer gets full, it sends the current encoded portion. This method remembers current state, so on
171*cfb92d14SAndroid Build Coastguard Worker // sub-sequent calls, it restarts encoding the bytes from where it left of in the frame .
EncodeAndSend(void)172*cfb92d14SAndroid Build Coastguard Worker void NcpHdlc::EncodeAndSend(void)
173*cfb92d14SAndroid Build Coastguard Worker {
174*cfb92d14SAndroid Build Coastguard Worker     uint16_t len;
175*cfb92d14SAndroid Build Coastguard Worker     bool     prevHostPowerState;
176*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
177*cfb92d14SAndroid Build Coastguard Worker     BufferEncrypterReader &txFrameBuffer = mTxFrameBufferEncrypterReader;
178*cfb92d14SAndroid Build Coastguard Worker #else
179*cfb92d14SAndroid Build Coastguard Worker     Spinel::Buffer &txFrameBuffer = mTxFrameBuffer;
180*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
181*cfb92d14SAndroid Build Coastguard Worker 
182*cfb92d14SAndroid Build Coastguard Worker     while (!txFrameBuffer.IsEmpty() || (mState == kFinalizingFrame))
183*cfb92d14SAndroid Build Coastguard Worker     {
184*cfb92d14SAndroid Build Coastguard Worker         switch (mState)
185*cfb92d14SAndroid Build Coastguard Worker         {
186*cfb92d14SAndroid Build Coastguard Worker         case kStartingFrame:
187*cfb92d14SAndroid Build Coastguard Worker 
188*cfb92d14SAndroid Build Coastguard Worker             if (super_t::ShouldWakeHost())
189*cfb92d14SAndroid Build Coastguard Worker             {
190*cfb92d14SAndroid Build Coastguard Worker                 otPlatWakeHost();
191*cfb92d14SAndroid Build Coastguard Worker             }
192*cfb92d14SAndroid Build Coastguard Worker 
193*cfb92d14SAndroid Build Coastguard Worker             VerifyOrExit(!super_t::ShouldDeferHostSend());
194*cfb92d14SAndroid Build Coastguard Worker             SuccessOrExit(mFrameEncoder.BeginFrame());
195*cfb92d14SAndroid Build Coastguard Worker 
196*cfb92d14SAndroid Build Coastguard Worker             IgnoreError(txFrameBuffer.OutFrameBegin());
197*cfb92d14SAndroid Build Coastguard Worker 
198*cfb92d14SAndroid Build Coastguard Worker             mState = kEncodingFrame;
199*cfb92d14SAndroid Build Coastguard Worker 
200*cfb92d14SAndroid Build Coastguard Worker             while (!txFrameBuffer.OutFrameHasEnded())
201*cfb92d14SAndroid Build Coastguard Worker             {
202*cfb92d14SAndroid Build Coastguard Worker                 mByte = txFrameBuffer.OutFrameReadByte();
203*cfb92d14SAndroid Build Coastguard Worker 
204*cfb92d14SAndroid Build Coastguard Worker                 OT_FALL_THROUGH;
205*cfb92d14SAndroid Build Coastguard Worker 
206*cfb92d14SAndroid Build Coastguard Worker             case kEncodingFrame:
207*cfb92d14SAndroid Build Coastguard Worker 
208*cfb92d14SAndroid Build Coastguard Worker                 SuccessOrExit(mFrameEncoder.Encode(mByte));
209*cfb92d14SAndroid Build Coastguard Worker             }
210*cfb92d14SAndroid Build Coastguard Worker 
211*cfb92d14SAndroid Build Coastguard Worker             // track the change of mHostPowerStateInProgress by the
212*cfb92d14SAndroid Build Coastguard Worker             // call to OutFrameRemove.
213*cfb92d14SAndroid Build Coastguard Worker             prevHostPowerState = mHostPowerStateInProgress;
214*cfb92d14SAndroid Build Coastguard Worker 
215*cfb92d14SAndroid Build Coastguard Worker             IgnoreError(txFrameBuffer.OutFrameRemove());
216*cfb92d14SAndroid Build Coastguard Worker 
217*cfb92d14SAndroid Build Coastguard Worker             if (prevHostPowerState && !mHostPowerStateInProgress)
218*cfb92d14SAndroid Build Coastguard Worker             {
219*cfb92d14SAndroid Build Coastguard Worker                 // If mHostPowerStateInProgress transitioned from true -> false
220*cfb92d14SAndroid Build Coastguard Worker                 // in the call to OutFrameRemove, then the frame should be sent
221*cfb92d14SAndroid Build Coastguard Worker                 // out without attempting to push any new frames into the
222*cfb92d14SAndroid Build Coastguard Worker                 // mHdlcBuffer. This is necessary to avoid prematurely calling
223*cfb92d14SAndroid Build Coastguard Worker                 // otPlatWakeHost.
224*cfb92d14SAndroid Build Coastguard Worker                 mHdlcSendImmediate = true;
225*cfb92d14SAndroid Build Coastguard Worker             }
226*cfb92d14SAndroid Build Coastguard Worker 
227*cfb92d14SAndroid Build Coastguard Worker             mState = kFinalizingFrame;
228*cfb92d14SAndroid Build Coastguard Worker 
229*cfb92d14SAndroid Build Coastguard Worker             OT_FALL_THROUGH;
230*cfb92d14SAndroid Build Coastguard Worker 
231*cfb92d14SAndroid Build Coastguard Worker         case kFinalizingFrame:
232*cfb92d14SAndroid Build Coastguard Worker 
233*cfb92d14SAndroid Build Coastguard Worker             SuccessOrExit(mFrameEncoder.EndFrame());
234*cfb92d14SAndroid Build Coastguard Worker 
235*cfb92d14SAndroid Build Coastguard Worker             mState = kStartingFrame;
236*cfb92d14SAndroid Build Coastguard Worker 
237*cfb92d14SAndroid Build Coastguard Worker             if (mHdlcSendImmediate)
238*cfb92d14SAndroid Build Coastguard Worker             {
239*cfb92d14SAndroid Build Coastguard Worker                 // clear state and break;
240*cfb92d14SAndroid Build Coastguard Worker                 mHdlcSendImmediate = false;
241*cfb92d14SAndroid Build Coastguard Worker                 break;
242*cfb92d14SAndroid Build Coastguard Worker             }
243*cfb92d14SAndroid Build Coastguard Worker         }
244*cfb92d14SAndroid Build Coastguard Worker     }
245*cfb92d14SAndroid Build Coastguard Worker 
246*cfb92d14SAndroid Build Coastguard Worker exit:
247*cfb92d14SAndroid Build Coastguard Worker     len = mHdlcBuffer.GetLength();
248*cfb92d14SAndroid Build Coastguard Worker 
249*cfb92d14SAndroid Build Coastguard Worker     if (len > 0)
250*cfb92d14SAndroid Build Coastguard Worker     {
251*cfb92d14SAndroid Build Coastguard Worker         int rval = mSendCallback(mHdlcBuffer.GetFrame(), len);
252*cfb92d14SAndroid Build Coastguard Worker         OT_UNUSED_VARIABLE(rval);
253*cfb92d14SAndroid Build Coastguard Worker         OT_ASSERT(rval == static_cast<int>(len));
254*cfb92d14SAndroid Build Coastguard Worker     }
255*cfb92d14SAndroid Build Coastguard Worker }
256*cfb92d14SAndroid Build Coastguard Worker 
otNcpHdlcSendDone(void)257*cfb92d14SAndroid Build Coastguard Worker extern "C" void otNcpHdlcSendDone(void)
258*cfb92d14SAndroid Build Coastguard Worker {
259*cfb92d14SAndroid Build Coastguard Worker     NcpHdlc *ncpHdlc = static_cast<NcpHdlc *>(NcpBase::GetNcpInstance());
260*cfb92d14SAndroid Build Coastguard Worker 
261*cfb92d14SAndroid Build Coastguard Worker     if (ncpHdlc != nullptr)
262*cfb92d14SAndroid Build Coastguard Worker     {
263*cfb92d14SAndroid Build Coastguard Worker         ncpHdlc->HandleHdlcSendDone();
264*cfb92d14SAndroid Build Coastguard Worker     }
265*cfb92d14SAndroid Build Coastguard Worker }
266*cfb92d14SAndroid Build Coastguard Worker 
HandleHdlcSendDone(void)267*cfb92d14SAndroid Build Coastguard Worker void NcpHdlc::HandleHdlcSendDone(void)
268*cfb92d14SAndroid Build Coastguard Worker {
269*cfb92d14SAndroid Build Coastguard Worker     mHdlcBuffer.Clear();
270*cfb92d14SAndroid Build Coastguard Worker     mHdlcSendTask.Post();
271*cfb92d14SAndroid Build Coastguard Worker }
272*cfb92d14SAndroid Build Coastguard Worker 
otNcpHdlcReceive(const uint8_t * aBuf,uint16_t aBufLength)273*cfb92d14SAndroid Build Coastguard Worker extern "C" void otNcpHdlcReceive(const uint8_t *aBuf, uint16_t aBufLength)
274*cfb92d14SAndroid Build Coastguard Worker {
275*cfb92d14SAndroid Build Coastguard Worker     NcpHdlc *ncpHdlc = static_cast<NcpHdlc *>(NcpBase::GetNcpInstance());
276*cfb92d14SAndroid Build Coastguard Worker 
277*cfb92d14SAndroid Build Coastguard Worker     if (ncpHdlc != nullptr)
278*cfb92d14SAndroid Build Coastguard Worker     {
279*cfb92d14SAndroid Build Coastguard Worker         ncpHdlc->HandleHdlcReceiveDone(aBuf, aBufLength);
280*cfb92d14SAndroid Build Coastguard Worker     }
281*cfb92d14SAndroid Build Coastguard Worker }
282*cfb92d14SAndroid Build Coastguard Worker 
HandleHdlcReceiveDone(const uint8_t * aBuf,uint16_t aBufLength)283*cfb92d14SAndroid Build Coastguard Worker void NcpHdlc::HandleHdlcReceiveDone(const uint8_t *aBuf, uint16_t aBufLength)
284*cfb92d14SAndroid Build Coastguard Worker {
285*cfb92d14SAndroid Build Coastguard Worker     mFrameDecoder.Decode(aBuf, aBufLength);
286*cfb92d14SAndroid Build Coastguard Worker }
287*cfb92d14SAndroid Build Coastguard Worker 
HandleFrame(void * aContext,otError aError)288*cfb92d14SAndroid Build Coastguard Worker void NcpHdlc::HandleFrame(void *aContext, otError aError) { static_cast<NcpHdlc *>(aContext)->HandleFrame(aError); }
289*cfb92d14SAndroid Build Coastguard Worker 
HandleFrame(otError aError)290*cfb92d14SAndroid Build Coastguard Worker void NcpHdlc::HandleFrame(otError aError)
291*cfb92d14SAndroid Build Coastguard Worker {
292*cfb92d14SAndroid Build Coastguard Worker     uint8_t *buf       = mRxBuffer.GetFrame();
293*cfb92d14SAndroid Build Coastguard Worker     uint16_t bufLength = mRxBuffer.GetLength();
294*cfb92d14SAndroid Build Coastguard Worker 
295*cfb92d14SAndroid Build Coastguard Worker     if (aError == OT_ERROR_NONE)
296*cfb92d14SAndroid Build Coastguard Worker     {
297*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
298*cfb92d14SAndroid Build Coastguard Worker         size_t dataLen = bufLength;
299*cfb92d14SAndroid Build Coastguard Worker         if (SpinelEncrypter::DecryptInbound(buf, kRxBufferSize, &dataLen))
300*cfb92d14SAndroid Build Coastguard Worker         {
301*cfb92d14SAndroid Build Coastguard Worker             super_t::HandleReceive(buf, dataLen);
302*cfb92d14SAndroid Build Coastguard Worker         }
303*cfb92d14SAndroid Build Coastguard Worker #else
304*cfb92d14SAndroid Build Coastguard Worker         super_t::HandleReceive(buf, bufLength);
305*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
306*cfb92d14SAndroid Build Coastguard Worker     }
307*cfb92d14SAndroid Build Coastguard Worker     else
308*cfb92d14SAndroid Build Coastguard Worker     {
309*cfb92d14SAndroid Build Coastguard Worker         HandleError(aError, buf, bufLength);
310*cfb92d14SAndroid Build Coastguard Worker     }
311*cfb92d14SAndroid Build Coastguard Worker 
312*cfb92d14SAndroid Build Coastguard Worker     mRxBuffer.Clear();
313*cfb92d14SAndroid Build Coastguard Worker }
314*cfb92d14SAndroid Build Coastguard Worker 
HandleError(otError aError,uint8_t * aBuf,uint16_t aBufLength)315*cfb92d14SAndroid Build Coastguard Worker void NcpHdlc::HandleError(otError aError, uint8_t *aBuf, uint16_t aBufLength)
316*cfb92d14SAndroid Build Coastguard Worker {
317*cfb92d14SAndroid Build Coastguard Worker     char     hexbuf[128];
318*cfb92d14SAndroid Build Coastguard Worker     uint16_t i = 0;
319*cfb92d14SAndroid Build Coastguard Worker 
320*cfb92d14SAndroid Build Coastguard Worker     super_t::IncrementFrameErrorCounter();
321*cfb92d14SAndroid Build Coastguard Worker 
322*cfb92d14SAndroid Build Coastguard Worker     snprintf(hexbuf, sizeof(hexbuf), "Framing error %d: [", aError);
323*cfb92d14SAndroid Build Coastguard Worker 
324*cfb92d14SAndroid Build Coastguard Worker     // Write out the first part of our log message.
325*cfb92d14SAndroid Build Coastguard Worker     IgnoreError(otNcpStreamWrite(0, reinterpret_cast<uint8_t *>(hexbuf), static_cast<int>(strlen(hexbuf))));
326*cfb92d14SAndroid Build Coastguard Worker 
327*cfb92d14SAndroid Build Coastguard Worker     // The first '3' comes from the trailing "]\n\000" at the end o the string.
328*cfb92d14SAndroid Build Coastguard Worker     // The second '3' comes from the length of two hex digits and a space.
329*cfb92d14SAndroid Build Coastguard Worker     for (i = 0; (i < aBufLength) && (i < (sizeof(hexbuf) - 3) / 3); i++)
330*cfb92d14SAndroid Build Coastguard Worker     {
331*cfb92d14SAndroid Build Coastguard Worker         snprintf(&hexbuf[i * 3], sizeof(hexbuf) - i * 3, " %02X", static_cast<uint8_t>(aBuf[i]));
332*cfb92d14SAndroid Build Coastguard Worker     }
333*cfb92d14SAndroid Build Coastguard Worker 
334*cfb92d14SAndroid Build Coastguard Worker     // Append a final closing bracket and newline character
335*cfb92d14SAndroid Build Coastguard Worker     // so our log line looks nice.
336*cfb92d14SAndroid Build Coastguard Worker     snprintf(&hexbuf[i * 3], sizeof(hexbuf) - i * 3, "]\n");
337*cfb92d14SAndroid Build Coastguard Worker 
338*cfb92d14SAndroid Build Coastguard Worker     // Write out the second part of our log message.
339*cfb92d14SAndroid Build Coastguard Worker     // We skip the first byte since it has a space in it.
340*cfb92d14SAndroid Build Coastguard Worker     IgnoreError(otNcpStreamWrite(0, reinterpret_cast<uint8_t *>(hexbuf + 1), static_cast<int>(strlen(hexbuf) - 1)));
341*cfb92d14SAndroid Build Coastguard Worker }
342*cfb92d14SAndroid Build Coastguard Worker 
343*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
344*cfb92d14SAndroid Build Coastguard Worker 
BufferEncrypterReader(Spinel::Buffer & aTxFrameBuffer)345*cfb92d14SAndroid Build Coastguard Worker NcpHdlc::BufferEncrypterReader::BufferEncrypterReader(Spinel::Buffer &aTxFrameBuffer)
346*cfb92d14SAndroid Build Coastguard Worker     : mTxFrameBuffer(aTxFrameBuffer)
347*cfb92d14SAndroid Build Coastguard Worker     , mDataBufferReadIndex(0)
348*cfb92d14SAndroid Build Coastguard Worker     , mOutputDataLength(0)
349*cfb92d14SAndroid Build Coastguard Worker {
350*cfb92d14SAndroid Build Coastguard Worker }
351*cfb92d14SAndroid Build Coastguard Worker 
IsEmpty(void) const352*cfb92d14SAndroid Build Coastguard Worker bool NcpHdlc::BufferEncrypterReader::IsEmpty(void) const { return mTxFrameBuffer.IsEmpty() && !mOutputDataLength; }
353*cfb92d14SAndroid Build Coastguard Worker 
OutFrameBegin(void)354*cfb92d14SAndroid Build Coastguard Worker otError NcpHdlc::BufferEncrypterReader::OutFrameBegin(void)
355*cfb92d14SAndroid Build Coastguard Worker {
356*cfb92d14SAndroid Build Coastguard Worker     otError status = OT_ERROR_FAILED;
357*cfb92d14SAndroid Build Coastguard Worker 
358*cfb92d14SAndroid Build Coastguard Worker     Reset();
359*cfb92d14SAndroid Build Coastguard Worker 
360*cfb92d14SAndroid Build Coastguard Worker     if ((status = mTxFrameBuffer.OutFrameBegin()) == OT_ERROR_NONE)
361*cfb92d14SAndroid Build Coastguard Worker     {
362*cfb92d14SAndroid Build Coastguard Worker         mOutputDataLength = mTxFrameBuffer.OutFrameGetLength();
363*cfb92d14SAndroid Build Coastguard Worker 
364*cfb92d14SAndroid Build Coastguard Worker         if (mOutputDataLength > 0)
365*cfb92d14SAndroid Build Coastguard Worker         {
366*cfb92d14SAndroid Build Coastguard Worker             OT_ASSERT(mOutputDataLength <= sizeof(mDataBuffer));
367*cfb92d14SAndroid Build Coastguard Worker             mTxFrameBuffer.OutFrameRead(mOutputDataLength, mDataBuffer);
368*cfb92d14SAndroid Build Coastguard Worker 
369*cfb92d14SAndroid Build Coastguard Worker             if (!SpinelEncrypter::EncryptOutbound(mDataBuffer, sizeof(mDataBuffer), &mOutputDataLength))
370*cfb92d14SAndroid Build Coastguard Worker             {
371*cfb92d14SAndroid Build Coastguard Worker                 mOutputDataLength = 0;
372*cfb92d14SAndroid Build Coastguard Worker                 status            = OT_ERROR_FAILED;
373*cfb92d14SAndroid Build Coastguard Worker             }
374*cfb92d14SAndroid Build Coastguard Worker         }
375*cfb92d14SAndroid Build Coastguard Worker         else
376*cfb92d14SAndroid Build Coastguard Worker         {
377*cfb92d14SAndroid Build Coastguard Worker             status = OT_ERROR_FAILED;
378*cfb92d14SAndroid Build Coastguard Worker         }
379*cfb92d14SAndroid Build Coastguard Worker     }
380*cfb92d14SAndroid Build Coastguard Worker 
381*cfb92d14SAndroid Build Coastguard Worker     return status;
382*cfb92d14SAndroid Build Coastguard Worker }
383*cfb92d14SAndroid Build Coastguard Worker 
OutFrameHasEnded(void)384*cfb92d14SAndroid Build Coastguard Worker bool NcpHdlc::BufferEncrypterReader::OutFrameHasEnded(void) { return (mDataBufferReadIndex >= mOutputDataLength); }
385*cfb92d14SAndroid Build Coastguard Worker 
OutFrameReadByte(void)386*cfb92d14SAndroid Build Coastguard Worker uint8_t NcpHdlc::BufferEncrypterReader::OutFrameReadByte(void) { return mDataBuffer[mDataBufferReadIndex++]; }
387*cfb92d14SAndroid Build Coastguard Worker 
OutFrameRemove(void)388*cfb92d14SAndroid Build Coastguard Worker otError NcpHdlc::BufferEncrypterReader::OutFrameRemove(void) { return mTxFrameBuffer.OutFrameRemove(); }
389*cfb92d14SAndroid Build Coastguard Worker 
Reset(void)390*cfb92d14SAndroid Build Coastguard Worker void NcpHdlc::BufferEncrypterReader::Reset(void)
391*cfb92d14SAndroid Build Coastguard Worker {
392*cfb92d14SAndroid Build Coastguard Worker     mOutputDataLength    = 0;
393*cfb92d14SAndroid Build Coastguard Worker     mDataBufferReadIndex = 0;
394*cfb92d14SAndroid Build Coastguard Worker }
395*cfb92d14SAndroid Build Coastguard Worker 
396*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
397*cfb92d14SAndroid Build Coastguard Worker 
398*cfb92d14SAndroid Build Coastguard Worker } // namespace Ncp
399*cfb92d14SAndroid Build Coastguard Worker } // namespace ot
400*cfb92d14SAndroid Build Coastguard Worker 
401*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_CONFIG_NCP_HDLC_ENABLE
402