1 /*
2  *    Copyright (c) 2016, The OpenThread Authors.
3  *    All rights reserved.
4  *
5  *    Redistribution and use in source and binary forms, with or without
6  *    modification, are permitted provided that the following conditions are met:
7  *    1. Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *    2. Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *    3. Neither the name of the copyright holder nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  *    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  *    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  *    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20  *    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  *    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  *    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  *    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  *    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 /**
29  * @file
30  *   This file contains definitions for a HDLC based NCP interface to the OpenThread stack.
31  */
32 
33 #ifndef NCP_HDLC_HPP_
34 #define NCP_HDLC_HPP_
35 
36 #include "openthread-core-config.h"
37 
38 #include "lib/hdlc/hdlc.hpp"
39 #include "lib/spinel/multi_frame_buffer.hpp"
40 #include "ncp/ncp_base.hpp"
41 
42 #if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
43 #include "lib/spinel/spinel_encrypter.hpp"
44 #endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
45 
46 namespace ot {
47 namespace Ncp {
48 
49 class NcpHdlc : public NcpBase
50 {
51     typedef NcpBase super_t;
52 
53 public:
54     /**
55      * Constructor
56      *
57      * @param[in]  aInstance  The OpenThread instance structure.
58      *
59      */
60     explicit NcpHdlc(Instance *aInstance, otNcpHdlcSendCallback aSendCallback);
61 
62 #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE && OPENTHREAD_RADIO
63     /**
64      * Constructor
65      *
66      * @param[in]  aInstancs      The OpenThread instance pointers array.
67      * @param[in]  aCount         Number of instances in the array.
68      * @param[in]  aSendCallback  Callback for sending data.
69      *
70      */
71     explicit NcpHdlc(Instance **aInstances, uint8_t aCount, otNcpHdlcSendCallback aSendCallback);
72 
73 #endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE && OPENTHREAD_RADIO
74 
75     /**
76      * Is called when uart tx is finished. It prepares and sends the next data chunk (if any) to uart.
77      *
78      */
79     void HandleHdlcSendDone(void);
80 
81     /**
82      * Is called when uart received a data buffer.
83      *
84      */
85     void HandleHdlcReceiveDone(const uint8_t *aBuf, uint16_t aBufLength);
86 
87 private:
88     enum
89     {
90         kHdlcTxBufferSize = OPENTHREAD_CONFIG_NCP_HDLC_TX_CHUNK_SIZE,   // HDLC tx buffer size.
91         kRxBufferSize     = OPENTHREAD_CONFIG_NCP_HDLC_RX_BUFFER_SIZE + // Rx buffer size (should be large enough to fit
92                         OPENTHREAD_CONFIG_NCP_SPINEL_ENCRYPTER_EXTRA_DATA_SIZE, // one whole (decoded) received frame).
93     };
94 
95     enum HdlcTxState
96     {
97         kStartingFrame,   // Starting a new frame.
98         kEncodingFrame,   // In middle of encoding a frame.
99         kFinalizingFrame, // Finalizing a frame.
100     };
101 
102 #if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
103     /**
104      * Wraps Spinel::Buffer allowing to read data through spinel encrypter.
105      * Creates additional buffers to allow transforming of the whole spinel frames.
106      */
107     class BufferEncrypterReader
108     {
109     public:
110         /**
111          * C-tor.
112          * Takes a reference to Spinel::Buffer in order to read spinel frames.
113          */
114         explicit BufferEncrypterReader(Spinel::Buffer &aTxFrameBuffer);
115         bool    IsEmpty(void) const;
116         otError OutFrameBegin(void);
117         bool    OutFrameHasEnded(void);
118         uint8_t OutFrameReadByte(void);
119         otError OutFrameRemove(void);
120 
121     private:
122         void Reset(void);
123 
124         Spinel::Buffer &mTxFrameBuffer;
125         uint8_t         mDataBuffer[kRxBufferSize];
126         size_t          mDataBufferReadIndex;
127         size_t          mOutputDataLength;
128     };
129 #endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
130 
131     void EncodeAndSend(void);
132     void HandleFrame(otError aError);
133     void HandleError(otError aError, uint8_t *aBuf, uint16_t aBufLength);
134     void TxFrameBufferHasData(void);
135     void HandleFrameAddedToNcpBuffer(void);
136 
137     static void           EncodeAndSend(Tasklet &aTasklet);
138     static void           HandleFrame(void *aContext, otError aError);
139     static void           HandleFrameAddedToNcpBuffer(void                    *aContext,
140                                                       Spinel::Buffer::FrameTag aTag,
141                                                       Spinel::Buffer::Priority aPriority,
142                                                       Spinel::Buffer          *aBuffer);
143     otNcpHdlcSendCallback mSendCallback;
144 
145     Spinel::FrameBuffer<kHdlcTxBufferSize> mHdlcBuffer;
146     Hdlc::Encoder                          mFrameEncoder;
147     Hdlc::Decoder                          mFrameDecoder;
148     HdlcTxState                            mState;
149     uint8_t                                mByte;
150     Spinel::FrameBuffer<kRxBufferSize>     mRxBuffer;
151     bool                                   mHdlcSendImmediate;
152     Tasklet                                mHdlcSendTask;
153 
154 #if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
155     BufferEncrypterReader mTxFrameBufferEncrypterReader;
156 #endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
157 };
158 
159 } // namespace Ncp
160 } // namespace ot
161 
162 #endif // NCP_HDLC_HPP_
163