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     /**
63      * Is called when uart tx is finished. It prepares and sends the next data chunk (if any) to uart.
64      *
65      */
66     void HandleHdlcSendDone(void);
67 
68     /**
69      * Is called when uart received a data buffer.
70      *
71      */
72     void HandleHdlcReceiveDone(const uint8_t *aBuf, uint16_t aBufLength);
73 
74 private:
75     enum
76     {
77         kHdlcTxBufferSize = OPENTHREAD_CONFIG_NCP_HDLC_TX_CHUNK_SIZE,   // HDLC tx buffer size.
78         kRxBufferSize     = OPENTHREAD_CONFIG_NCP_HDLC_RX_BUFFER_SIZE + // Rx buffer size (should be large enough to fit
79                         OPENTHREAD_CONFIG_NCP_SPINEL_ENCRYPTER_EXTRA_DATA_SIZE, // one whole (decoded) received frame).
80     };
81 
82     enum HdlcTxState
83     {
84         kStartingFrame,   // Starting a new frame.
85         kEncodingFrame,   // In middle of encoding a frame.
86         kFinalizingFrame, // Finalizing a frame.
87     };
88 
89 #if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
90     /**
91      * Wraps Spinel::Buffer allowing to read data through spinel encrypter.
92      * Creates additional buffers to allow transforming of the whole spinel frames.
93      */
94     class BufferEncrypterReader
95     {
96     public:
97         /**
98          * C-tor.
99          * Takes a reference to Spinel::Buffer in order to read spinel frames.
100          */
101         explicit BufferEncrypterReader(Spinel::Buffer &aTxFrameBuffer);
102         bool    IsEmpty(void) const;
103         otError OutFrameBegin(void);
104         bool    OutFrameHasEnded(void);
105         uint8_t OutFrameReadByte(void);
106         otError OutFrameRemove(void);
107 
108     private:
109         void Reset(void);
110 
111         Spinel::Buffer &mTxFrameBuffer;
112         uint8_t         mDataBuffer[kRxBufferSize];
113         size_t          mDataBufferReadIndex;
114         size_t          mOutputDataLength;
115     };
116 #endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
117 
118     void EncodeAndSend(void);
119     void HandleFrame(otError aError);
120     void HandleError(otError aError, uint8_t *aBuf, uint16_t aBufLength);
121     void TxFrameBufferHasData(void);
122     void HandleFrameAddedToNcpBuffer(void);
123 
124     static void           EncodeAndSend(Tasklet &aTasklet);
125     static void           HandleFrame(void *aContext, otError aError);
126     static void           HandleFrameAddedToNcpBuffer(void                    *aContext,
127                                                       Spinel::Buffer::FrameTag aTag,
128                                                       Spinel::Buffer::Priority aPriority,
129                                                       Spinel::Buffer          *aBuffer);
130     otNcpHdlcSendCallback mSendCallback;
131 
132     Spinel::FrameBuffer<kHdlcTxBufferSize> mHdlcBuffer;
133     Hdlc::Encoder                          mFrameEncoder;
134     Hdlc::Decoder                          mFrameDecoder;
135     HdlcTxState                            mState;
136     uint8_t                                mByte;
137     Spinel::FrameBuffer<kRxBufferSize>     mRxBuffer;
138     bool                                   mHdlcSendImmediate;
139     Tasklet                                mHdlcSendTask;
140 
141 #if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
142     BufferEncrypterReader mTxFrameBufferEncrypterReader;
143 #endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
144 };
145 
146 } // namespace Ncp
147 } // namespace ot
148 
149 #endif // NCP_HDLC_HPP_
150