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