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