1 /*
2 * Copyright (c) 2017, 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 "common/code_utils.hpp"
30 #include "instance/instance.hpp"
31 #include "lib/spinel/spinel_encoder.hpp"
32
33 #include "test_util.hpp"
34
35 namespace ot {
36 namespace Spinel {
37
38 enum
39 {
40 kTestBufferSize = 800,
41 };
42
ReadFrame(Spinel::Buffer & aNcpBuffer,uint8_t * aFrame,uint16_t & aFrameLen)43 otError ReadFrame(Spinel::Buffer &aNcpBuffer, uint8_t *aFrame, uint16_t &aFrameLen)
44 {
45 otError error = OT_ERROR_NONE;
46
47 SuccessOrExit(error = aNcpBuffer.OutFrameBegin());
48 aFrameLen = aNcpBuffer.OutFrameGetLength();
49 VerifyOrExit(aNcpBuffer.OutFrameRead(aFrameLen, aFrame) == aFrameLen, error = OT_ERROR_FAILED);
50 SuccessOrExit(error = aNcpBuffer.OutFrameRemove());
51
52 exit:
53 return error;
54 }
55
TestEncoder(void)56 void TestEncoder(void)
57 {
58 uint8_t buffer[kTestBufferSize];
59 Spinel::Buffer ncpBuffer(buffer, kTestBufferSize);
60 Spinel::Encoder encoder(ncpBuffer);
61
62 uint8_t frame[kTestBufferSize];
63 uint16_t frameLen;
64 spinel_ssize_t parsedLen;
65
66 const bool kBool_1 = true;
67 const bool kBool_2 = false;
68 const uint8_t kUint8 = 0x42;
69 const int8_t kInt8 = -73;
70 const uint16_t kUint16 = 0xabcd;
71 const int16_t kInt16 = -567;
72 const uint32_t kUint32 = 0xdeadbeef;
73 const int32_t kInt32 = -123455678L;
74 const uint64_t kUint64 = 0xfe10dc32ba549876ULL;
75 const int64_t kInt64 = -9197712039090021561LL;
76 const unsigned int kUint_1 = 9;
77 const unsigned int kUint_2 = 0xa3;
78 const unsigned int kUint_3 = 0x8765;
79 const unsigned int kUint_4 = SPINEL_MAX_UINT_PACKED - 1;
80
81 const spinel_ipv6addr_t kIp6Addr = {
82 {0x6B, 0x41, 0x65, 0x73, 0x42, 0x68, 0x61, 0x76, 0x54, 0x61, 0x72, 0x7A, 0x49, 0x69, 0x61, 0x4E}};
83
84 const spinel_eui48_t kEui48 = {
85 {4, 8, 15, 16, 23, 42} // "Lost" EUI48!
86 };
87
88 const spinel_eui64_t kEui64 = {
89 {2, 3, 5, 7, 11, 13, 17, 19}, // "Prime" EUI64!
90 };
91
92 const char kString_1[] = "OpenThread";
93 const char kString_2[] = "";
94
95 const uint16_t kData[] = {10, 20, 3, 15, 1000, 60, 16}; // ... then comes 17,18,19,20 :)
96
97 bool b_1, b_2;
98 uint8_t u8;
99 int8_t i8;
100 uint16_t u16;
101 int16_t i16;
102 uint32_t u32;
103 int32_t i32;
104 uint64_t u64;
105 int64_t i64;
106 unsigned int u_1, u_2, u_3, u_4;
107 spinel_ipv6addr_t *ip6Addr;
108 spinel_eui48_t *eui48;
109 spinel_eui64_t *eui64;
110 const char *utf_1;
111 const char *utf_2;
112 const uint8_t *dataPtr;
113 spinel_size_t dataLen;
114
115 memset(buffer, 0, sizeof(buffer));
116
117 printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
118 printf("\nTest 1: Encoding of simple types");
119
120 SuccessOrQuit(encoder.BeginFrame(Spinel::Buffer::kPriorityLow));
121 SuccessOrQuit(encoder.WriteBool(kBool_1));
122 SuccessOrQuit(encoder.WriteBool(kBool_2));
123 SuccessOrQuit(encoder.WriteUint8(kUint8));
124 SuccessOrQuit(encoder.WriteInt8(kInt8));
125 SuccessOrQuit(encoder.WriteUint16(kUint16));
126 SuccessOrQuit(encoder.WriteInt16(kInt16));
127 SuccessOrQuit(encoder.WriteUint32(kUint32));
128 SuccessOrQuit(encoder.WriteInt32(kInt32));
129 SuccessOrQuit(encoder.WriteUint64(kUint64));
130 SuccessOrQuit(encoder.WriteInt64(kInt64));
131 SuccessOrQuit(encoder.WriteUintPacked(kUint_1));
132 SuccessOrQuit(encoder.WriteUintPacked(kUint_2));
133 SuccessOrQuit(encoder.WriteUintPacked(kUint_3));
134 SuccessOrQuit(encoder.WriteUintPacked(kUint_4));
135 SuccessOrQuit(encoder.WriteIp6Address(kIp6Addr));
136 SuccessOrQuit(encoder.WriteEui48(kEui48));
137 SuccessOrQuit(encoder.WriteEui64(kEui64));
138 SuccessOrQuit(encoder.WriteUtf8(kString_1));
139 SuccessOrQuit(encoder.WriteUtf8(kString_2));
140 SuccessOrQuit(encoder.WriteData((const uint8_t *)kData, sizeof(kData)));
141 SuccessOrQuit(encoder.EndFrame());
142
143 DumpBuffer("Buffer", buffer, 256);
144 SuccessOrQuit(ReadFrame(ncpBuffer, frame, frameLen));
145 DumpBuffer("Frame", frame, frameLen);
146
147 parsedLen = spinel_datatype_unpack(
148 frame, static_cast<spinel_size_t>(frameLen),
149 (SPINEL_DATATYPE_BOOL_S SPINEL_DATATYPE_BOOL_S SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT8_S
150 SPINEL_DATATYPE_UINT16_S SPINEL_DATATYPE_INT16_S SPINEL_DATATYPE_UINT32_S SPINEL_DATATYPE_INT32_S
151 SPINEL_DATATYPE_UINT64_S SPINEL_DATATYPE_INT64_S SPINEL_DATATYPE_UINT_PACKED_S
152 SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_UINT_PACKED_S
153 SPINEL_DATATYPE_IPv6ADDR_S SPINEL_DATATYPE_EUI48_S SPINEL_DATATYPE_EUI64_S
154 SPINEL_DATATYPE_UTF8_S SPINEL_DATATYPE_UTF8_S SPINEL_DATATYPE_DATA_S),
155 &b_1, &b_2, &u8, &i8, &u16, &i16, &u32, &i32, &u64, &i64, &u_1, &u_2, &u_3, &u_4, &ip6Addr, &eui48, &eui64,
156 &utf_1, &utf_2, &dataPtr, &dataLen);
157
158 VerifyOrQuit(parsedLen == frameLen);
159 VerifyOrQuit(b_1 == kBool_1);
160 VerifyOrQuit(b_2 == kBool_2);
161 VerifyOrQuit(u8 == kUint8);
162 VerifyOrQuit(i8 == kInt8);
163 VerifyOrQuit(u16 == kUint16);
164 VerifyOrQuit(i16 == kInt16);
165 VerifyOrQuit(u32 == kUint32);
166 VerifyOrQuit(i32 == kInt32);
167 VerifyOrQuit(u64 == kUint64);
168 VerifyOrQuit(i64 == kInt64);
169 VerifyOrQuit(u_1 == kUint_1);
170 VerifyOrQuit(u_2 == kUint_2);
171 VerifyOrQuit(u_3 == kUint_3);
172 VerifyOrQuit(u_4 == kUint_4);
173 VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0);
174 VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0);
175 VerifyOrQuit(memcmp(eui64, &kEui64, sizeof(spinel_eui64_t)) == 0);
176 VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0);
177 VerifyOrQuit(memcmp(utf_2, kString_2, sizeof(kString_2)) == 0);
178 VerifyOrQuit(dataLen == sizeof(kData));
179 VerifyOrQuit(memcmp(dataPtr, &kData, sizeof(kData)) == 0);
180
181 printf(" -- PASS\n");
182
183 printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
184 printf("\nTest 2: Test a single simple struct.");
185
186 SuccessOrQuit(encoder.BeginFrame(Spinel::Buffer::kPriorityLow));
187 SuccessOrQuit(encoder.WriteUint8(kUint8));
188 SuccessOrQuit(encoder.OpenStruct());
189 {
190 SuccessOrQuit(encoder.WriteUint32(kUint32));
191 SuccessOrQuit(encoder.WriteEui48(kEui48));
192 SuccessOrQuit(encoder.WriteUintPacked(kUint_3));
193 }
194 SuccessOrQuit(encoder.CloseStruct());
195 SuccessOrQuit(encoder.WriteInt16(kInt16));
196 SuccessOrQuit(encoder.EndFrame());
197
198 DumpBuffer("Buffer", buffer, 256);
199 SuccessOrQuit(ReadFrame(ncpBuffer, frame, frameLen));
200 DumpBuffer("Frame", frame, frameLen);
201
202 parsedLen = spinel_datatype_unpack(
203 frame, static_cast<spinel_size_t>(frameLen),
204 (SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_STRUCT_S(
205 SPINEL_DATATYPE_UINT32_S SPINEL_DATATYPE_EUI48_S SPINEL_DATATYPE_UINT_PACKED_S) SPINEL_DATATYPE_INT16_S
206
207 ),
208 &u8, &u32, &eui48, &u_3, &i16);
209
210 VerifyOrQuit(parsedLen == frameLen);
211 VerifyOrQuit(u8 == kUint8);
212 VerifyOrQuit(i16 == kInt16);
213 VerifyOrQuit(u32 == kUint32);
214 VerifyOrQuit(u_3 == kUint_3);
215 VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0);
216
217 // Parse the struct as a "data with len".
218 parsedLen = spinel_datatype_unpack(frame, static_cast<spinel_size_t>(frameLen),
219 (SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_DATA_WLEN_S SPINEL_DATATYPE_INT16_S
220
221 ),
222 &u8, &dataPtr, &dataLen, &i16);
223
224 VerifyOrQuit(parsedLen == frameLen);
225 VerifyOrQuit(u8 == kUint8);
226 VerifyOrQuit(i16 == kInt16);
227
228 printf(" -- PASS\n");
229
230 printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
231 printf("\nTest 3: Test multiple structs and struct within struct.");
232
233 SuccessOrQuit(encoder.BeginFrame(Spinel::Buffer::kPriorityLow));
234 SuccessOrQuit(encoder.OpenStruct());
235 {
236 SuccessOrQuit(encoder.WriteUint8(kUint8));
237 SuccessOrQuit(encoder.WriteUtf8(kString_1));
238 SuccessOrQuit(encoder.OpenStruct());
239 {
240 SuccessOrQuit(encoder.WriteBool(kBool_1));
241 SuccessOrQuit(encoder.WriteIp6Address(kIp6Addr));
242 }
243 SuccessOrQuit(encoder.CloseStruct());
244 SuccessOrQuit(encoder.WriteUint16(kUint16));
245 }
246 SuccessOrQuit(encoder.CloseStruct());
247 SuccessOrQuit(encoder.WriteEui48(kEui48));
248 SuccessOrQuit(encoder.OpenStruct());
249 {
250 SuccessOrQuit(encoder.WriteUint32(kUint32));
251 }
252 SuccessOrQuit(encoder.CloseStruct());
253 SuccessOrQuit(encoder.WriteInt32(kInt32));
254 SuccessOrQuit(encoder.EndFrame());
255
256 DumpBuffer("Buffer", buffer, 256 + 100);
257
258 SuccessOrQuit(ReadFrame(ncpBuffer, frame, frameLen));
259
260 parsedLen = spinel_datatype_unpack(
261 frame, static_cast<spinel_size_t>(frameLen),
262 (SPINEL_DATATYPE_STRUCT_S(SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_UTF8_S SPINEL_DATATYPE_STRUCT_S(
263 SPINEL_DATATYPE_BOOL_S SPINEL_DATATYPE_IPv6ADDR_S) SPINEL_DATATYPE_UINT16_S)
264 SPINEL_DATATYPE_EUI48_S SPINEL_DATATYPE_STRUCT_S(SPINEL_DATATYPE_UINT32_S) SPINEL_DATATYPE_INT32_S),
265 &u8, &utf_1, &b_1, &ip6Addr, &u16, &eui48, &u32, &i32);
266
267 VerifyOrQuit(parsedLen == frameLen);
268 VerifyOrQuit(b_1 == kBool_1);
269 VerifyOrQuit(u8 == kUint8);
270 VerifyOrQuit(u16 == kUint16);
271 VerifyOrQuit(u32 == kUint32);
272 VerifyOrQuit(i32 == kInt32);
273 VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0);
274 VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0);
275 VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0);
276
277 printf(" -- PASS\n");
278
279 printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
280 printf("\nTest 4: Test unclosed struct.");
281
282 SuccessOrQuit(encoder.BeginFrame(Spinel::Buffer::kPriorityLow));
283 SuccessOrQuit(encoder.WriteUint8(kUint8));
284 SuccessOrQuit(encoder.OpenStruct());
285 {
286 SuccessOrQuit(encoder.WriteUint32(kUint32));
287 SuccessOrQuit(encoder.OpenStruct());
288 {
289 SuccessOrQuit(encoder.WriteEui48(kEui48));
290 SuccessOrQuit(encoder.WriteUintPacked(kUint_3));
291 // Do not close the structs expecting `EndFrame()` to close them.
292 }
293 }
294 SuccessOrQuit(encoder.EndFrame());
295
296 SuccessOrQuit(ReadFrame(ncpBuffer, frame, frameLen));
297
298 parsedLen = spinel_datatype_unpack(
299 frame, static_cast<spinel_size_t>(frameLen),
300 (SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_STRUCT_S(
301 SPINEL_DATATYPE_UINT32_S SPINEL_DATATYPE_STRUCT_S(SPINEL_DATATYPE_EUI48_S SPINEL_DATATYPE_UINT_PACKED_S))),
302 &u8, &u32, &eui48, &u_3);
303
304 VerifyOrQuit(parsedLen == frameLen);
305 VerifyOrQuit(u8 == kUint8);
306 VerifyOrQuit(u32 == kUint32);
307 VerifyOrQuit(u_3 == kUint_3);
308 VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0);
309
310 printf(" -- PASS\n");
311
312 printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
313 printf("\nTest 5: Test saving position and resetting back to a saved position");
314
315 SuccessOrQuit(encoder.BeginFrame(Spinel::Buffer::kPriorityLow));
316 SuccessOrQuit(encoder.WriteUint8(kUint8));
317 SuccessOrQuit(encoder.OpenStruct());
318 {
319 SuccessOrQuit(encoder.WriteUint32(kUint32));
320
321 // Save position in middle a first open struct.
322 SuccessOrQuit(encoder.SavePosition());
323 SuccessOrQuit(encoder.OpenStruct());
324 {
325 SuccessOrQuit(encoder.WriteEui48(kEui48));
326 SuccessOrQuit(encoder.WriteUintPacked(kUint_3));
327 }
328
329 // Reset to saved position in middle of the second open struct which should be discarded.
330
331 SuccessOrQuit(encoder.ResetToSaved());
332
333 SuccessOrQuit(encoder.WriteIp6Address(kIp6Addr));
334 SuccessOrQuit(encoder.WriteEui64(kEui64));
335 }
336 SuccessOrQuit(encoder.CloseStruct());
337 SuccessOrQuit(encoder.WriteUtf8(kString_1));
338 SuccessOrQuit(encoder.EndFrame());
339
340 SuccessOrQuit(ReadFrame(ncpBuffer, frame, frameLen));
341
342 parsedLen = spinel_datatype_unpack(
343 frame, static_cast<spinel_size_t>(frameLen),
344 (SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_STRUCT_S(
345 SPINEL_DATATYPE_UINT32_S SPINEL_DATATYPE_IPv6ADDR_S SPINEL_DATATYPE_EUI64_S) SPINEL_DATATYPE_UTF8_S),
346 &u8, &u32, &ip6Addr, &eui64, &utf_1);
347
348 VerifyOrQuit(parsedLen == frameLen);
349
350 VerifyOrQuit(u8 == kUint8);
351 VerifyOrQuit(u32 == kUint32);
352 VerifyOrQuit(i32 == kInt32);
353 VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0);
354 VerifyOrQuit(memcmp(eui64, &kEui64, sizeof(spinel_eui64_t)) == 0);
355 VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0);
356
357 printf(" -- PASS\n");
358 }
359
360 } // namespace Spinel
361 } // namespace ot
362
main(void)363 int main(void)
364 {
365 ot::Spinel::TestEncoder();
366 printf("\nAll tests passed.\n");
367 return 0;
368 }
369