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