1 /*
2  *  Copyright (c) 2018, 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"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <ctype.h>
30 
31 #include "common/code_utils.hpp"
32 #include "common/instance.hpp"
33 #include "lib/hdlc/hdlc.hpp"
34 
35 #include "test_util.h"
36 
37 namespace ot {
38 namespace Ncp {
39 
40 enum
41 {
42     kBufferSize        = 1500,  // Frame buffer size
43     kMaxFrameLength    = 500,   // Maximum allowed frame length (used when randomly generating frames)
44     kFuzzTestIteration = 50000, // Number of iteration during fuzz test (randomly generating frames)
45     kFrameHeaderSize   = 4,     // Frame header size
46 
47     kFlagXOn        = 0x11,
48     kFlagXOff       = 0x13,
49     kFlagSequence   = 0x7e, ///< HDLC Flag value
50     kEscapeSequence = 0x7d, ///< HDLC Escape value
51     kFlagSpecial    = 0xf8,
52 
53 };
54 
55 static const uint8_t sOpenThreadText[] = "OpenThread Rocks";
56 static const uint8_t sHelloText[]      = "Hello there!";
57 static const uint8_t sMottoText[]      = "Think good thoughts, say good words, do good deeds!";
58 static const uint8_t sHexText[]        = "0123456789abcdef";
59 static const uint8_t sSkipText[]       = "Skip text";
60 static const uint8_t sHdlcSpecials[]   = {kFlagSequence, kFlagXOn,        kFlagXOff,
61                                         kFlagSequence, kEscapeSequence, kFlagSpecial};
62 
WriteToBuffer(const uint8_t * aText,Hdlc::FrameWritePointer & aWritePointer)63 otError WriteToBuffer(const uint8_t *aText, Hdlc::FrameWritePointer &aWritePointer)
64 {
65     otError error = OT_ERROR_NONE;
66 
67     while (*aText != 0)
68     {
69         SuccessOrExit(aWritePointer.WriteByte(*aText++));
70     }
71 
72 exit:
73     return error;
74 }
75 
TestHdlcFrameBuffer(void)76 void TestHdlcFrameBuffer(void)
77 {
78     Hdlc::FrameBuffer<kBufferSize> frameBuffer;
79 
80     printf("Testing Hdlc::FrameBuffer");
81 
82     VerifyOrQuit(frameBuffer.IsEmpty(), "after constructor");
83     VerifyOrQuit(frameBuffer.GetLength() == 0, "after constructor");
84 
85     SuccessOrQuit(WriteToBuffer(sOpenThreadText, frameBuffer));
86 
87     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sOpenThreadText) - 1);
88     VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sOpenThreadText, frameBuffer.GetLength()) == 0);
89 
90     VerifyOrQuit(frameBuffer.CanWrite(1));
91     VerifyOrQuit(!frameBuffer.IsEmpty());
92 
93     SuccessOrQuit(WriteToBuffer(sHelloText, frameBuffer));
94     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sOpenThreadText) + sizeof(sHelloText) - 2);
95 
96     frameBuffer.UndoLastWrites(sizeof(sHelloText) - 1);
97     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sOpenThreadText) - 1);
98     VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sOpenThreadText, frameBuffer.GetLength()) == 0);
99 
100     VerifyOrQuit(!frameBuffer.IsEmpty());
101     frameBuffer.Clear();
102     VerifyOrQuit(frameBuffer.IsEmpty(), "after Clear()");
103     VerifyOrQuit(frameBuffer.GetLength() == 0, "after Clear()");
104 
105     SuccessOrQuit(WriteToBuffer(sMottoText, frameBuffer));
106 
107     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sMottoText) - 1);
108     VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sMottoText, frameBuffer.GetLength()) == 0);
109 
110     frameBuffer.Clear();
111     VerifyOrQuit(frameBuffer.CanWrite(kBufferSize));
112     VerifyOrQuit(frameBuffer.CanWrite(kBufferSize + 1) == false, "CanWrite(kBufferSize + 1) did not fail as expected");
113 
114     for (uint16_t i = 0; i < kBufferSize; i++)
115     {
116         VerifyOrQuit(frameBuffer.CanWrite(1));
117         SuccessOrQuit(frameBuffer.WriteByte(i & 0xff));
118     }
119 
120     VerifyOrQuit(frameBuffer.CanWrite(1) == false, "did not fail with full buffer");
121     VerifyOrQuit(frameBuffer.WriteByte(0) == OT_ERROR_NO_BUFS, "did not fail with full buffer");
122 
123     printf(" -- PASS\n");
124 }
125 
TestHdlcMultiFrameBuffer(void)126 void TestHdlcMultiFrameBuffer(void)
127 {
128     Hdlc::MultiFrameBuffer<kBufferSize> frameBuffer;
129     uint8_t *                           frame    = nullptr;
130     uint8_t *                           newFrame = nullptr;
131     uint16_t                            length;
132     uint16_t                            newLength;
133 
134     printf("Testing Hdlc::MultiFrameBuffer");
135 
136     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
137     // Check state after constructor
138 
139     VerifyOrQuit(!frameBuffer.HasFrame(), "after constructor");
140     VerifyOrQuit(!frameBuffer.HasSavedFrame(), "after constructor");
141     VerifyOrQuit(frameBuffer.GetLength() == 0, "after constructor");
142     VerifyOrQuit(frameBuffer.GetNextSavedFrame(frame, length) == OT_ERROR_NOT_FOUND, "after constructor");
143 
144     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
145     // Write multiple frames, save them and read later
146 
147     SuccessOrQuit(WriteToBuffer(sMottoText, frameBuffer));
148 
149     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sMottoText) - 1);
150     VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sMottoText, frameBuffer.GetLength()) == 0);
151 
152     frameBuffer.SaveFrame();
153 
154     VerifyOrQuit(!frameBuffer.HasFrame(), "after SaveFrame()");
155     VerifyOrQuit(frameBuffer.HasSavedFrame(), "after SaveFrame()");
156     VerifyOrQuit(frameBuffer.GetLength() == 0, "after SaveFrame()");
157 
158     SuccessOrQuit(WriteToBuffer(sHelloText, frameBuffer));
159     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sHelloText) - 1);
160     VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sHelloText, frameBuffer.GetLength()) == 0);
161 
162     frameBuffer.SaveFrame();
163 
164     VerifyOrQuit(!frameBuffer.HasFrame(), "after SaveFrame()");
165     VerifyOrQuit(frameBuffer.HasSavedFrame(), "after SaveFrame()");
166     VerifyOrQuit(frameBuffer.GetLength() == 0, "after SaveFrame()");
167 
168     SuccessOrQuit(WriteToBuffer(sOpenThreadText, frameBuffer));
169     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sOpenThreadText) - 1);
170     VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sOpenThreadText, frameBuffer.GetLength()) == 0);
171 
172     frameBuffer.DiscardFrame();
173 
174     VerifyOrQuit(!frameBuffer.HasFrame(), "after DiscardFrame()");
175     VerifyOrQuit(frameBuffer.HasSavedFrame(), "after SaveFrame()");
176     VerifyOrQuit(frameBuffer.GetLength() == 0, "after DiscardFrame()");
177 
178     SuccessOrQuit(WriteToBuffer(sMottoText, frameBuffer));
179     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sMottoText) - 1);
180     VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sMottoText, frameBuffer.GetLength()) == 0);
181 
182     frameBuffer.DiscardFrame();
183 
184     VerifyOrQuit(!frameBuffer.HasFrame(), "after DiscardFrame()");
185     VerifyOrQuit(frameBuffer.GetLength() == 0, "after DiscardFrame()");
186 
187     SuccessOrQuit(WriteToBuffer(sHexText, frameBuffer));
188     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sHexText) - 1);
189     VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sHexText, frameBuffer.GetLength()) == 0);
190 
191     frameBuffer.SaveFrame();
192 
193     VerifyOrQuit(!frameBuffer.HasFrame(), "after SaveFrame()");
194     VerifyOrQuit(frameBuffer.HasSavedFrame(), "after SaveFrame()");
195     VerifyOrQuit(frameBuffer.GetLength() == 0, "after SaveFrame()");
196 
197     SuccessOrQuit(WriteToBuffer(sOpenThreadText, frameBuffer));
198     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sOpenThreadText) - 1);
199     VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sOpenThreadText, frameBuffer.GetLength()) == 0);
200 
201     // Read the first saved frame and check the content
202     frame = nullptr;
203     SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length));
204     VerifyOrQuit(length == sizeof(sMottoText) - 1, "GetNextSavedFrame() length is incorrect");
205     VerifyOrQuit(memcmp(frame, sMottoText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
206 
207     // Read the second saved frame and check the content
208     SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length));
209     VerifyOrQuit(length == sizeof(sHelloText) - 1, "GetNextSavedFrame() length is incorrect");
210     VerifyOrQuit(memcmp(frame, sHelloText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
211 
212     // Read the third saved frame and check the content
213     SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length));
214     VerifyOrQuit(length == sizeof(sHexText) - 1, "GetNextSavedFrame() length is incorrect");
215     VerifyOrQuit(memcmp(frame, sHexText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
216 
217     newFrame  = frame;
218     newLength = length;
219     VerifyOrQuit(frameBuffer.GetNextSavedFrame(newFrame, newLength) == OT_ERROR_NOT_FOUND,
220                  "GetNextSavedFrame() incorrect behavior after all frames were read");
221     VerifyOrQuit(newFrame == nullptr, "GetNextSavedFrame() incorrect behavior after all frames were read");
222 
223     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sOpenThreadText) - 1);
224     VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sOpenThreadText, frameBuffer.GetLength()) == 0,
225                  "GetFrame() content is incorrect");
226 
227     frameBuffer.SaveFrame();
228 
229     // Read the fourth saved frame and check the content
230     SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length));
231     VerifyOrQuit(length == sizeof(sOpenThreadText) - 1, "GetNextSavedFrame() length is incorrect");
232     VerifyOrQuit(memcmp(frame, sOpenThreadText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
233 
234     // Re-read all the saved frames
235     frame = nullptr;
236     SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length));
237     VerifyOrQuit(length == sizeof(sMottoText) - 1, "GetNextSavedFrame() length is incorrect");
238     VerifyOrQuit(memcmp(frame, sMottoText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
239 
240     // Second saved frame
241     SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length));
242     VerifyOrQuit(length == sizeof(sHelloText) - 1, "GetNextSavedFrame() length is incorrect");
243     VerifyOrQuit(memcmp(frame, sHelloText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
244 
245     // Third saved frame
246     SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length));
247     VerifyOrQuit(length == sizeof(sHexText) - 1, "GetNextSavedFrame() length is incorrect");
248     VerifyOrQuit(memcmp(frame, sHexText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
249 
250     // Fourth saved frame and check the content
251     SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length));
252     VerifyOrQuit(length == sizeof(sOpenThreadText) - 1, "GetNextSavedFrame() length is incorrect");
253     VerifyOrQuit(memcmp(frame, sOpenThreadText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
254 
255     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
256     // Verify behavior of `Clear()`
257 
258     frameBuffer.Clear();
259 
260     VerifyOrQuit(!frameBuffer.HasFrame(), "after Clear()");
261     VerifyOrQuit(!frameBuffer.HasSavedFrame(), "after Clear()");
262     VerifyOrQuit(frameBuffer.GetLength() == 0, "after Clear()");
263 
264     SuccessOrQuit(WriteToBuffer(sOpenThreadText, frameBuffer));
265     frameBuffer.SaveFrame();
266 
267     SuccessOrQuit(WriteToBuffer(sHelloText, frameBuffer));
268     frameBuffer.SaveFrame();
269     VerifyOrQuit(frameBuffer.HasSavedFrame(), "after SaveFrame()");
270 
271     frame = nullptr;
272     SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length));
273     VerifyOrQuit(frameBuffer.HasSavedFrame(), "after GetNextSavedFrame()");
274 
275     frameBuffer.Clear();
276 
277     frame = nullptr;
278     VerifyOrQuit(frameBuffer.GetNextSavedFrame(frame, length) == OT_ERROR_NOT_FOUND, "after Clear()");
279 
280     VerifyOrQuit(!frameBuffer.HasFrame(), "after Clear()");
281     VerifyOrQuit(!frameBuffer.HasSavedFrame(), "after Clear()");
282     VerifyOrQuit(frameBuffer.CanWrite(kBufferSize - (kFrameHeaderSize - 1)) == false, "after Clear()");
283     VerifyOrQuit(frameBuffer.CanWrite(kBufferSize - kFrameHeaderSize) == true, "after Clear()");
284 
285     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
286     // Verify behavior of `ClearSavedFrames()`
287 
288     SuccessOrQuit(WriteToBuffer(sHelloText, frameBuffer));
289     frameBuffer.SaveFrame();
290     SuccessOrQuit(WriteToBuffer(sOpenThreadText, frameBuffer));
291     frameBuffer.SaveFrame();
292     SuccessOrQuit(WriteToBuffer(sMottoText, frameBuffer));
293     frameBuffer.SaveFrame();
294     SuccessOrQuit(WriteToBuffer(sHexText, frameBuffer));
295 
296     frame = nullptr;
297     SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length));
298     VerifyOrQuit(length == sizeof(sHelloText) - 1, "GetNextSavedFrame() length is incorrect");
299     VerifyOrQuit(memcmp(frame, sHelloText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
300 
301     frameBuffer.ClearSavedFrames();
302 
303     VerifyOrQuit(frameBuffer.HasFrame(), "after ClearSavedFrames()");
304     VerifyOrQuit(!frameBuffer.HasSavedFrame(), "after ClearSavedFrames()");
305 
306     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sHexText) - 1, "after ClearSavedFrames()");
307     VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sHexText, frameBuffer.GetLength()) == 0);
308 
309     frameBuffer.SaveFrame();
310 
311     SuccessOrQuit(WriteToBuffer(sHelloText, frameBuffer));
312 
313     frame = nullptr;
314     SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length));
315     VerifyOrQuit(length == sizeof(sHexText) - 1, "GetNextSavedFrame() length is incorrect");
316     VerifyOrQuit(memcmp(frame, sHexText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
317 
318     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sHelloText) - 1, "after ClearSavedFrames()");
319     VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sHelloText, frameBuffer.GetLength()) == 0, "after ClearSavedFrames()");
320 
321     frameBuffer.ClearSavedFrames();
322     frameBuffer.DiscardFrame();
323 
324     VerifyOrQuit(!frameBuffer.HasFrame(), "after all frames are read and discarded");
325     VerifyOrQuit(!frameBuffer.HasSavedFrame(), "after all read or discarded");
326     VerifyOrQuit(frameBuffer.CanWrite(kBufferSize - (kFrameHeaderSize - 1)) == false, "after all read or discarded");
327     VerifyOrQuit(frameBuffer.CanWrite(kBufferSize - kFrameHeaderSize) == true, "after all read of discarded");
328 
329     SuccessOrQuit(WriteToBuffer(sHelloText, frameBuffer));
330 
331     frameBuffer.ClearSavedFrames();
332 
333     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sHelloText) - 1);
334     VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sHelloText, frameBuffer.GetLength()) == 0);
335 
336     frameBuffer.SaveFrame();
337     frame = nullptr;
338     SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length));
339     VerifyOrQuit(length == sizeof(sHelloText) - 1, "GetNextSavedFrame() length is incorrect");
340     VerifyOrQuit(memcmp(frame, sHelloText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
341 
342     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
343     // Verify behavior of `SetSkipLength()` and `GetSkipLength()`
344 
345     frameBuffer.Clear();
346 
347     VerifyOrQuit(frameBuffer.GetSkipLength() == 0, "after Clear()");
348     VerifyOrQuit(frameBuffer.SetSkipLength(sizeof(sSkipText)) == OT_ERROR_NONE);
349     SuccessOrQuit(WriteToBuffer(sMottoText, frameBuffer));
350     VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sMottoText, frameBuffer.GetLength()) == 0);
351     memcpy(frameBuffer.GetFrame() - sizeof(sSkipText), sSkipText, sizeof(sSkipText));
352     VerifyOrQuit(frameBuffer.GetSkipLength() == sizeof(sSkipText));
353     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sMottoText) - 1);
354     VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sMottoText, frameBuffer.GetLength()) == 0);
355 
356     frameBuffer.SaveFrame();
357     VerifyOrQuit(!frameBuffer.HasFrame(), "after SaveFrame()");
358     VerifyOrQuit(frameBuffer.HasSavedFrame(), "after SaveFrame()");
359     VerifyOrQuit(frameBuffer.GetSkipLength() == 0, "after SaveFrame()");
360 
361     VerifyOrQuit(frameBuffer.SetSkipLength(sizeof(sSkipText)) == OT_ERROR_NONE);
362     SuccessOrQuit(WriteToBuffer(sOpenThreadText, frameBuffer));
363     VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sOpenThreadText, frameBuffer.GetLength()) == 0);
364     memcpy(frameBuffer.GetFrame() - sizeof(sSkipText), sSkipText, sizeof(sSkipText));
365     VerifyOrQuit(frameBuffer.GetSkipLength() == sizeof(sSkipText));
366     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sOpenThreadText) - 1);
367     VerifyOrQuit(memcmp(frameBuffer.GetFrame(), sOpenThreadText, frameBuffer.GetLength()) == 0);
368 
369     frameBuffer.SaveFrame();
370     VerifyOrQuit(!frameBuffer.HasFrame(), "after SaveFrame()");
371     VerifyOrQuit(frameBuffer.HasSavedFrame(), "after SaveFrame()");
372     VerifyOrQuit(frameBuffer.GetSkipLength() == 0, "after SaveFrame()");
373 
374     frame = nullptr;
375     SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length));
376     VerifyOrQuit(length == sizeof(sMottoText) - 1, "GetNextSavedFrame() length is incorrect");
377     VerifyOrQuit(memcmp(frame, sMottoText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
378     VerifyOrQuit(memcmp(frame - sizeof(sSkipText), sSkipText, sizeof(sSkipText)) == 0,
379                  "GetNextSavedFrame() reserved frame buffer content is incorrect");
380 
381     SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length));
382     VerifyOrQuit(length == sizeof(sOpenThreadText) - 1, "GetNextSavedFrame() length is incorrect");
383     VerifyOrQuit(memcmp(frame, sOpenThreadText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
384     VerifyOrQuit(memcmp(frame - sizeof(sSkipText), sSkipText, sizeof(sSkipText)) == 0,
385                  "GetNextSavedFrame() reserved frame buffer content is incorrect");
386 
387     frameBuffer.Clear();
388     VerifyOrQuit(frameBuffer.SetSkipLength(kBufferSize - (kFrameHeaderSize - 1)) == OT_ERROR_NO_BUFS, "after Clear()");
389     VerifyOrQuit(frameBuffer.SetSkipLength(kBufferSize - kFrameHeaderSize) == OT_ERROR_NONE, "after Clear()");
390 
391     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
392     // Verify behavior of `SetLength()` and `GetLength()`
393 
394     frameBuffer.Clear();
395     VerifyOrQuit((frame = frameBuffer.GetFrame()) != nullptr);
396     memcpy(frame, sHelloText, sizeof(sHelloText));
397     VerifyOrQuit(frameBuffer.SetLength(sizeof(sHelloText)) == OT_ERROR_NONE);
398     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sHelloText));
399     VerifyOrQuit(frameBuffer.HasFrame());
400     frameBuffer.SaveFrame();
401 
402     VerifyOrQuit((frame = frameBuffer.GetFrame()) != nullptr);
403     memcpy(frame, sMottoText, sizeof(sMottoText));
404     VerifyOrQuit(frameBuffer.SetLength(sizeof(sMottoText)) == OT_ERROR_NONE);
405     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sMottoText));
406     VerifyOrQuit(frameBuffer.HasFrame());
407     frameBuffer.SaveFrame();
408 
409     VerifyOrQuit((frame = frameBuffer.GetFrame()) != nullptr);
410     memcpy(frame, sHexText, sizeof(sHexText));
411     VerifyOrQuit(frameBuffer.SetLength(sizeof(sHexText)) == OT_ERROR_NONE);
412     VerifyOrQuit(frameBuffer.GetLength() == sizeof(sHexText));
413     frameBuffer.DiscardFrame();
414     VerifyOrQuit(!frameBuffer.HasFrame());
415 
416     frame = nullptr;
417     SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length));
418     VerifyOrQuit(length == sizeof(sHelloText), "GetNextSavedFrame() length is incorrect");
419     VerifyOrQuit(memcmp(frame, sHelloText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
420 
421     SuccessOrQuit(frameBuffer.GetNextSavedFrame(frame, length));
422     VerifyOrQuit(length == sizeof(sMottoText), "GetNextSavedFrame() length is incorrect");
423     VerifyOrQuit(memcmp(frame, sMottoText, length) == 0, "GetNextSavedFrame() frame content is incorrect");
424 
425     SuccessOrQuit(!frameBuffer.GetNextSavedFrame(frame, length));
426 
427     frameBuffer.Clear();
428     VerifyOrQuit(frameBuffer.SetLength(kBufferSize - (kFrameHeaderSize - 1)) == OT_ERROR_NO_BUFS, "after Clear()");
429     VerifyOrQuit(frameBuffer.SetLength(kBufferSize - kFrameHeaderSize) == OT_ERROR_NONE, "after Clear()");
430 
431     printf(" -- PASS\n");
432 }
433 
434 struct DecoderContext
435 {
436     bool    mWasCalled;
437     otError mError;
438 };
439 
ProcessDecodedFrame(void * aContext,otError aError)440 void ProcessDecodedFrame(void *aContext, otError aError)
441 {
442     DecoderContext &decoderContext = *static_cast<DecoderContext *>(aContext);
443 
444     decoderContext.mError     = aError;
445     decoderContext.mWasCalled = true;
446 }
447 
TestEncoderDecoder(void)448 void TestEncoderDecoder(void)
449 {
450     otError                             error;
451     uint8_t                             byte;
452     Hdlc::MultiFrameBuffer<kBufferSize> encoderBuffer;
453     Hdlc::MultiFrameBuffer<kBufferSize> decoderBuffer;
454     DecoderContext                      decoderContext;
455     Hdlc::Encoder                       encoder(encoderBuffer);
456     Hdlc::Decoder                       decoder(decoderBuffer, ProcessDecodedFrame, &decoderContext);
457     uint8_t *                           frame;
458     uint16_t                            length;
459     uint8_t                             badShortFrame[3] = {kFlagSequence, 0xaa, kFlagSequence};
460 
461     printf("Testing Hdlc::Encoder and Hdlc::Decoder");
462 
463     SuccessOrQuit(encoder.BeginFrame());
464     SuccessOrQuit(encoder.Encode(sOpenThreadText, sizeof(sOpenThreadText) - 1));
465     SuccessOrQuit(encoder.EndFrame());
466     encoderBuffer.SaveFrame();
467 
468     SuccessOrQuit(encoder.BeginFrame());
469     SuccessOrQuit(encoder.Encode(sMottoText, sizeof(sMottoText) - 1));
470     SuccessOrQuit(encoder.EndFrame());
471     encoderBuffer.SaveFrame();
472 
473     SuccessOrQuit(encoder.BeginFrame());
474     SuccessOrQuit(encoder.Encode(sHdlcSpecials, sizeof(sHdlcSpecials)));
475     SuccessOrQuit(encoder.EndFrame());
476     encoderBuffer.SaveFrame();
477 
478     SuccessOrQuit(encoder.BeginFrame());
479     SuccessOrQuit(encoder.Encode(sHelloText, sizeof(sHelloText) - 1));
480     SuccessOrQuit(encoder.EndFrame());
481     encoderBuffer.SaveFrame();
482 
483     SuccessOrQuit(encoder.BeginFrame());
484     // Empty frame
485     SuccessOrQuit(encoder.EndFrame());
486     encoderBuffer.SaveFrame();
487 
488     byte = kFlagSequence;
489     SuccessOrQuit(encoder.BeginFrame());
490     SuccessOrQuit(encoder.Encode(&byte, sizeof(uint8_t)));
491     SuccessOrQuit(encoder.EndFrame());
492     encoderBuffer.SaveFrame();
493 
494     // Feed the encoded frames to decoder and save the content
495     for (frame = nullptr; encoderBuffer.GetNextSavedFrame(frame, length) == OT_ERROR_NONE;)
496     {
497         decoderContext.mWasCalled = false;
498 
499         decoder.Decode(frame, length);
500 
501         VerifyOrQuit(decoderContext.mWasCalled);
502         VerifyOrQuit(decoderContext.mError == OT_ERROR_NONE, "Decoder::Decode() returned incorrect error code");
503 
504         decoderBuffer.SaveFrame();
505     }
506 
507     // Verify the decoded frames match the original frames
508     frame = nullptr;
509     SuccessOrQuit(decoderBuffer.GetNextSavedFrame(frame, length));
510     VerifyOrQuit(length == sizeof(sOpenThreadText) - 1, "Decoded frame length does not match original frame");
511     VerifyOrQuit(memcmp(frame, sOpenThreadText, length) == 0, "Decoded frame content does not match original frame");
512 
513     SuccessOrQuit(decoderBuffer.GetNextSavedFrame(frame, length));
514     VerifyOrQuit(length == sizeof(sMottoText) - 1, "Decoded frame length does not match original frame");
515     VerifyOrQuit(memcmp(frame, sMottoText, length) == 0, "Decoded frame content does not match original frame");
516 
517     SuccessOrQuit(decoderBuffer.GetNextSavedFrame(frame, length));
518     VerifyOrQuit(length == sizeof(sHdlcSpecials), "Decoded frame length does not match original frame");
519     VerifyOrQuit(memcmp(frame, sHdlcSpecials, length) == 0, "Decoded frame content does not match original frame");
520 
521     SuccessOrQuit(decoderBuffer.GetNextSavedFrame(frame, length));
522     VerifyOrQuit(length == sizeof(sHelloText) - 1, "Decoded frame length does not match original frame");
523     VerifyOrQuit(memcmp(frame, sHelloText, length) == 0, "Decoded frame content does not match original frame");
524 
525     SuccessOrQuit(decoderBuffer.GetNextSavedFrame(frame, length));
526     VerifyOrQuit(length == 0, "Decoded frame length does not match original frame");
527 
528     SuccessOrQuit(decoderBuffer.GetNextSavedFrame(frame, length));
529     VerifyOrQuit(length == sizeof(uint8_t), "Decoded frame length does not match original frame");
530     VerifyOrQuit(*frame == kFlagSequence, "Decoded frame content does not match original frame");
531 
532     VerifyOrQuit(decoderBuffer.GetNextSavedFrame(frame, length) == OT_ERROR_NOT_FOUND, "Extra decoded frame");
533 
534     encoderBuffer.Clear();
535     decoderBuffer.Clear();
536 
537     // Test `Encoder` behavior when running out of buffer space
538     SuccessOrQuit(encoder.BeginFrame());
539 
540     error = OT_ERROR_NONE;
541 
542     for (uint16_t i = 0; error == OT_ERROR_NONE; i++)
543     {
544         byte  = i & 0xff;
545         error = encoder.Encode(&byte, sizeof(uint8_t));
546     }
547 
548     VerifyOrQuit(encoder.Encode(&byte, sizeof(uint8_t)) == OT_ERROR_NO_BUFS,
549                  "Encoder::Encode() did not fail with a full buffer");
550     VerifyOrQuit(encoder.EndFrame(), "Encoder::EndFrame() did not fail with a full buffer");
551 
552     encoderBuffer.Clear();
553 
554     // Test `Decoder` behavior with incorrect FCS
555 
556     SuccessOrQuit(encoder.BeginFrame());
557     SuccessOrQuit(encoder.Encode(sMottoText, sizeof(sMottoText) - 1));
558     SuccessOrQuit(encoder.EndFrame());
559 
560     encoderBuffer.GetFrame()[0] ^= 0x0a; // Change the first byte in the frame to cause FCS failure
561 
562     decoderContext.mWasCalled = false;
563     decoder.Decode(encoderBuffer.GetFrame(), encoderBuffer.GetLength());
564     VerifyOrQuit(decoderContext.mWasCalled);
565     VerifyOrQuit(decoderContext.mError == OT_ERROR_PARSE, "Decoder::Decode() did not fail with bad FCS");
566 
567     decoderBuffer.Clear();
568 
569     // Test `Decoder` behavior with short frame (smaller than FCS)
570 
571     decoderContext.mWasCalled = false;
572     decoder.Decode(badShortFrame, sizeof(badShortFrame));
573     VerifyOrQuit(decoderContext.mWasCalled);
574     VerifyOrQuit(decoderContext.mError == OT_ERROR_PARSE, "Decoder::Decode() did not fail for short frame");
575 
576     decoderBuffer.Clear();
577 
578     // Test `Decoder` with back to back `kFlagSequence` and ensure callback is not invoked.
579 
580     byte                      = kFlagSequence;
581     decoderContext.mWasCalled = false;
582     decoder.Decode(&byte, sizeof(uint8_t));
583     VerifyOrQuit(!decoderContext.mWasCalled);
584     decoder.Decode(&byte, sizeof(uint8_t));
585     VerifyOrQuit(!decoderContext.mWasCalled);
586     decoder.Decode(&byte, sizeof(uint8_t));
587     VerifyOrQuit(!decoderContext.mWasCalled);
588     decoder.Decode(&byte, sizeof(uint8_t));
589     VerifyOrQuit(!decoderContext.mWasCalled);
590 
591     printf(" -- PASS\n");
592 }
593 
GetRandom(uint32_t max)594 uint32_t GetRandom(uint32_t max)
595 {
596     return static_cast<uint32_t>(rand()) % max;
597 }
598 
TestFuzzEncoderDecoder(void)599 void TestFuzzEncoderDecoder(void)
600 {
601     uint16_t                       length;
602     uint8_t                        frame[kMaxFrameLength];
603     Hdlc::FrameBuffer<kBufferSize> encoderBuffer;
604     Hdlc::FrameBuffer<kBufferSize> decoderBuffer;
605     DecoderContext                 decoderContext;
606     Hdlc::Encoder                  encoder(encoderBuffer);
607     Hdlc::Decoder                  decoder(decoderBuffer, ProcessDecodedFrame, &decoderContext);
608 
609     printf("Testing Hdlc::Encoder and Hdlc::Decoder with randomly generated frames");
610 
611     for (uint32_t iter = 0; iter < kFuzzTestIteration; iter++)
612     {
613         encoderBuffer.Clear();
614         decoderBuffer.Clear();
615 
616         do
617         {
618             length = static_cast<uint16_t>(GetRandom(kMaxFrameLength));
619         } while (length == 0);
620 
621         for (uint16_t i = 0; i < length; i++)
622         {
623             frame[i] = static_cast<uint8_t>(GetRandom(256));
624         }
625 
626         SuccessOrQuit(encoder.BeginFrame());
627         SuccessOrQuit(encoder.Encode(frame, length));
628         SuccessOrQuit(encoder.EndFrame());
629 
630         VerifyOrQuit(!encoderBuffer.IsEmpty(), "Encoded frame is empty");
631         VerifyOrQuit(encoderBuffer.GetLength() > length, "Encoded frame is too short");
632 
633         decoderContext.mWasCalled = false;
634         decoder.Decode(encoderBuffer.GetFrame(), encoderBuffer.GetLength());
635         VerifyOrQuit(decoderContext.mWasCalled);
636         VerifyOrQuit(decoderContext.mError == OT_ERROR_NONE, "Decoder::Decode() returned incorrect error code");
637 
638         VerifyOrQuit(!decoderBuffer.IsEmpty(), "Decoded frame is empty");
639         VerifyOrQuit(decoderBuffer.GetLength() == length, "Decoded frame length does not match original frame");
640         VerifyOrQuit(memcmp(decoderBuffer.GetFrame(), frame, length) == 0,
641                      "Decoded frame content does not match original frame");
642     }
643 
644     printf(" -- PASS\n");
645 }
646 
647 } // namespace Ncp
648 } // namespace ot
649 
main(void)650 int main(void)
651 {
652     ot::Ncp::TestHdlcFrameBuffer();
653     ot::Ncp::TestHdlcMultiFrameBuffer();
654     ot::Ncp::TestEncoderDecoder();
655     ot::Ncp::TestFuzzEncoderDecoder();
656     printf("\nAll tests passed.\n");
657     return 0;
658 }
659