1 /*
2 * Copyright (c) 2016, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /*
29 * -------------------------------------------------------------------
30 *
31 * ## Unit Test ##
32 *
33 * This file includes its own unit test. To compile the unit test,
34 * simply compile this file with the macro SPINEL_SELF_TEST set to 1.
35 * For example:
36 *
37 * cc spinel.c -Wall -DSPINEL_SELF_TEST=1 -o spinel
38 *
39 * -------------------------------------------------------------------
40 */
41
42 // ----------------------------------------------------------------------------
43 // MARK: -
44 // MARK: Headers
45
46 #include "spinel.h"
47
48 #include <errno.h>
49 #include <limits.h>
50
51 #ifndef SPINEL_PLATFORM_HEADER
52 /* These are all already included in the spinel platform header
53 * if SPINEL_PLATFORM_HEADER was defined.
54 */
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #endif // #ifndef SPINEL_PLATFORM_HEADER
59
60 // ----------------------------------------------------------------------------
61 // MARK: -
62
63 // IAR's errno.h apparently doesn't define EOVERFLOW.
64 #ifndef EOVERFLOW
65 // There is no real good choice for what to set
66 // errno to in this case, so we just pick the
67 // value '1' somewhat arbitrarily.
68 #define EOVERFLOW 1
69 #endif
70
71 // IAR's errno.h apparently doesn't define EINVAL.
72 #ifndef EINVAL
73 // There is no real good choice for what to set
74 // errno to in this case, so we just pick the
75 // value '1' somewhat arbitrarily.
76 #define EINVAL 1
77 #endif
78
79 // IAR's errno.h apparently doesn't define ENOMEM.
80 #ifndef ENOMEM
81 // There is no real good choice for what to set
82 // errno to in this case, so we just pick the
83 // value '1' somewhat arbitrarily.
84 #define ENOMEM 1
85 #endif
86
87 #ifndef SPINEL_PLATFORM_SHOULD_LOG_ASSERTS
88 #define SPINEL_PLATFORM_SHOULD_LOG_ASSERTS 0
89 #endif
90
91 #ifndef SPINEL_PLATFORM_DOESNT_IMPLEMENT_ERRNO_VAR
92 #define SPINEL_PLATFORM_DOESNT_IMPLEMENT_ERRNO_VAR 0
93 #endif
94
95 #ifndef SPINEL_PLATFORM_DOESNT_IMPLEMENT_FPRINTF
96 #define SPINEL_PLATFORM_DOESNT_IMPLEMENT_FPRINTF 0
97 #endif
98
99 #ifndef SPINEL_SELF_TEST
100 #define SPINEL_SELF_TEST 0
101 #endif
102
103 #if defined(errno) && SPINEL_PLATFORM_DOESNT_IMPLEMENT_ERRNO_VAR
104 #error "SPINEL_PLATFORM_DOESNT_IMPLEMENT_ERRNO_VAR is set but errno is already defined."
105 #endif
106
107 // Work-around for platforms that don't implement the `errno` variable.
108 #if !defined(errno) && SPINEL_PLATFORM_DOESNT_IMPLEMENT_ERRNO_VAR
109 static int spinel_errno_workaround_;
110 #define errno spinel_errno_workaround_
111 #endif // SPINEL_PLATFORM_DOESNT_IMPLEMENT_ERRNO_VAR
112
113 #ifndef assert_printf
114 #if SPINEL_PLATFORM_DOESNT_IMPLEMENT_FPRINTF
115 #define assert_printf(fmt, ...) printf(__FILE__ ":%d: " fmt "\n", __LINE__, __VA_ARGS__)
116 #else // if SPINEL_PLATFORM_DOESNT_IMPLEMENT_FPRINTF
117 #define assert_printf(fmt, ...) fprintf(stderr, __FILE__ ":%d: " fmt "\n", __LINE__, __VA_ARGS__)
118 #endif // else SPINEL_PLATFORM_DOESNT_IMPLEMENT_FPRINTF
119 #endif
120
121 #ifndef require_action
122 #if SPINEL_PLATFORM_SHOULD_LOG_ASSERTS
123 #define require_action(c, l, a) \
124 do \
125 { \
126 if (!(c)) \
127 { \
128 assert_printf("Requirement Failed (%s)", #c); \
129 a; \
130 goto l; \
131 } \
132 } while (0)
133 #else // if DEBUG
134 #define require_action(c, l, a) \
135 do \
136 { \
137 if (!(c)) \
138 { \
139 a; \
140 goto l; \
141 } \
142 } while (0)
143 #endif // else DEBUG
144 #endif // ifndef require_action
145
146 #ifndef require
147 #define require(c, l) require_action(c, l, {})
148 #endif
149
150 #ifndef strnlen
spinel_strnlen(const char * s,size_t maxlen)151 static size_t spinel_strnlen(const char *s, size_t maxlen)
152 {
153 size_t ret;
154
155 for (ret = 0; (ret < maxlen) && (s[ret] != 0); ret++)
156 {
157 // Empty loop.
158 }
159
160 return ret;
161 }
162 #else
163 #define spinel_strnlen strnlen
164 #endif
165
166 typedef struct
167 {
168 va_list obj;
169 } va_list_obj;
170
171 #define SPINEL_MAX_PACK_LENGTH 32767
172
173 // ----------------------------------------------------------------------------
174
175 // This function validates whether a given byte sequence (string) follows UTF8 encoding.
spinel_validate_utf8(const uint8_t * string)176 static bool spinel_validate_utf8(const uint8_t *string)
177 {
178 bool ret = true;
179 uint8_t byte;
180 uint8_t continuation_bytes = 0;
181
182 while ((byte = *string++) != 0)
183 {
184 if ((byte & 0x80) == 0)
185 {
186 continue;
187 }
188
189 // This is a leading byte 1xxx-xxxx.
190
191 if ((byte & 0x40) == 0) // 10xx-xxxx
192 {
193 // We got a continuation byte pattern without seeing a leading byte earlier.
194 ret = false;
195 goto bail;
196 }
197 else if ((byte & 0x20) == 0) // 110x-xxxx
198 {
199 continuation_bytes = 1;
200 }
201 else if ((byte & 0x10) == 0) // 1110-xxxx
202 {
203 continuation_bytes = 2;
204 }
205 else if ((byte & 0x08) == 0) // 1111-0xxx
206 {
207 continuation_bytes = 3;
208 }
209 else // 1111-1xxx (invalid pattern).
210 {
211 ret = false;
212 goto bail;
213 }
214
215 while (continuation_bytes-- != 0)
216 {
217 byte = *string++;
218
219 // Verify the continuation byte pattern 10xx-xxxx
220 if ((byte & 0xc0) != 0x80)
221 {
222 ret = false;
223 goto bail;
224 }
225 }
226 }
227
228 bail:
229 return ret;
230 }
231
232 // ----------------------------------------------------------------------------
233 // MARK: -
234
spinel_packed_uint_decode(const uint8_t * bytes,spinel_size_t len,unsigned int * value_ptr)235 spinel_ssize_t spinel_packed_uint_decode(const uint8_t *bytes, spinel_size_t len, unsigned int *value_ptr)
236 {
237 spinel_ssize_t ret = 0;
238 unsigned int value = 0;
239
240 unsigned int i = 0;
241
242 do
243 {
244 if ((len < sizeof(uint8_t)) || (i >= sizeof(unsigned int) * CHAR_BIT))
245 {
246 ret = -1;
247 break;
248 }
249
250 value |= (unsigned int)(bytes[0] & 0x7F) << i;
251 i += 7;
252 ret += sizeof(uint8_t);
253 bytes += sizeof(uint8_t);
254 len -= sizeof(uint8_t);
255 } while ((bytes[-1] & 0x80) == 0x80);
256
257 if ((ret > 0) && (value_ptr != NULL))
258 {
259 *value_ptr = value;
260 }
261
262 return ret;
263 }
264
spinel_packed_uint_size(unsigned int value)265 spinel_ssize_t spinel_packed_uint_size(unsigned int value)
266 {
267 spinel_ssize_t ret;
268
269 if (value < (1 << 7))
270 {
271 ret = 1;
272 }
273 else if (value < (1 << 14))
274 {
275 ret = 2;
276 }
277 else if (value < (1 << 21))
278 {
279 ret = 3;
280 }
281 else if (value < (1 << 28))
282 {
283 ret = 4;
284 }
285 else
286 {
287 ret = 5;
288 }
289
290 return ret;
291 }
292
spinel_packed_uint_encode(uint8_t * bytes,spinel_size_t len,unsigned int value)293 spinel_ssize_t spinel_packed_uint_encode(uint8_t *bytes, spinel_size_t len, unsigned int value)
294 {
295 const spinel_ssize_t encoded_size = spinel_packed_uint_size(value);
296
297 if ((spinel_ssize_t)len >= encoded_size)
298 {
299 spinel_ssize_t i;
300
301 for (i = 0; i != encoded_size - 1; ++i)
302 {
303 *bytes++ = (value & 0x7F) | 0x80;
304 value = (value >> 7);
305 }
306
307 *bytes++ = (value & 0x7F);
308 }
309
310 return encoded_size;
311 }
312
spinel_next_packed_datatype(const char * pack_format)313 const char *spinel_next_packed_datatype(const char *pack_format)
314 {
315 int depth = 0;
316
317 do
318 {
319 switch (*++pack_format)
320 {
321 case '(':
322 depth++;
323 break;
324
325 case ')':
326 depth--;
327
328 if (depth == 0)
329 {
330 pack_format++;
331 }
332
333 break;
334 }
335 } while ((depth > 0) && *pack_format != 0);
336
337 return pack_format;
338 }
339
spinel_datatype_vunpack_(bool in_place,const uint8_t * data_in,spinel_size_t data_len,const char * pack_format,va_list_obj * args)340 static spinel_ssize_t spinel_datatype_vunpack_(bool in_place,
341 const uint8_t *data_in,
342 spinel_size_t data_len,
343 const char * pack_format,
344 va_list_obj * args)
345 {
346 spinel_ssize_t ret = 0;
347
348 // Buffer length sanity check
349 require_action(data_len <= SPINEL_MAX_PACK_LENGTH, bail, (ret = -1, errno = EINVAL));
350
351 for (; *pack_format != 0; pack_format = spinel_next_packed_datatype(pack_format))
352 {
353 if (*pack_format == ')')
354 {
355 // Don't go past the end of a struct.
356 break;
357 }
358
359 switch ((spinel_datatype_t)pack_format[0])
360 {
361 case SPINEL_DATATYPE_BOOL_C:
362 {
363 bool *arg_ptr = va_arg(args->obj, bool *);
364 require_action(data_len >= sizeof(uint8_t), bail, (ret = -1, errno = EOVERFLOW));
365
366 if (arg_ptr)
367 {
368 *arg_ptr = data_in[0] != 0;
369 }
370
371 ret += sizeof(uint8_t);
372 data_in += sizeof(uint8_t);
373 data_len -= sizeof(uint8_t);
374 break;
375 }
376
377 case SPINEL_DATATYPE_INT8_C:
378 case SPINEL_DATATYPE_UINT8_C:
379 {
380 uint8_t *arg_ptr = va_arg(args->obj, uint8_t *);
381 require_action(data_len >= sizeof(uint8_t), bail, (ret = -1, errno = EOVERFLOW));
382
383 if (arg_ptr)
384 {
385 *arg_ptr = data_in[0];
386 }
387
388 ret += sizeof(uint8_t);
389 data_in += sizeof(uint8_t);
390 data_len -= sizeof(uint8_t);
391 break;
392 }
393
394 case SPINEL_DATATYPE_INT16_C:
395 case SPINEL_DATATYPE_UINT16_C:
396 {
397 uint16_t *arg_ptr = va_arg(args->obj, uint16_t *);
398 require_action(data_len >= sizeof(uint16_t), bail, (ret = -1, errno = EOVERFLOW));
399
400 if (arg_ptr)
401 {
402 *arg_ptr = (uint16_t)((data_in[1] << 8) | data_in[0]);
403 }
404
405 ret += sizeof(uint16_t);
406 data_in += sizeof(uint16_t);
407 data_len -= sizeof(uint16_t);
408 break;
409 }
410
411 case SPINEL_DATATYPE_INT32_C:
412 case SPINEL_DATATYPE_UINT32_C:
413 {
414 uint32_t *arg_ptr = va_arg(args->obj, uint32_t *);
415 require_action(data_len >= sizeof(uint32_t), bail, (ret = -1, errno = EOVERFLOW));
416
417 if (arg_ptr)
418 {
419 *arg_ptr = (uint32_t)((data_in[3] << 24) | (data_in[2] << 16) | (data_in[1] << 8) | data_in[0]);
420 }
421
422 ret += sizeof(uint32_t);
423 data_in += sizeof(uint32_t);
424 data_len -= sizeof(uint32_t);
425 break;
426 }
427
428 case SPINEL_DATATYPE_INT64_C:
429 case SPINEL_DATATYPE_UINT64_C:
430 {
431 uint64_t *arg_ptr = va_arg(args->obj, uint64_t *);
432 require_action(data_len >= sizeof(uint64_t), bail, (ret = -1, errno = EOVERFLOW));
433
434 if (arg_ptr)
435 {
436 uint32_t l32 = (uint32_t)((data_in[3] << 24) | (data_in[2] << 16) | (data_in[1] << 8) | data_in[0]);
437 uint32_t h32 = (uint32_t)((data_in[7] << 24) | (data_in[6] << 16) | (data_in[5] << 8) | data_in[4]);
438
439 *arg_ptr = ((uint64_t)l32) | (((uint64_t)h32) << 32);
440 }
441
442 ret += sizeof(uint64_t);
443 data_in += sizeof(uint64_t);
444 data_len -= sizeof(uint64_t);
445 break;
446 }
447
448 case SPINEL_DATATYPE_IPv6ADDR_C:
449 {
450 require_action(data_len >= sizeof(spinel_ipv6addr_t), bail, (ret = -1, errno = EOVERFLOW));
451
452 if (in_place)
453 {
454 spinel_ipv6addr_t *arg = va_arg(args->obj, spinel_ipv6addr_t *);
455 if (arg)
456 {
457 memcpy(arg, data_in, sizeof(spinel_ipv6addr_t));
458 }
459 }
460 else
461 {
462 const spinel_ipv6addr_t **arg_ptr = va_arg(args->obj, const spinel_ipv6addr_t **);
463 if (arg_ptr)
464 {
465 *arg_ptr = (const spinel_ipv6addr_t *)data_in;
466 }
467 }
468
469 ret += sizeof(spinel_ipv6addr_t);
470 data_in += sizeof(spinel_ipv6addr_t);
471 data_len -= sizeof(spinel_ipv6addr_t);
472 break;
473 }
474
475 case SPINEL_DATATYPE_EUI64_C:
476 {
477 require_action(data_len >= sizeof(spinel_eui64_t), bail, (ret = -1, errno = EOVERFLOW));
478
479 if (in_place)
480 {
481 spinel_eui64_t *arg = va_arg(args->obj, spinel_eui64_t *);
482 if (arg)
483 {
484 memcpy(arg, data_in, sizeof(spinel_eui64_t));
485 }
486 }
487 else
488 {
489 const spinel_eui64_t **arg_ptr = va_arg(args->obj, const spinel_eui64_t **);
490 if (arg_ptr)
491 {
492 *arg_ptr = (const spinel_eui64_t *)data_in;
493 }
494 }
495
496 ret += sizeof(spinel_eui64_t);
497 data_in += sizeof(spinel_eui64_t);
498 data_len -= sizeof(spinel_eui64_t);
499 break;
500 }
501
502 case SPINEL_DATATYPE_EUI48_C:
503 {
504 require_action(data_len >= sizeof(spinel_eui48_t), bail, (ret = -1, errno = EOVERFLOW));
505
506 if (in_place)
507 {
508 spinel_eui48_t *arg = va_arg(args->obj, spinel_eui48_t *);
509 if (arg)
510 {
511 memcpy(arg, data_in, sizeof(spinel_eui48_t));
512 }
513 }
514 else
515 {
516 const spinel_eui48_t **arg_ptr = va_arg(args->obj, const spinel_eui48_t **);
517 if (arg_ptr)
518 {
519 *arg_ptr = (const spinel_eui48_t *)data_in;
520 }
521 }
522
523 ret += sizeof(spinel_eui48_t);
524 data_in += sizeof(spinel_eui48_t);
525 data_len -= sizeof(spinel_eui48_t);
526 break;
527 }
528
529 case SPINEL_DATATYPE_UINT_PACKED_C:
530 {
531 unsigned int * arg_ptr = va_arg(args->obj, unsigned int *);
532 spinel_ssize_t pui_len = spinel_packed_uint_decode(data_in, data_len, arg_ptr);
533
534 // Range check
535 require_action(NULL == arg_ptr || (*arg_ptr < SPINEL_MAX_UINT_PACKED), bail, (ret = -1, errno = ERANGE));
536
537 require(pui_len > 0, bail);
538
539 require(pui_len <= (spinel_ssize_t)data_len, bail);
540
541 ret += pui_len;
542 data_in += pui_len;
543 data_len -= (spinel_size_t)pui_len;
544 break;
545 }
546
547 case SPINEL_DATATYPE_UTF8_C:
548 {
549 size_t len;
550
551 // Make sure we have at least one byte.
552 require_action(data_len > 0, bail, (ret = -1, errno = EOVERFLOW));
553
554 // Add 1 for zero termination. If not zero terminated,
555 // len will then be data_len+1, which we will detect
556 // in the next check.
557 len = spinel_strnlen((const char *)data_in, data_len) + 1;
558
559 // Verify that the string is zero terminated.
560 require_action(len <= data_len, bail, (ret = -1, errno = EOVERFLOW));
561
562 // Verify the string follows valid UTF8 encoding.
563 require_action(spinel_validate_utf8(data_in), bail, (ret = -1, errno = EINVAL));
564
565 if (in_place)
566 {
567 char * arg = va_arg(args->obj, char *);
568 size_t len_arg = va_arg(args->obj, size_t);
569 if (arg)
570 {
571 require_action(len_arg >= len, bail, (ret = -1, errno = ENOMEM));
572 memcpy(arg, data_in, len);
573 }
574 }
575 else
576 {
577 const char **arg_ptr = va_arg(args->obj, const char **);
578 if (arg_ptr)
579 {
580 *arg_ptr = (const char *)data_in;
581 }
582 }
583
584 ret += (spinel_size_t)len;
585 data_in += len;
586 data_len -= (spinel_size_t)len;
587 break;
588 }
589
590 case SPINEL_DATATYPE_DATA_C:
591 case SPINEL_DATATYPE_DATA_WLEN_C:
592 {
593 spinel_ssize_t pui_len = 0;
594 uint16_t block_len = 0;
595 const uint8_t *block_ptr = data_in;
596 void * arg_ptr = va_arg(args->obj, void *);
597 unsigned int * block_len_ptr = va_arg(args->obj, unsigned int *);
598 char nextformat = *spinel_next_packed_datatype(pack_format);
599
600 if ((pack_format[0] == SPINEL_DATATYPE_DATA_WLEN_C) || ((nextformat != 0) && (nextformat != ')')))
601 {
602 pui_len = spinel_datatype_unpack(data_in, data_len, SPINEL_DATATYPE_UINT16_S, &block_len);
603 block_ptr += pui_len;
604
605 require(pui_len > 0, bail);
606 require(block_len < SPINEL_FRAME_MAX_SIZE, bail);
607 }
608 else
609 {
610 block_len = (uint16_t)data_len;
611 pui_len = 0;
612 }
613
614 require_action((spinel_ssize_t)data_len >= (block_len + pui_len), bail, (ret = -1, errno = EOVERFLOW));
615
616 if (in_place)
617 {
618 require_action(NULL != block_len_ptr && *block_len_ptr >= block_len, bail, (ret = -1, errno = EINVAL));
619 memcpy(arg_ptr, block_ptr, block_len);
620 }
621 else
622 {
623 const uint8_t **block_ptr_ptr = (const uint8_t **)arg_ptr;
624 if (NULL != block_ptr_ptr)
625 {
626 *block_ptr_ptr = block_ptr;
627 }
628 }
629
630 if (NULL != block_len_ptr)
631 {
632 *block_len_ptr = block_len;
633 }
634
635 block_len += (uint16_t)pui_len;
636 ret += block_len;
637 data_in += block_len;
638 data_len -= block_len;
639 break;
640 }
641
642 case 'T':
643 case SPINEL_DATATYPE_STRUCT_C:
644 {
645 spinel_ssize_t pui_len = 0;
646 uint16_t block_len = 0;
647 spinel_ssize_t actual_len = 0;
648 const uint8_t *block_ptr = data_in;
649 char nextformat = *spinel_next_packed_datatype(pack_format);
650
651 if ((pack_format[0] == SPINEL_DATATYPE_STRUCT_C) || ((nextformat != 0) && (nextformat != ')')))
652 {
653 pui_len = spinel_datatype_unpack(data_in, data_len, SPINEL_DATATYPE_UINT16_S, &block_len);
654 block_ptr += pui_len;
655
656 require(pui_len > 0, bail);
657 require(block_len < SPINEL_FRAME_MAX_SIZE, bail);
658 }
659 else
660 {
661 block_len = (uint16_t)data_len;
662 pui_len = 0;
663 }
664
665 require_action((spinel_ssize_t)data_len >= (block_len + pui_len), bail, (ret = -1, errno = EOVERFLOW));
666
667 actual_len = spinel_datatype_vunpack_(false, block_ptr, block_len, pack_format + 2, args);
668
669 require_action(actual_len > -1, bail, (ret = -1, errno = EOVERFLOW));
670
671 if (pui_len)
672 {
673 block_len += (uint16_t)pui_len;
674 }
675 else
676 {
677 block_len = (uint16_t)actual_len;
678 }
679
680 ret += block_len;
681 data_in += block_len;
682 data_len -= block_len;
683 break;
684 }
685
686 case '.':
687 // Skip.
688 break;
689
690 case SPINEL_DATATYPE_ARRAY_C:
691 default:
692 // Unsupported Type!
693 ret = -1;
694 errno = EINVAL;
695 goto bail;
696 }
697 }
698
699 return ret;
700
701 bail:
702 return ret;
703 }
704
spinel_datatype_unpack_in_place(const uint8_t * data_in,spinel_size_t data_len,const char * pack_format,...)705 spinel_ssize_t spinel_datatype_unpack_in_place(const uint8_t *data_in,
706 spinel_size_t data_len,
707 const char * pack_format,
708 ...)
709 {
710 spinel_ssize_t ret;
711 va_list_obj args;
712 va_start(args.obj, pack_format);
713
714 ret = spinel_datatype_vunpack_(true, data_in, data_len, pack_format, &args);
715
716 va_end(args.obj);
717 return ret;
718 }
719
spinel_datatype_unpack(const uint8_t * data_in,spinel_size_t data_len,const char * pack_format,...)720 spinel_ssize_t spinel_datatype_unpack(const uint8_t *data_in, spinel_size_t data_len, const char *pack_format, ...)
721 {
722 spinel_ssize_t ret;
723 va_list_obj args;
724 va_start(args.obj, pack_format);
725
726 ret = spinel_datatype_vunpack_(false, data_in, data_len, pack_format, &args);
727
728 va_end(args.obj);
729 return ret;
730 }
731
spinel_datatype_vunpack_in_place(const uint8_t * data_in,spinel_size_t data_len,const char * pack_format,va_list args)732 spinel_ssize_t spinel_datatype_vunpack_in_place(const uint8_t *data_in,
733 spinel_size_t data_len,
734 const char * pack_format,
735 va_list args)
736 {
737 spinel_ssize_t ret;
738 va_list_obj args_obj;
739 va_copy(args_obj.obj, args);
740
741 ret = spinel_datatype_vunpack_(true, data_in, data_len, pack_format, &args_obj);
742
743 va_end(args_obj.obj);
744 return ret;
745 }
746
spinel_datatype_vunpack(const uint8_t * data_in,spinel_size_t data_len,const char * pack_format,va_list args)747 spinel_ssize_t spinel_datatype_vunpack(const uint8_t *data_in,
748 spinel_size_t data_len,
749 const char * pack_format,
750 va_list args)
751 {
752 spinel_ssize_t ret;
753 va_list_obj args_obj;
754 va_copy(args_obj.obj, args);
755
756 ret = spinel_datatype_vunpack_(false, data_in, data_len, pack_format, &args_obj);
757
758 va_end(args_obj.obj);
759 return ret;
760 }
761
spinel_datatype_vpack_(uint8_t * data_out,spinel_size_t data_len_max,const char * pack_format,va_list_obj * args)762 static spinel_ssize_t spinel_datatype_vpack_(uint8_t * data_out,
763 spinel_size_t data_len_max,
764 const char * pack_format,
765 va_list_obj * args)
766 {
767 spinel_ssize_t ret = 0;
768
769 // Buffer length sanity check
770 require_action(data_len_max <= SPINEL_MAX_PACK_LENGTH, bail, (ret = -1, errno = EINVAL));
771
772 if (data_out == NULL)
773 {
774 data_len_max = 0;
775 }
776
777 for (; *pack_format != 0; pack_format = spinel_next_packed_datatype(pack_format))
778 {
779 if (*pack_format == ')')
780 {
781 // Don't go past the end of a struct.
782 break;
783 }
784
785 switch ((spinel_datatype_t)*pack_format)
786 {
787 case SPINEL_DATATYPE_BOOL_C:
788 {
789 bool arg = (bool)va_arg(args->obj, int);
790 ret += sizeof(uint8_t);
791
792 if (data_len_max >= sizeof(uint8_t))
793 {
794 data_out[0] = (arg != false);
795 data_out += sizeof(uint8_t);
796 data_len_max -= sizeof(uint8_t);
797 }
798 else
799 {
800 data_len_max = 0;
801 }
802
803 break;
804 }
805
806 case SPINEL_DATATYPE_INT8_C:
807 case SPINEL_DATATYPE_UINT8_C:
808 {
809 uint8_t arg = (uint8_t)va_arg(args->obj, int);
810 ret += sizeof(uint8_t);
811
812 if (data_len_max >= sizeof(uint8_t))
813 {
814 data_out[0] = arg;
815 data_out += sizeof(uint8_t);
816 data_len_max -= sizeof(uint8_t);
817 }
818 else
819 {
820 data_len_max = 0;
821 }
822
823 break;
824 }
825
826 case SPINEL_DATATYPE_INT16_C:
827 case SPINEL_DATATYPE_UINT16_C:
828 {
829 uint16_t arg = (uint16_t)va_arg(args->obj, int);
830 ret += sizeof(uint16_t);
831
832 if (data_len_max >= sizeof(uint16_t))
833 {
834 data_out[1] = (arg >> 8) & 0xff;
835 data_out[0] = (arg >> 0) & 0xff;
836 data_out += sizeof(uint16_t);
837 data_len_max -= sizeof(uint16_t);
838 }
839 else
840 {
841 data_len_max = 0;
842 }
843
844 break;
845 }
846
847 case SPINEL_DATATYPE_INT32_C:
848 case SPINEL_DATATYPE_UINT32_C:
849 {
850 uint32_t arg = (uint32_t)va_arg(args->obj, int);
851 ret += sizeof(uint32_t);
852
853 if (data_len_max >= sizeof(uint32_t))
854 {
855 data_out[3] = (arg >> 24) & 0xff;
856 data_out[2] = (arg >> 16) & 0xff;
857 data_out[1] = (arg >> 8) & 0xff;
858 data_out[0] = (arg >> 0) & 0xff;
859 data_out += sizeof(uint32_t);
860 data_len_max -= sizeof(uint32_t);
861 }
862 else
863 {
864 data_len_max = 0;
865 }
866
867 break;
868 }
869
870 case SPINEL_DATATYPE_INT64_C:
871 case SPINEL_DATATYPE_UINT64_C:
872 {
873 uint64_t arg = va_arg(args->obj, uint64_t);
874
875 ret += sizeof(uint64_t);
876
877 if (data_len_max >= sizeof(uint64_t))
878 {
879 data_out[7] = (arg >> 56) & 0xff;
880 data_out[6] = (arg >> 48) & 0xff;
881 data_out[5] = (arg >> 40) & 0xff;
882 data_out[4] = (arg >> 32) & 0xff;
883 data_out[3] = (arg >> 24) & 0xff;
884 data_out[2] = (arg >> 16) & 0xff;
885 data_out[1] = (arg >> 8) & 0xff;
886 data_out[0] = (arg >> 0) & 0xff;
887 data_out += sizeof(uint64_t);
888 data_len_max -= sizeof(uint64_t);
889 }
890 else
891 {
892 data_len_max = 0;
893 }
894
895 break;
896 }
897
898 case SPINEL_DATATYPE_IPv6ADDR_C:
899 {
900 spinel_ipv6addr_t *arg = va_arg(args->obj, spinel_ipv6addr_t *);
901 ret += sizeof(spinel_ipv6addr_t);
902
903 if (data_len_max >= sizeof(spinel_ipv6addr_t))
904 {
905 *(spinel_ipv6addr_t *)data_out = *arg;
906 data_out += sizeof(spinel_ipv6addr_t);
907 data_len_max -= sizeof(spinel_ipv6addr_t);
908 }
909 else
910 {
911 data_len_max = 0;
912 }
913
914 break;
915 }
916
917 case SPINEL_DATATYPE_EUI48_C:
918 {
919 spinel_eui48_t *arg = va_arg(args->obj, spinel_eui48_t *);
920 ret += sizeof(spinel_eui48_t);
921
922 if (data_len_max >= sizeof(spinel_eui48_t))
923 {
924 *(spinel_eui48_t *)data_out = *arg;
925 data_out += sizeof(spinel_eui48_t);
926 data_len_max -= sizeof(spinel_eui48_t);
927 }
928 else
929 {
930 data_len_max = 0;
931 }
932
933 break;
934 }
935
936 case SPINEL_DATATYPE_EUI64_C:
937 {
938 spinel_eui64_t *arg = va_arg(args->obj, spinel_eui64_t *);
939 ret += sizeof(spinel_eui64_t);
940
941 if (data_len_max >= sizeof(spinel_eui64_t))
942 {
943 *(spinel_eui64_t *)data_out = *arg;
944 data_out += sizeof(spinel_eui64_t);
945 data_len_max -= sizeof(spinel_eui64_t);
946 }
947 else
948 {
949 data_len_max = 0;
950 }
951
952 break;
953 }
954
955 case SPINEL_DATATYPE_UINT_PACKED_C:
956 {
957 uint32_t arg = va_arg(args->obj, uint32_t);
958 spinel_ssize_t encoded_size;
959
960 // Range Check
961 require_action(arg < SPINEL_MAX_UINT_PACKED, bail, {
962 ret = -1;
963 errno = EINVAL;
964 });
965
966 encoded_size = spinel_packed_uint_encode(data_out, data_len_max, arg);
967 ret += encoded_size;
968
969 if ((spinel_ssize_t)data_len_max >= encoded_size)
970 {
971 data_out += encoded_size;
972 data_len_max -= (spinel_size_t)encoded_size;
973 }
974 else
975 {
976 data_len_max = 0;
977 }
978
979 break;
980 }
981
982 case SPINEL_DATATYPE_UTF8_C:
983 {
984 const char *string_arg = va_arg(args->obj, const char *);
985 size_t string_arg_len = 0;
986
987 if (string_arg)
988 {
989 string_arg_len = strlen(string_arg) + 1;
990 }
991 else
992 {
993 string_arg = "";
994 string_arg_len = 1;
995 }
996
997 ret += (spinel_size_t)string_arg_len;
998
999 if (data_len_max >= string_arg_len)
1000 {
1001 memcpy(data_out, string_arg, string_arg_len);
1002
1003 data_out += string_arg_len;
1004 data_len_max -= (spinel_size_t)string_arg_len;
1005 }
1006 else
1007 {
1008 data_len_max = 0;
1009 }
1010
1011 break;
1012 }
1013
1014 case SPINEL_DATATYPE_DATA_WLEN_C:
1015 case SPINEL_DATATYPE_DATA_C:
1016 {
1017 const uint8_t *arg = va_arg(args->obj, const uint8_t *);
1018 uint32_t data_size_arg = va_arg(args->obj, uint32_t);
1019 spinel_ssize_t size_len = 0;
1020 char nextformat = *spinel_next_packed_datatype(pack_format);
1021
1022 if ((pack_format[0] == SPINEL_DATATYPE_DATA_WLEN_C) || ((nextformat != 0) && (nextformat != ')')))
1023 {
1024 size_len = spinel_datatype_pack(data_out, data_len_max, SPINEL_DATATYPE_UINT16_S, data_size_arg);
1025 require_action(size_len > 0, bail, {
1026 ret = -1;
1027 errno = EINVAL;
1028 });
1029 }
1030
1031 ret += (spinel_size_t)size_len + data_size_arg;
1032
1033 if (data_len_max >= (spinel_size_t)size_len + data_size_arg)
1034 {
1035 data_out += size_len;
1036 data_len_max -= (spinel_size_t)size_len;
1037
1038 if (data_out && arg)
1039 {
1040 memcpy(data_out, arg, data_size_arg);
1041 }
1042
1043 data_out += data_size_arg;
1044 data_len_max -= data_size_arg;
1045 }
1046 else
1047 {
1048 data_len_max = 0;
1049 }
1050
1051 break;
1052 }
1053
1054 case 'T':
1055 case SPINEL_DATATYPE_STRUCT_C:
1056 {
1057 spinel_ssize_t struct_len = 0;
1058 spinel_ssize_t size_len = 0;
1059 char nextformat = *spinel_next_packed_datatype(pack_format);
1060
1061 require_action(pack_format[1] == '(', bail, {
1062 ret = -1;
1063 errno = EINVAL;
1064 });
1065
1066 // First we figure out the size of the struct
1067 {
1068 va_list_obj subargs;
1069 va_copy(subargs.obj, args->obj);
1070 struct_len = spinel_datatype_vpack_(NULL, 0, pack_format + 2, &subargs);
1071 va_end(subargs.obj);
1072 }
1073
1074 if ((pack_format[0] == SPINEL_DATATYPE_STRUCT_C) || ((nextformat != 0) && (nextformat != ')')))
1075 {
1076 size_len = spinel_datatype_pack(data_out, data_len_max, SPINEL_DATATYPE_UINT16_S, struct_len);
1077 require_action(size_len > 0, bail, {
1078 ret = -1;
1079 errno = EINVAL;
1080 });
1081 }
1082
1083 ret += size_len + struct_len;
1084
1085 if (struct_len + size_len <= (spinel_ssize_t)data_len_max)
1086 {
1087 data_out += size_len;
1088 data_len_max -= (spinel_size_t)size_len;
1089
1090 struct_len = spinel_datatype_vpack_(data_out, data_len_max, pack_format + 2, args);
1091
1092 data_out += struct_len;
1093 data_len_max -= (spinel_size_t)struct_len;
1094 }
1095 else
1096 {
1097 data_len_max = 0;
1098 }
1099
1100 break;
1101 }
1102
1103 case '.':
1104 // Skip.
1105 break;
1106
1107 default:
1108 // Unsupported Type!
1109 ret = -1;
1110 errno = EINVAL;
1111 goto bail;
1112 }
1113 }
1114
1115 bail:
1116 return ret;
1117 }
1118
spinel_datatype_pack(uint8_t * data_out,spinel_size_t data_len_max,const char * pack_format,...)1119 spinel_ssize_t spinel_datatype_pack(uint8_t *data_out, spinel_size_t data_len_max, const char *pack_format, ...)
1120 {
1121 int ret;
1122 va_list_obj args;
1123 va_start(args.obj, pack_format);
1124
1125 ret = spinel_datatype_vpack_(data_out, data_len_max, pack_format, &args);
1126
1127 va_end(args.obj);
1128 return ret;
1129 }
1130
spinel_datatype_vpack(uint8_t * data_out,spinel_size_t data_len_max,const char * pack_format,va_list args)1131 spinel_ssize_t spinel_datatype_vpack(uint8_t * data_out,
1132 spinel_size_t data_len_max,
1133 const char * pack_format,
1134 va_list args)
1135 {
1136 int ret;
1137 va_list_obj args_obj;
1138 va_copy(args_obj.obj, args);
1139
1140 ret = spinel_datatype_vpack_(data_out, data_len_max, pack_format, &args_obj);
1141
1142 va_end(args_obj.obj);
1143 return ret;
1144 }
1145
1146 // ----------------------------------------------------------------------------
1147 // MARK: -
1148
1149 // LCOV_EXCL_START
1150
1151 struct spinel_cstr
1152 {
1153 uint32_t val;
1154 const char *str;
1155 };
1156
spinel_to_cstr(const struct spinel_cstr * table,uint32_t val)1157 static const char *spinel_to_cstr(const struct spinel_cstr *table, uint32_t val)
1158 {
1159 int i;
1160
1161 for (i = 0; table[i].str; i++)
1162 if (val == table[i].val)
1163 return table[i].str;
1164 return "UNKNOWN";
1165 }
1166
spinel_command_to_cstr(spinel_command_t command)1167 const char *spinel_command_to_cstr(spinel_command_t command)
1168 {
1169 static const struct spinel_cstr spinel_commands_cstr[] = {
1170 {SPINEL_CMD_NOOP, "NOOP"},
1171 {SPINEL_CMD_RESET, "RESET"},
1172 {SPINEL_CMD_PROP_VALUE_GET, "PROP_VALUE_GET"},
1173 {SPINEL_CMD_PROP_VALUE_SET, "PROP_VALUE_SET"},
1174 {SPINEL_CMD_PROP_VALUE_INSERT, "PROP_VALUE_INSERT"},
1175 {SPINEL_CMD_PROP_VALUE_REMOVE, "PROP_VALUE_REMOVE"},
1176 {SPINEL_CMD_PROP_VALUE_IS, "PROP_VALUE_IS"},
1177 {SPINEL_CMD_PROP_VALUE_INSERTED, "PROP_VALUE_INSERTED"},
1178 {SPINEL_CMD_PROP_VALUE_REMOVED, "PROP_VALUE_REMOVED"},
1179 {SPINEL_CMD_NET_SAVE, "NET_SAVE"},
1180 {SPINEL_CMD_NET_CLEAR, "NET_CLEAR"},
1181 {SPINEL_CMD_NET_RECALL, "NET_RECALL"},
1182 {SPINEL_CMD_HBO_OFFLOAD, "HBO_OFFLOAD"},
1183 {SPINEL_CMD_HBO_RECLAIM, "HBO_RECLAIM"},
1184 {SPINEL_CMD_HBO_DROP, "HBO_DROP"},
1185 {SPINEL_CMD_HBO_OFFLOADED, "HBO_OFFLOADED"},
1186 {SPINEL_CMD_HBO_RECLAIMED, "HBO_RECLAIMED"},
1187 {SPINEL_CMD_HBO_DROPPED, "HBO_DROPPED"},
1188 {SPINEL_CMD_PEEK, "PEEK"},
1189 {SPINEL_CMD_PEEK_RET, "PEEK_RET"},
1190 {SPINEL_CMD_POKE, "POKE"},
1191 {SPINEL_CMD_PROP_VALUE_MULTI_GET, "PROP_VALUE_MULTI_GET"},
1192 {SPINEL_CMD_PROP_VALUE_MULTI_SET, "PROP_VALUE_MULTI_SET"},
1193 {SPINEL_CMD_PROP_VALUES_ARE, "PROP_VALUES_ARE"},
1194 {0, NULL},
1195 };
1196
1197 return spinel_to_cstr(spinel_commands_cstr, command);
1198 }
1199
spinel_prop_key_to_cstr(spinel_prop_key_t prop_key)1200 const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key)
1201 {
1202 static const struct spinel_cstr spinel_prop_cstr[] = {
1203 {SPINEL_PROP_LAST_STATUS, "LAST_STATUS"},
1204 {SPINEL_PROP_PROTOCOL_VERSION, "PROTOCOL_VERSION"},
1205 {SPINEL_PROP_NCP_VERSION, "NCP_VERSION"},
1206 {SPINEL_PROP_INTERFACE_TYPE, "INTERFACE_TYPE"},
1207 {SPINEL_PROP_VENDOR_ID, "VENDOR_ID"},
1208 {SPINEL_PROP_CAPS, "CAPS"},
1209 {SPINEL_PROP_INTERFACE_COUNT, "INTERFACE_COUNT"},
1210 {SPINEL_PROP_POWER_STATE, "POWER_STATE"},
1211 {SPINEL_PROP_HWADDR, "HWADDR"},
1212 {SPINEL_PROP_LOCK, "LOCK"},
1213 {SPINEL_PROP_HBO_MEM_MAX, "HBO_MEM_MAX"},
1214 {SPINEL_PROP_HBO_BLOCK_MAX, "HBO_BLOCK_MAX"},
1215 {SPINEL_PROP_HOST_POWER_STATE, "HOST_POWER_STATE"},
1216 {SPINEL_PROP_MCU_POWER_STATE, "MCU_POWER_STATE"},
1217 {SPINEL_PROP_GPIO_CONFIG, "GPIO_CONFIG"},
1218 {SPINEL_PROP_GPIO_STATE, "GPIO_STATE"},
1219 {SPINEL_PROP_GPIO_STATE_SET, "GPIO_STATE_SET"},
1220 {SPINEL_PROP_GPIO_STATE_CLEAR, "GPIO_STATE_CLEAR"},
1221 {SPINEL_PROP_TRNG_32, "TRNG_32"},
1222 {SPINEL_PROP_TRNG_128, "TRNG_128"},
1223 {SPINEL_PROP_TRNG_RAW_32, "TRNG_RAW_32"},
1224 {SPINEL_PROP_UNSOL_UPDATE_FILTER, "UNSOL_UPDATE_FILTER"},
1225 {SPINEL_PROP_UNSOL_UPDATE_LIST, "UNSOL_UPDATE_LIST"},
1226 {SPINEL_PROP_PHY_ENABLED, "PHY_ENABLED"},
1227 {SPINEL_PROP_PHY_CHAN, "PHY_CHAN"},
1228 {SPINEL_PROP_PHY_CHAN_SUPPORTED, "PHY_CHAN_SUPPORTED"},
1229 {SPINEL_PROP_PHY_FREQ, "PHY_FREQ"},
1230 {SPINEL_PROP_PHY_CCA_THRESHOLD, "PHY_CCA_THRESHOLD"},
1231 {SPINEL_PROP_PHY_TX_POWER, "PHY_TX_POWER"},
1232 {SPINEL_PROP_PHY_FEM_LNA_GAIN, "PHY_FEM_LNA_GAIN"},
1233 {SPINEL_PROP_PHY_RSSI, "PHY_RSSI"},
1234 {SPINEL_PROP_PHY_RX_SENSITIVITY, "PHY_RX_SENSITIVITY"},
1235 {SPINEL_PROP_PHY_PCAP_ENABLED, "PHY_PCAP_ENABLED"},
1236 {SPINEL_PROP_PHY_CHAN_PREFERRED, "PHY_CHAN_PREFERRED"},
1237 {SPINEL_PROP_PHY_CHAN_MAX_POWER, "PHY_CHAN_MAX_POWER"},
1238 {SPINEL_PROP_JAM_DETECT_ENABLE, "JAM_DETECT_ENABLE"},
1239 {SPINEL_PROP_JAM_DETECTED, "JAM_DETECTED"},
1240 {SPINEL_PROP_JAM_DETECT_RSSI_THRESHOLD, "JAM_DETECT_RSSI_THRESHOLD"},
1241 {SPINEL_PROP_JAM_DETECT_WINDOW, "JAM_DETECT_WINDOW"},
1242 {SPINEL_PROP_JAM_DETECT_BUSY, "JAM_DETECT_BUSY"},
1243 {SPINEL_PROP_JAM_DETECT_HISTORY_BITMAP, "JAM_DETECT_HISTORY_BITMAP"},
1244 {SPINEL_PROP_CHANNEL_MONITOR_SAMPLE_INTERVAL, "CHANNEL_MONITOR_SAMPLE_INTERVAL"},
1245 {SPINEL_PROP_CHANNEL_MONITOR_RSSI_THRESHOLD, "CHANNEL_MONITOR_RSSI_THRESHOLD"},
1246 {SPINEL_PROP_CHANNEL_MONITOR_SAMPLE_WINDOW, "CHANNEL_MONITOR_SAMPLE_WINDOW"},
1247 {SPINEL_PROP_CHANNEL_MONITOR_SAMPLE_COUNT, "CHANNEL_MONITOR_SAMPLE_COUNT"},
1248 {SPINEL_PROP_CHANNEL_MONITOR_CHANNEL_OCCUPANCY, "CHANNEL_MONITOR_CHANNEL_OCCUPANCY"},
1249 {SPINEL_PROP_RADIO_CAPS, "RADIO_CAPS"},
1250 {SPINEL_PROP_RADIO_COEX_METRICS, "RADIO_COEX_METRICS"},
1251 {SPINEL_PROP_RADIO_COEX_ENABLE, "RADIO_COEX_ENABLE"},
1252 {SPINEL_PROP_MAC_SCAN_STATE, "MAC_SCAN_STATE"},
1253 {SPINEL_PROP_MAC_SCAN_MASK, "MAC_SCAN_MASK"},
1254 {SPINEL_PROP_MAC_SCAN_PERIOD, "MAC_SCAN_PERIOD"},
1255 {SPINEL_PROP_MAC_SCAN_BEACON, "MAC_SCAN_BEACON"},
1256 {SPINEL_PROP_MAC_15_4_LADDR, "MAC_15_4_LADDR"},
1257 {SPINEL_PROP_MAC_15_4_SADDR, "MAC_15_4_SADDR"},
1258 {SPINEL_PROP_MAC_15_4_PANID, "MAC_15_4_PANID"},
1259 {SPINEL_PROP_MAC_RAW_STREAM_ENABLED, "MAC_RAW_STREAM_ENABLED"},
1260 {SPINEL_PROP_MAC_PROMISCUOUS_MODE, "MAC_PROMISCUOUS_MODE"},
1261 {SPINEL_PROP_MAC_ENERGY_SCAN_RESULT, "MAC_ENERGY_SCAN_RESULT"},
1262 {SPINEL_PROP_MAC_DATA_POLL_PERIOD, "MAC_DATA_POLL_PERIOD"},
1263 {SPINEL_PROP_MAC_ALLOWLIST, "MAC_ALLOWLIST"},
1264 {SPINEL_PROP_MAC_ALLOWLIST_ENABLED, "MAC_ALLOWLIST_ENABLED"},
1265 {SPINEL_PROP_MAC_EXTENDED_ADDR, "MAC_EXTENDED_ADDR"},
1266 {SPINEL_PROP_MAC_SRC_MATCH_ENABLED, "MAC_SRC_MATCH_ENABLED"},
1267 {SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, "MAC_SRC_MATCH_SHORT_ADDRESSES"},
1268 {SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, "MAC_SRC_MATCH_EXTENDED_ADDRESSES"},
1269 {SPINEL_PROP_MAC_DENYLIST, "MAC_DENYLIST"},
1270 {SPINEL_PROP_MAC_DENYLIST_ENABLED, "MAC_DENYLIST_ENABLED"},
1271 {SPINEL_PROP_MAC_FIXED_RSS, "MAC_FIXED_RSS"},
1272 {SPINEL_PROP_MAC_CCA_FAILURE_RATE, "MAC_CCA_FAILURE_RATE"},
1273 {SPINEL_PROP_MAC_MAX_RETRY_NUMBER_DIRECT, "MAC_MAX_RETRY_NUMBER_DIRECT"},
1274 {SPINEL_PROP_MAC_MAX_RETRY_NUMBER_INDIRECT, "MAC_MAX_RETRY_NUMBER_INDIRECT"},
1275 {SPINEL_PROP_NET_SAVED, "NET_SAVED"},
1276 {SPINEL_PROP_NET_IF_UP, "NET_IF_UP"},
1277 {SPINEL_PROP_NET_STACK_UP, "NET_STACK_UP"},
1278 {SPINEL_PROP_NET_ROLE, "NET_ROLE"},
1279 {SPINEL_PROP_NET_NETWORK_NAME, "NET_NETWORK_NAME"},
1280 {SPINEL_PROP_NET_XPANID, "NET_XPANID"},
1281 {SPINEL_PROP_NET_NETWORK_KEY, "NET_NETWORK_KEY"},
1282 {SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER, "NET_KEY_SEQUENCE_COUNTER"},
1283 {SPINEL_PROP_NET_PARTITION_ID, "NET_PARTITION_ID"},
1284 {SPINEL_PROP_NET_REQUIRE_JOIN_EXISTING, "NET_REQUIRE_JOIN_EXISTING"},
1285 {SPINEL_PROP_NET_KEY_SWITCH_GUARDTIME, "NET_KEY_SWITCH_GUARDTIME"},
1286 {SPINEL_PROP_NET_PSKC, "NET_PSKC"},
1287 {SPINEL_PROP_THREAD_LEADER_ADDR, "THREAD_LEADER_ADDR"},
1288 {SPINEL_PROP_THREAD_PARENT, "THREAD_PARENT"},
1289 {SPINEL_PROP_THREAD_CHILD_TABLE, "THREAD_CHILD_TABLE"},
1290 {SPINEL_PROP_THREAD_LEADER_RID, "THREAD_LEADER_RID"},
1291 {SPINEL_PROP_THREAD_LEADER_WEIGHT, "THREAD_LEADER_WEIGHT"},
1292 {SPINEL_PROP_THREAD_LOCAL_LEADER_WEIGHT, "THREAD_LOCAL_LEADER_WEIGHT"},
1293 {SPINEL_PROP_THREAD_NETWORK_DATA, "THREAD_NETWORK_DATA"},
1294 {SPINEL_PROP_THREAD_NETWORK_DATA_VERSION, "THREAD_NETWORK_DATA_VERSION"},
1295 {SPINEL_PROP_THREAD_STABLE_NETWORK_DATA, "THREAD_STABLE_NETWORK_DATA"},
1296 {SPINEL_PROP_THREAD_STABLE_NETWORK_DATA_VERSION, "THREAD_STABLE_NETWORK_DATA_VERSION"},
1297 {SPINEL_PROP_THREAD_ON_MESH_NETS, "THREAD_ON_MESH_NETS"},
1298 {SPINEL_PROP_THREAD_OFF_MESH_ROUTES, "THREAD_OFF_MESH_ROUTES"},
1299 {SPINEL_PROP_THREAD_ASSISTING_PORTS, "THREAD_ASSISTING_PORTS"},
1300 {SPINEL_PROP_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE, "THREAD_ALLOW_LOCAL_NET_DATA_CHANGE"},
1301 {SPINEL_PROP_THREAD_MODE, "THREAD_MODE"},
1302 {SPINEL_PROP_THREAD_CHILD_TIMEOUT, "THREAD_CHILD_TIMEOUT"},
1303 {SPINEL_PROP_THREAD_RLOC16, "THREAD_RLOC16"},
1304 {SPINEL_PROP_THREAD_ROUTER_UPGRADE_THRESHOLD, "THREAD_ROUTER_UPGRADE_THRESHOLD"},
1305 {SPINEL_PROP_THREAD_CONTEXT_REUSE_DELAY, "THREAD_CONTEXT_REUSE_DELAY"},
1306 {SPINEL_PROP_THREAD_NETWORK_ID_TIMEOUT, "THREAD_NETWORK_ID_TIMEOUT"},
1307 {SPINEL_PROP_THREAD_ACTIVE_ROUTER_IDS, "THREAD_ACTIVE_ROUTER_IDS"},
1308 {SPINEL_PROP_THREAD_RLOC16_DEBUG_PASSTHRU, "THREAD_RLOC16_DEBUG_PASSTHRU"},
1309 {SPINEL_PROP_THREAD_ROUTER_ROLE_ENABLED, "THREAD_ROUTER_ROLE_ENABLED"},
1310 {SPINEL_PROP_THREAD_ROUTER_DOWNGRADE_THRESHOLD, "THREAD_ROUTER_DOWNGRADE_THRESHOLD"},
1311 {SPINEL_PROP_THREAD_ROUTER_SELECTION_JITTER, "THREAD_ROUTER_SELECTION_JITTER"},
1312 {SPINEL_PROP_THREAD_PREFERRED_ROUTER_ID, "THREAD_PREFERRED_ROUTER_ID"},
1313 {SPINEL_PROP_THREAD_NEIGHBOR_TABLE, "THREAD_NEIGHBOR_TABLE"},
1314 {SPINEL_PROP_THREAD_CHILD_COUNT_MAX, "THREAD_CHILD_COUNT_MAX"},
1315 {SPINEL_PROP_THREAD_LEADER_NETWORK_DATA, "THREAD_LEADER_NETWORK_DATA"},
1316 {SPINEL_PROP_THREAD_STABLE_LEADER_NETWORK_DATA, "THREAD_STABLE_LEADER_NETWORK_DATA"},
1317 {SPINEL_PROP_THREAD_JOINERS, "THREAD_JOINERS"},
1318 {SPINEL_PROP_THREAD_COMMISSIONER_ENABLED, "THREAD_COMMISSIONER_ENABLED"},
1319 {SPINEL_PROP_THREAD_TMF_PROXY_ENABLED, "THREAD_TMF_PROXY_ENABLED"},
1320 {SPINEL_PROP_THREAD_TMF_PROXY_STREAM, "THREAD_TMF_PROXY_STREAM"},
1321 {SPINEL_PROP_THREAD_UDP_FORWARD_STREAM, "THREAD_UDP_FORWARD_STREAM"},
1322 {SPINEL_PROP_THREAD_DISCOVERY_SCAN_JOINER_FLAG, "THREAD_DISCOVERY_SCAN_JOINER_FLAG"},
1323 {SPINEL_PROP_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING, "THREAD_DISCOVERY_SCAN_ENABLE_FILTERING"},
1324 {SPINEL_PROP_THREAD_DISCOVERY_SCAN_PANID, "THREAD_DISCOVERY_SCAN_PANID"},
1325 {SPINEL_PROP_THREAD_STEERING_DATA, "THREAD_STEERING_DATA"},
1326 {SPINEL_PROP_THREAD_ROUTER_TABLE, "THREAD_ROUTER_TABLE"},
1327 {SPINEL_PROP_THREAD_ACTIVE_DATASET, "THREAD_ACTIVE_DATASET"},
1328 {SPINEL_PROP_THREAD_PENDING_DATASET, "THREAD_PENDING_DATASET"},
1329 {SPINEL_PROP_THREAD_MGMT_SET_ACTIVE_DATASET, "THREAD_MGMT_SET_ACTIVE_DATASET"},
1330 {SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET, "THREAD_MGMT_SET_PENDING_DATASET"},
1331 {SPINEL_PROP_DATASET_ACTIVE_TIMESTAMP, "DATASET_ACTIVE_TIMESTAMP"},
1332 {SPINEL_PROP_DATASET_PENDING_TIMESTAMP, "DATASET_PENDING_TIMESTAMP"},
1333 {SPINEL_PROP_DATASET_DELAY_TIMER, "DATASET_DELAY_TIMER"},
1334 {SPINEL_PROP_DATASET_SECURITY_POLICY, "DATASET_SECURITY_POLICY"},
1335 {SPINEL_PROP_DATASET_RAW_TLVS, "DATASET_RAW_TLVS"},
1336 {SPINEL_PROP_THREAD_CHILD_TABLE_ADDRESSES, "THREAD_CHILD_TABLE_ADDRESSES"},
1337 {SPINEL_PROP_THREAD_NEIGHBOR_TABLE_ERROR_RATES, "THREAD_NEIGHBOR_TABLE_ERROR_RATES"},
1338 {SPINEL_PROP_THREAD_ADDRESS_CACHE_TABLE, "THREAD_ADDRESS_CACHE_TABLE"},
1339 {SPINEL_PROP_THREAD_MGMT_GET_ACTIVE_DATASET, "THREAD_MGMT_GET_ACTIVE_DATASET"},
1340 {SPINEL_PROP_THREAD_MGMT_GET_PENDING_DATASET, "THREAD_MGMT_GET_PENDING_DATASET"},
1341 {SPINEL_PROP_DATASET_DEST_ADDRESS, "DATASET_DEST_ADDRESS"},
1342 {SPINEL_PROP_THREAD_NEW_DATASET, "THREAD_NEW_DATASET"},
1343 {SPINEL_PROP_THREAD_CSL_PERIOD, "THREAD_CSL_PERIOD"},
1344 {SPINEL_PROP_THREAD_CSL_TIMEOUT, "THREAD_CSL_TIMEOUT"},
1345 {SPINEL_PROP_THREAD_CSL_CHANNEL, "THREAD_CSL_CHANNEL"},
1346 {SPINEL_PROP_THREAD_DOMAIN_NAME, "THREAD_DOMAIN_NAME"},
1347 {SPINEL_PROP_THREAD_LINK_METRICS_QUERY, "THREAD_LINK_METRICS_QUERY"},
1348 {SPINEL_PROP_THREAD_LINK_METRICS_QUERY_RESULT, "THREAD_LINK_METRICS_QUERY_RESULT"},
1349 {SPINEL_PROP_THREAD_LINK_METRICS_PROBE, "THREAD_LINK_METRICS_PROBE"},
1350 {SPINEL_PROP_THREAD_LINK_METRICS_MGMT_ENH_ACK, "THREAD_LINK_METRICS_MGMT_ENH_ACK"},
1351 {SPINEL_PROP_THREAD_LINK_METRICS_MGMT_ENH_ACK_IE, "THREAD_LINK_METRICS_MGMT_ENH_ACK_IE"},
1352 {SPINEL_PROP_THREAD_LINK_METRICS_MGMT_FORWARD, "THREAD_LINK_METRICS_MGMT_FORWARD"},
1353 {SPINEL_PROP_THREAD_LINK_METRICS_MGMT_RESPONSE, "THREAD_LINK_METRICS_MGMT_RESPONSE"},
1354 {SPINEL_PROP_THREAD_MLR_REQUEST, "THREAD_MLR_REQUEST"},
1355 {SPINEL_PROP_THREAD_MLR_RESPONSE, "THREAD_MLR_RESPONSE"},
1356 {SPINEL_PROP_THREAD_BACKBONE_ROUTER_PRIMARY, "THREAD_BACKBONE_ROUTER_PRIMARY"},
1357 {SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_STATE, "THREAD_BACKBONE_ROUTER_LOCAL_STATE"},
1358 {SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_CONFIG, "THREAD_BACKBONE_ROUTER_LOCAL_CONFIG"},
1359 {SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_REGISTER, "THREAD_BACKBONE_ROUTER_LOCAL_REGISTER"},
1360 {SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_REGISTRATION_JITTER,
1361 "THREAD_BACKBONE_ROUTER_LOCAL_REGISTRATION_JITTER"},
1362 {SPINEL_PROP_MESHCOP_JOINER_STATE, "MESHCOP_JOINER_STATE"},
1363 {SPINEL_PROP_MESHCOP_JOINER_COMMISSIONING, "MESHCOP_JOINER_COMMISSIONING"},
1364 {SPINEL_PROP_IPV6_LL_ADDR, "IPV6_LL_ADDR"},
1365 {SPINEL_PROP_IPV6_ML_ADDR, "IPV6_ML_ADDR"},
1366 {SPINEL_PROP_IPV6_ML_PREFIX, "IPV6_ML_PREFIX"},
1367 {SPINEL_PROP_IPV6_ADDRESS_TABLE, "IPV6_ADDRESS_TABLE"},
1368 {SPINEL_PROP_IPV6_ROUTE_TABLE, "IPV6_ROUTE_TABLE"},
1369 {SPINEL_PROP_IPV6_ICMP_PING_OFFLOAD, "IPV6_ICMP_PING_OFFLOAD"},
1370 {SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE, "IPV6_MULTICAST_ADDRESS_TABLE"},
1371 {SPINEL_PROP_IPV6_ICMP_PING_OFFLOAD_MODE, "IPV6_ICMP_PING_OFFLOAD_MODE"},
1372 {SPINEL_PROP_STREAM_DEBUG, "STREAM_DEBUG"},
1373 {SPINEL_PROP_STREAM_RAW, "STREAM_RAW"},
1374 {SPINEL_PROP_STREAM_NET, "STREAM_NET"},
1375 {SPINEL_PROP_STREAM_NET_INSECURE, "STREAM_NET_INSECURE"},
1376 {SPINEL_PROP_STREAM_LOG, "STREAM_LOG"},
1377 {SPINEL_PROP_MESHCOP_COMMISSIONER_STATE, "MESHCOP_COMMISSIONER_STATE"},
1378 {SPINEL_PROP_MESHCOP_COMMISSIONER_JOINERS, "MESHCOP_COMMISSIONER_JOINERS"},
1379 {SPINEL_PROP_MESHCOP_COMMISSIONER_PROVISIONING_URL, "MESHCOP_COMMISSIONER_PROVISIONING_URL"},
1380 {SPINEL_PROP_MESHCOP_COMMISSIONER_SESSION_ID, "MESHCOP_COMMISSIONER_SESSION_ID"},
1381 {SPINEL_PROP_MESHCOP_JOINER_DISCERNER, "MESHCOP_JOINER_DISCERNER"},
1382 {SPINEL_PROP_MESHCOP_COMMISSIONER_ANNOUNCE_BEGIN, "MESHCOP_COMMISSIONER_ANNOUNCE_BEGIN"},
1383 {SPINEL_PROP_MESHCOP_COMMISSIONER_ENERGY_SCAN, "MESHCOP_COMMISSIONER_ENERGY_SCAN"},
1384 {SPINEL_PROP_MESHCOP_COMMISSIONER_ENERGY_SCAN_RESULT, "MESHCOP_COMMISSIONER_ENERGY_SCAN_RESULT"},
1385 {SPINEL_PROP_MESHCOP_COMMISSIONER_PAN_ID_QUERY, "MESHCOP_COMMISSIONER_PAN_ID_QUERY"},
1386 {SPINEL_PROP_MESHCOP_COMMISSIONER_PAN_ID_CONFLICT_RESULT, "MESHCOP_COMMISSIONER_PAN_ID_CONFLICT_RESULT"},
1387 {SPINEL_PROP_MESHCOP_COMMISSIONER_MGMT_GET, "MESHCOP_COMMISSIONER_MGMT_GET"},
1388 {SPINEL_PROP_MESHCOP_COMMISSIONER_MGMT_SET, "MESHCOP_COMMISSIONER_MGMT_SET"},
1389 {SPINEL_PROP_MESHCOP_COMMISSIONER_GENERATE_PSKC, "MESHCOP_COMMISSIONER_GENERATE_PSKC"},
1390 {SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL, "CHANNEL_MANAGER_NEW_CHANNEL"},
1391 {SPINEL_PROP_CHANNEL_MANAGER_DELAY, "CHANNEL_MANAGER_DELAY"},
1392 {SPINEL_PROP_CHANNEL_MANAGER_SUPPORTED_CHANNELS, "CHANNEL_MANAGER_SUPPORTED_CHANNELS"},
1393 {SPINEL_PROP_CHANNEL_MANAGER_FAVORED_CHANNELS, "CHANNEL_MANAGER_FAVORED_CHANNELS"},
1394 {SPINEL_PROP_CHANNEL_MANAGER_CHANNEL_SELECT, "CHANNEL_MANAGER_CHANNEL_SELECT"},
1395 {SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_ENABLED, "CHANNEL_MANAGER_AUTO_SELECT_ENABLED"},
1396 {SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL, "CHANNEL_MANAGER_AUTO_SELECT_INTERVAL"},
1397 {SPINEL_PROP_THREAD_NETWORK_TIME, "THREAD_NETWORK_TIME"},
1398 {SPINEL_PROP_TIME_SYNC_PERIOD, "TIME_SYNC_PERIOD"},
1399 {SPINEL_PROP_TIME_SYNC_XTAL_THRESHOLD, "TIME_SYNC_XTAL_THRESHOLD"},
1400 {SPINEL_PROP_CHILD_SUPERVISION_INTERVAL, "CHILD_SUPERVISION_INTERVAL"},
1401 {SPINEL_PROP_CHILD_SUPERVISION_CHECK_TIMEOUT, "CHILD_SUPERVISION_CHECK_TIMEOUT"},
1402 {SPINEL_PROP_RCP_VERSION, "RCP_VERSION"},
1403 {SPINEL_PROP_RCP_ENH_ACK_PROBING, "ENH_ACK_PROBING"},
1404 {SPINEL_PROP_RCP_CSL_ACCURACY, "CSL_ACCURACY"},
1405 {SPINEL_PROP_RCP_CSL_UNCERTAINTY, "CSL_UNCERTAINTY"},
1406 {SPINEL_PROP_PARENT_RESPONSE_INFO, "PARENT_RESPONSE_INFO"},
1407 {SPINEL_PROP_SLAAC_ENABLED, "SLAAC_ENABLED"},
1408 {SPINEL_PROP_SUPPORTED_RADIO_LINKS, "SUPPORTED_RADIO_LINKS"},
1409 {SPINEL_PROP_NEIGHBOR_TABLE_MULTI_RADIO_INFO, "NEIGHBOR_TABLE_MULTI_RADIO_INFO"},
1410 {SPINEL_PROP_SRP_CLIENT_START, "SRP_CLIENT_START"},
1411 {SPINEL_PROP_SRP_CLIENT_LEASE_INTERVAL, "SRP_CLIENT_LEASE_INTERVAL"},
1412 {SPINEL_PROP_SRP_CLIENT_KEY_LEASE_INTERVAL, "SRP_CLIENT_KEY_LEASE_INTERVAL"},
1413 {SPINEL_PROP_SRP_CLIENT_HOST_INFO, "SRP_CLIENT_HOST_INFO"},
1414 {SPINEL_PROP_SRP_CLIENT_HOST_NAME, "SRP_CLIENT_HOST_NAME"},
1415 {SPINEL_PROP_SRP_CLIENT_HOST_ADDRESSES, "SRP_CLIENT_HOST_ADDRESSES"},
1416 {SPINEL_PROP_SRP_CLIENT_SERVICES, "SRP_CLIENT_SERVICES"},
1417 {SPINEL_PROP_SRP_CLIENT_HOST_SERVICES_REMOVE, "SRP_CLIENT_HOST_SERVICES_REMOVE"},
1418 {SPINEL_PROP_SRP_CLIENT_HOST_SERVICES_CLEAR, "SRP_CLIENT_HOST_SERVICES_CLEAR"},
1419 {SPINEL_PROP_SRP_CLIENT_EVENT, "SRP_CLIENT_EVENT"},
1420 {SPINEL_PROP_SRP_CLIENT_SERVICE_KEY_ENABLED, "SRP_CLIENT_SERVICE_KEY_ENABLED"},
1421 {SPINEL_PROP_SERVER_ALLOW_LOCAL_DATA_CHANGE, "SERVER_ALLOW_LOCAL_DATA_CHANGE"},
1422 {SPINEL_PROP_SERVER_SERVICES, "SERVER_SERVICES"},
1423 {SPINEL_PROP_SERVER_LEADER_SERVICES, "SERVER_LEADER_SERVICES"},
1424 {SPINEL_PROP_RCP_API_VERSION, "RCP_API_VERSION"},
1425 {SPINEL_PROP_UART_BITRATE, "UART_BITRATE"},
1426 {SPINEL_PROP_UART_XON_XOFF, "UART_XON_XOFF"},
1427 {SPINEL_PROP_15_4_PIB_PHY_CHANNELS_SUPPORTED, "15_4_PIB_PHY_CHANNELS_SUPPORTED"},
1428 {SPINEL_PROP_15_4_PIB_MAC_PROMISCUOUS_MODE, "15_4_PIB_MAC_PROMISCUOUS_MODE"},
1429 {SPINEL_PROP_15_4_PIB_MAC_SECURITY_ENABLED, "15_4_PIB_MAC_SECURITY_ENABLED"},
1430 {SPINEL_PROP_CNTR_RESET, "CNTR_RESET"},
1431 {SPINEL_PROP_CNTR_TX_PKT_TOTAL, "CNTR_TX_PKT_TOTAL"},
1432 {SPINEL_PROP_CNTR_TX_PKT_ACK_REQ, "CNTR_TX_PKT_ACK_REQ"},
1433 {SPINEL_PROP_CNTR_TX_PKT_ACKED, "CNTR_TX_PKT_ACKED"},
1434 {SPINEL_PROP_CNTR_TX_PKT_NO_ACK_REQ, "CNTR_TX_PKT_NO_ACK_REQ"},
1435 {SPINEL_PROP_CNTR_TX_PKT_DATA, "CNTR_TX_PKT_DATA"},
1436 {SPINEL_PROP_CNTR_TX_PKT_DATA_POLL, "CNTR_TX_PKT_DATA_POLL"},
1437 {SPINEL_PROP_CNTR_TX_PKT_BEACON, "CNTR_TX_PKT_BEACON"},
1438 {SPINEL_PROP_CNTR_TX_PKT_BEACON_REQ, "CNTR_TX_PKT_BEACON_REQ"},
1439 {SPINEL_PROP_CNTR_TX_PKT_OTHER, "CNTR_TX_PKT_OTHER"},
1440 {SPINEL_PROP_CNTR_TX_PKT_RETRY, "CNTR_TX_PKT_RETRY"},
1441 {SPINEL_PROP_CNTR_TX_ERR_CCA, "CNTR_TX_ERR_CCA"},
1442 {SPINEL_PROP_CNTR_TX_PKT_UNICAST, "CNTR_TX_PKT_UNICAST"},
1443 {SPINEL_PROP_CNTR_TX_PKT_BROADCAST, "CNTR_TX_PKT_BROADCAST"},
1444 {SPINEL_PROP_CNTR_TX_ERR_ABORT, "CNTR_TX_ERR_ABORT"},
1445 {SPINEL_PROP_CNTR_RX_PKT_TOTAL, "CNTR_RX_PKT_TOTAL"},
1446 {SPINEL_PROP_CNTR_RX_PKT_DATA, "CNTR_RX_PKT_DATA"},
1447 {SPINEL_PROP_CNTR_RX_PKT_DATA_POLL, "CNTR_RX_PKT_DATA_POLL"},
1448 {SPINEL_PROP_CNTR_RX_PKT_BEACON, "CNTR_RX_PKT_BEACON"},
1449 {SPINEL_PROP_CNTR_RX_PKT_BEACON_REQ, "CNTR_RX_PKT_BEACON_REQ"},
1450 {SPINEL_PROP_CNTR_RX_PKT_OTHER, "CNTR_RX_PKT_OTHER"},
1451 {SPINEL_PROP_CNTR_RX_PKT_FILT_WL, "CNTR_RX_PKT_FILT_WL"},
1452 {SPINEL_PROP_CNTR_RX_PKT_FILT_DA, "CNTR_RX_PKT_FILT_DA"},
1453 {SPINEL_PROP_CNTR_RX_ERR_EMPTY, "CNTR_RX_ERR_EMPTY"},
1454 {SPINEL_PROP_CNTR_RX_ERR_UKWN_NBR, "CNTR_RX_ERR_UKWN_NBR"},
1455 {SPINEL_PROP_CNTR_RX_ERR_NVLD_SADDR, "CNTR_RX_ERR_NVLD_SADDR"},
1456 {SPINEL_PROP_CNTR_RX_ERR_SECURITY, "CNTR_RX_ERR_SECURITY"},
1457 {SPINEL_PROP_CNTR_RX_ERR_BAD_FCS, "CNTR_RX_ERR_BAD_FCS"},
1458 {SPINEL_PROP_CNTR_RX_ERR_OTHER, "CNTR_RX_ERR_OTHER"},
1459 {SPINEL_PROP_CNTR_RX_PKT_DUP, "CNTR_RX_PKT_DUP"},
1460 {SPINEL_PROP_CNTR_RX_PKT_UNICAST, "CNTR_RX_PKT_UNICAST"},
1461 {SPINEL_PROP_CNTR_RX_PKT_BROADCAST, "CNTR_RX_PKT_BROADCAST"},
1462 {SPINEL_PROP_CNTR_TX_IP_SEC_TOTAL, "CNTR_TX_IP_SEC_TOTAL"},
1463 {SPINEL_PROP_CNTR_TX_IP_INSEC_TOTAL, "CNTR_TX_IP_INSEC_TOTAL"},
1464 {SPINEL_PROP_CNTR_TX_IP_DROPPED, "CNTR_TX_IP_DROPPED"},
1465 {SPINEL_PROP_CNTR_RX_IP_SEC_TOTAL, "CNTR_RX_IP_SEC_TOTAL"},
1466 {SPINEL_PROP_CNTR_RX_IP_INSEC_TOTAL, "CNTR_RX_IP_INSEC_TOTAL"},
1467 {SPINEL_PROP_CNTR_RX_IP_DROPPED, "CNTR_RX_IP_DROPPED"},
1468 {SPINEL_PROP_CNTR_TX_SPINEL_TOTAL, "CNTR_TX_SPINEL_TOTAL"},
1469 {SPINEL_PROP_CNTR_RX_SPINEL_TOTAL, "CNTR_RX_SPINEL_TOTAL"},
1470 {SPINEL_PROP_CNTR_RX_SPINEL_ERR, "CNTR_RX_SPINEL_ERR"},
1471 {SPINEL_PROP_CNTR_RX_SPINEL_OUT_OF_ORDER_TID, "CNTR_RX_SPINEL_OUT_OF_ORDER_TID"},
1472 {SPINEL_PROP_CNTR_IP_TX_SUCCESS, "CNTR_IP_TX_SUCCESS"},
1473 {SPINEL_PROP_CNTR_IP_RX_SUCCESS, "CNTR_IP_RX_SUCCESS"},
1474 {SPINEL_PROP_CNTR_IP_TX_FAILURE, "CNTR_IP_TX_FAILURE"},
1475 {SPINEL_PROP_CNTR_IP_RX_FAILURE, "CNTR_IP_RX_FAILURE"},
1476 {SPINEL_PROP_MSG_BUFFER_COUNTERS, "MSG_BUFFER_COUNTERS"},
1477 {SPINEL_PROP_CNTR_ALL_MAC_COUNTERS, "CNTR_ALL_MAC_COUNTERS"},
1478 {SPINEL_PROP_CNTR_MLE_COUNTERS, "CNTR_MLE_COUNTERS"},
1479 {SPINEL_PROP_CNTR_ALL_IP_COUNTERS, "CNTR_ALL_IP_COUNTERS"},
1480 {SPINEL_PROP_CNTR_MAC_RETRY_HISTOGRAM, "CNTR_MAC_RETRY_HISTOGRAM"},
1481 {SPINEL_PROP_NEST_STREAM_MFG, "NEST_STREAM_MFG"},
1482 {SPINEL_PROP_NEST_LEGACY_ULA_PREFIX, "NEST_LEGACY_ULA_PREFIX"},
1483 {SPINEL_PROP_NEST_LEGACY_LAST_NODE_JOINED, "NEST_LEGACY_LAST_NODE_JOINED"},
1484 {SPINEL_PROP_DEBUG_TEST_ASSERT, "DEBUG_TEST_ASSERT"},
1485 {SPINEL_PROP_DEBUG_NCP_LOG_LEVEL, "DEBUG_NCP_LOG_LEVEL"},
1486 {SPINEL_PROP_DEBUG_TEST_WATCHDOG, "DEBUG_TEST_WATCHDOG"},
1487 {SPINEL_PROP_RCP_MAC_FRAME_COUNTER, "RCP_MAC_FRAME_COUNTER"},
1488 {SPINEL_PROP_RCP_MAC_KEY, "RCP_MAC_KEY"},
1489 {SPINEL_PROP_DEBUG_LOG_TIMESTAMP_BASE, "DEBUG_LOG_TIMESTAMP_BASE"},
1490 {SPINEL_PROP_DEBUG_TREL_TEST_MODE_ENABLE, "DEBUG_TREL_TEST_MODE_ENABLE"},
1491 {0, NULL},
1492 };
1493
1494 return spinel_to_cstr(spinel_prop_cstr, prop_key);
1495 }
1496
spinel_net_role_to_cstr(uint8_t net_role)1497 const char *spinel_net_role_to_cstr(uint8_t net_role)
1498 {
1499 static const struct spinel_cstr spinel_net_cstr[] = {
1500 {SPINEL_NET_ROLE_DETACHED, "NET_ROLE_DETACHED"},
1501 {SPINEL_NET_ROLE_CHILD, "NET_ROLE_CHILD"},
1502 {SPINEL_NET_ROLE_ROUTER, "NET_ROLE_ROUTER"},
1503 {SPINEL_NET_ROLE_LEADER, "NET_ROLE_LEADER"},
1504 {0, NULL},
1505 };
1506
1507 return spinel_to_cstr(spinel_net_cstr, net_role);
1508 }
1509
spinel_mcu_power_state_to_cstr(uint8_t mcu_power_state)1510 const char *spinel_mcu_power_state_to_cstr(uint8_t mcu_power_state)
1511 {
1512 static const struct spinel_cstr spinel_mcu_power_state_cstr[] = {
1513 {SPINEL_MCU_POWER_STATE_ON, "MCU_POWER_STATE_ON"},
1514 {SPINEL_MCU_POWER_STATE_LOW_POWER, "MCU_POWER_STATE_LOW_POWER"},
1515 {SPINEL_MCU_POWER_STATE_OFF, "MCU_POWER_STATE_OFF"},
1516 {0, NULL},
1517 };
1518
1519 return spinel_to_cstr(spinel_mcu_power_state_cstr, mcu_power_state);
1520 }
1521
spinel_status_to_cstr(spinel_status_t status)1522 const char *spinel_status_to_cstr(spinel_status_t status)
1523 {
1524 static const struct spinel_cstr spinel_status_cstr[] = {
1525 {SPINEL_STATUS_OK, "OK"},
1526 {SPINEL_STATUS_FAILURE, "FAILURE"},
1527 {SPINEL_STATUS_UNIMPLEMENTED, "UNIMPLEMENTED"},
1528 {SPINEL_STATUS_INVALID_ARGUMENT, "INVALID_ARGUMENT"},
1529 {SPINEL_STATUS_INVALID_STATE, "INVALID_STATE"},
1530 {SPINEL_STATUS_INVALID_COMMAND, "INVALID_COMMAND"},
1531 {SPINEL_STATUS_INVALID_INTERFACE, "INVALID_INTERFACE"},
1532 {SPINEL_STATUS_INTERNAL_ERROR, "INTERNAL_ERROR"},
1533 {SPINEL_STATUS_SECURITY_ERROR, "SECURITY_ERROR"},
1534 {SPINEL_STATUS_PARSE_ERROR, "PARSE_ERROR"},
1535 {SPINEL_STATUS_IN_PROGRESS, "IN_PROGRESS"},
1536 {SPINEL_STATUS_NOMEM, "NOMEM"},
1537 {SPINEL_STATUS_BUSY, "BUSY"},
1538 {SPINEL_STATUS_PROP_NOT_FOUND, "PROP_NOT_FOUND"},
1539 {SPINEL_STATUS_DROPPED, "DROPPED"},
1540 {SPINEL_STATUS_EMPTY, "EMPTY"},
1541 {SPINEL_STATUS_CMD_TOO_BIG, "CMD_TOO_BIG"},
1542 {SPINEL_STATUS_NO_ACK, "NO_ACK"},
1543 {SPINEL_STATUS_CCA_FAILURE, "CCA_FAILURE"},
1544 {SPINEL_STATUS_ALREADY, "ALREADY"},
1545 {SPINEL_STATUS_ITEM_NOT_FOUND, "ITEM_NOT_FOUND"},
1546 {SPINEL_STATUS_INVALID_COMMAND_FOR_PROP, "INVALID_COMMAND_FOR_PROP"},
1547 {SPINEL_STATUS_RESPONSE_TIMEOUT, "RESPONSE_TIMEOUT"},
1548 {SPINEL_STATUS_JOIN_FAILURE, "JOIN_FAILURE"},
1549 {SPINEL_STATUS_JOIN_SECURITY, "JOIN_SECURITY"},
1550 {SPINEL_STATUS_JOIN_NO_PEERS, "JOIN_NO_PEERS"},
1551 {SPINEL_STATUS_JOIN_INCOMPATIBLE, "JOIN_INCOMPATIBLE"},
1552 {SPINEL_STATUS_JOIN_RSP_TIMEOUT, "JOIN_RSP_TIMEOUT"},
1553 {SPINEL_STATUS_JOIN_SUCCESS, "JOIN_SUCCESS"},
1554 {SPINEL_STATUS_RESET_POWER_ON, "RESET_POWER_ON"},
1555 {SPINEL_STATUS_RESET_EXTERNAL, "RESET_EXTERNAL"},
1556 {SPINEL_STATUS_RESET_SOFTWARE, "RESET_SOFTWARE"},
1557 {SPINEL_STATUS_RESET_FAULT, "RESET_FAULT"},
1558 {SPINEL_STATUS_RESET_CRASH, "RESET_CRASH"},
1559 {SPINEL_STATUS_RESET_ASSERT, "RESET_ASSERT"},
1560 {SPINEL_STATUS_RESET_OTHER, "RESET_OTHER"},
1561 {SPINEL_STATUS_RESET_UNKNOWN, "RESET_UNKNOWN"},
1562 {SPINEL_STATUS_RESET_WATCHDOG, "RESET_WATCHDOG"},
1563 {0, NULL},
1564 };
1565
1566 return spinel_to_cstr(spinel_status_cstr, status);
1567 }
1568
spinel_capability_to_cstr(spinel_capability_t capability)1569 const char *spinel_capability_to_cstr(spinel_capability_t capability)
1570 {
1571 static const struct spinel_cstr spinel_cap_cstr[] = {
1572 {SPINEL_CAP_LOCK, "LOCK"},
1573 {SPINEL_CAP_NET_SAVE, "NET_SAVE"},
1574 {SPINEL_CAP_HBO, "HBO"},
1575 {SPINEL_CAP_POWER_SAVE, "POWER_SAVE"},
1576 {SPINEL_CAP_COUNTERS, "COUNTERS"},
1577 {SPINEL_CAP_JAM_DETECT, "JAM_DETECT"},
1578 {SPINEL_CAP_PEEK_POKE, "PEEK_POKE"},
1579 {SPINEL_CAP_WRITABLE_RAW_STREAM, "WRITABLE_RAW_STREAM"},
1580 {SPINEL_CAP_GPIO, "GPIO"},
1581 {SPINEL_CAP_TRNG, "TRNG"},
1582 {SPINEL_CAP_CMD_MULTI, "CMD_MULTI"},
1583 {SPINEL_CAP_UNSOL_UPDATE_FILTER, "UNSOL_UPDATE_FILTER"},
1584 {SPINEL_CAP_MCU_POWER_STATE, "MCU_POWER_STATE"},
1585 {SPINEL_CAP_PCAP, "PCAP"},
1586 {SPINEL_CAP_802_15_4_2003, "802_15_4_2003"},
1587 {SPINEL_CAP_802_15_4_2006, "802_15_4_2006"},
1588 {SPINEL_CAP_802_15_4_2011, "802_15_4_2011"},
1589 {SPINEL_CAP_802_15_4_PIB, "802_15_4_PIB"},
1590 {SPINEL_CAP_802_15_4_2450MHZ_OQPSK, "802_15_4_2450MHZ_OQPSK"},
1591 {SPINEL_CAP_802_15_4_915MHZ_OQPSK, "802_15_4_915MHZ_OQPSK"},
1592 {SPINEL_CAP_802_15_4_868MHZ_OQPSK, "802_15_4_868MHZ_OQPSK"},
1593 {SPINEL_CAP_802_15_4_915MHZ_BPSK, "802_15_4_915MHZ_BPSK"},
1594 {SPINEL_CAP_802_15_4_868MHZ_BPSK, "802_15_4_868MHZ_BPSK"},
1595 {SPINEL_CAP_802_15_4_915MHZ_ASK, "802_15_4_915MHZ_ASK"},
1596 {SPINEL_CAP_802_15_4_868MHZ_ASK, "802_15_4_868MHZ_ASK"},
1597 {SPINEL_CAP_CONFIG_FTD, "CONFIG_FTD"},
1598 {SPINEL_CAP_CONFIG_MTD, "CONFIG_MTD"},
1599 {SPINEL_CAP_CONFIG_RADIO, "CONFIG_RADIO"},
1600 {SPINEL_CAP_ROLE_ROUTER, "ROLE_ROUTER"},
1601 {SPINEL_CAP_ROLE_SLEEPY, "ROLE_SLEEPY"},
1602 {SPINEL_CAP_NET_THREAD_1_0, "NET_THREAD_1_0"},
1603 {SPINEL_CAP_NET_THREAD_1_1, "NET_THREAD_1_1"},
1604 {SPINEL_CAP_NET_THREAD_1_2, "NET_THREAD_1_2"},
1605 {SPINEL_CAP_RCP_API_VERSION, "RCP_API_VERSION"},
1606 {SPINEL_CAP_MAC_ALLOWLIST, "MAC_ALLOWLIST"},
1607 {SPINEL_CAP_MAC_RAW, "MAC_RAW"},
1608 {SPINEL_CAP_OOB_STEERING_DATA, "OOB_STEERING_DATA"},
1609 {SPINEL_CAP_CHANNEL_MONITOR, "CHANNEL_MONITOR"},
1610 {SPINEL_CAP_CHANNEL_MANAGER, "CHANNEL_MANAGER"},
1611 {SPINEL_CAP_OPENTHREAD_LOG_METADATA, "OPENTHREAD_LOG_METADATA"},
1612 {SPINEL_CAP_TIME_SYNC, "TIME_SYNC"},
1613 {SPINEL_CAP_CHILD_SUPERVISION, "CHILD_SUPERVISION"},
1614 {SPINEL_CAP_POSIX, "POSIX"},
1615 {SPINEL_CAP_SLAAC, "SLAAC"},
1616 {SPINEL_CAP_RADIO_COEX, "RADIO_COEX"},
1617 {SPINEL_CAP_MAC_RETRY_HISTOGRAM, "MAC_RETRY_HISTOGRAM"},
1618 {SPINEL_CAP_MULTI_RADIO, "MULTI_RADIO"},
1619 {SPINEL_CAP_SRP_CLIENT, "SRP_CLIENT"},
1620 {SPINEL_CAP_DUA, "DUA"},
1621 {SPINEL_CAP_REFERENCE_DEVICE, "REFERENCE_DEVICE"},
1622 {SPINEL_CAP_ERROR_RATE_TRACKING, "ERROR_RATE_TRACKING"},
1623 {SPINEL_CAP_THREAD_COMMISSIONER, "THREAD_COMMISSIONER"},
1624 {SPINEL_CAP_THREAD_TMF_PROXY, "THREAD_TMF_PROXY"},
1625 {SPINEL_CAP_THREAD_UDP_FORWARD, "THREAD_UDP_FORWARD"},
1626 {SPINEL_CAP_THREAD_JOINER, "THREAD_JOINER"},
1627 {SPINEL_CAP_THREAD_BORDER_ROUTER, "THREAD_BORDER_ROUTER"},
1628 {SPINEL_CAP_THREAD_SERVICE, "THREAD_SERVICE"},
1629 {SPINEL_CAP_THREAD_CSL_RECEIVER, "THREAD_CSL_RECEIVER"},
1630 {SPINEL_CAP_THREAD_BACKBONE_ROUTER, "THREAD_BACKBONE_ROUTER"},
1631 {SPINEL_CAP_NEST_LEGACY_INTERFACE, "NEST_LEGACY_INTERFACE"},
1632 {SPINEL_CAP_NEST_LEGACY_NET_WAKE, "NEST_LEGACY_NET_WAKE"},
1633 {SPINEL_CAP_NEST_TRANSMIT_HOOK, "NEST_TRANSMIT_HOOK"},
1634 {0, NULL},
1635 };
1636
1637 return spinel_to_cstr(spinel_cap_cstr, capability);
1638 }
1639
1640 // LCOV_EXCL_STOP
1641
1642 /* -------------------------------------------------------------------------- */
1643
1644 #if SPINEL_SELF_TEST
1645
main(void)1646 int main(void)
1647 {
1648 int ret = -1;
1649 const spinel_eui64_t static_eui64 = {{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}};
1650 const char static_string[] = "static_string";
1651 uint8_t buffer[1024];
1652 ssize_t len;
1653
1654 len =
1655 spinel_datatype_pack(buffer, sizeof(buffer), "CiiLUE", 0x88, 9, 0xA3, 0xDEADBEEF, static_string, &static_eui64);
1656
1657 if (len != 30)
1658 {
1659 printf("error:%d: len != 30; (%d)\n", __LINE__, (int)len);
1660 goto bail;
1661 }
1662
1663 {
1664 const char *str = NULL;
1665
1666 // Length ends right before the string.
1667 len = spinel_datatype_unpack(buffer, 8, "CiiLU", NULL, NULL, NULL, NULL, &str);
1668
1669 if (len != -1)
1670 {
1671 printf("error:%d: len != -1; (%d)\n", __LINE__, (int)len);
1672 goto bail;
1673 }
1674
1675 if (str != NULL)
1676 {
1677 printf("error:%d: str != NULL\n", __LINE__);
1678 goto bail;
1679 }
1680 }
1681
1682 len = 30;
1683
1684 {
1685 uint8_t c = 0;
1686 unsigned int i1 = 0;
1687 unsigned int i2 = 0;
1688 uint32_t l = 0;
1689 const char * str = NULL;
1690 const spinel_eui64_t *eui64 = NULL;
1691
1692 len = spinel_datatype_unpack(buffer, (spinel_size_t)len, "CiiLUE", &c, &i1, &i2, &l, &str, &eui64);
1693
1694 if (len != 30)
1695 {
1696 printf("error:%d: len != 30; (%d)\n", __LINE__, (int)len);
1697 goto bail;
1698 }
1699
1700 if (c != 0x88)
1701 {
1702 printf("error: x != 0x88; (%d)\n", c);
1703 goto bail;
1704 }
1705
1706 if (i1 != 9)
1707 {
1708 printf("error: i1 != 9; (%d)\n", i1);
1709 goto bail;
1710 }
1711
1712 if (i2 != 0xA3)
1713 {
1714 printf("error: i2 != 0xA3; (0x%02X)\n", i2);
1715 goto bail;
1716 }
1717
1718 if (l != 0xDEADBEEF)
1719 {
1720 printf("error: l != 0xDEADBEEF; (0x%08X)\n", (unsigned int)l);
1721 goto bail;
1722 }
1723
1724 if (strcmp(str, static_string) != 0)
1725 {
1726 printf("error:%d: strcmp(str,static_string) != 0\n", __LINE__);
1727 goto bail;
1728 }
1729
1730 if (memcmp(eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0)
1731 {
1732 printf("error:%d: memcmp(eui64, &eui64, sizeof(spinel_eui64_t)) != 0\n", __LINE__);
1733 goto bail;
1734 }
1735 }
1736
1737 {
1738 uint8_t c = 0;
1739 unsigned int i1 = 0;
1740 unsigned int i2 = 0;
1741 uint32_t l = 0;
1742 char str[sizeof(static_string)];
1743 spinel_eui64_t eui64 = {{0}};
1744
1745 len = spinel_datatype_unpack_in_place(buffer, (spinel_size_t)len, "CiiLUE", &c, &i1, &i2, &l, &str, sizeof(str),
1746 &eui64);
1747
1748 if (len != 30)
1749 {
1750 printf("error:%d: len != 30; (%d)\n", __LINE__, (int)len);
1751 goto bail;
1752 }
1753
1754 if (c != 0x88)
1755 {
1756 printf("error: x != 0x88; (%d)\n", c);
1757 goto bail;
1758 }
1759
1760 if (i1 != 9)
1761 {
1762 printf("error: i1 != 9; (%d)\n", i1);
1763 goto bail;
1764 }
1765
1766 if (i2 != 0xA3)
1767 {
1768 printf("error: i2 != 0xA3; (0x%02X)\n", i2);
1769 goto bail;
1770 }
1771
1772 if (l != 0xDEADBEEF)
1773 {
1774 printf("error: l != 0xDEADBEEF; (0x%08X)\n", (unsigned int)l);
1775 goto bail;
1776 }
1777
1778 if (strcmp(str, static_string) != 0)
1779 {
1780 printf("error:%d: strcmp(str,static_string) != 0\n", __LINE__);
1781 goto bail;
1782 }
1783
1784 if (memcmp(&eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0)
1785 {
1786 printf("error:%d: memcmp(&eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0\n", __LINE__);
1787 goto bail;
1788 }
1789 }
1790
1791 // -----------------------------------
1792
1793 memset(buffer, 0xAA, sizeof(buffer));
1794
1795 len = spinel_datatype_pack(buffer, sizeof(buffer), "Cit(iL)UE", 0x88, 9, 0xA3, 0xDEADBEEF, static_string,
1796 &static_eui64);
1797
1798 if (len != 32)
1799 {
1800 printf("error:%d: len != 32; (%d)\n", __LINE__, (int)len);
1801 goto bail;
1802 }
1803
1804 {
1805 uint8_t c = 0;
1806 unsigned int i1 = 0;
1807 unsigned int i2 = 0;
1808 uint32_t l = 0;
1809 const char * str = NULL;
1810 spinel_eui64_t *eui64 = NULL;
1811
1812 len = spinel_datatype_unpack(buffer, (spinel_size_t)len, "Cit(iL)UE", &c, &i1, &i2, &l, &str, &eui64);
1813
1814 if (len != 32)
1815 {
1816 printf("error:%d: len != 24; (%d)\n", __LINE__, (int)len);
1817 goto bail;
1818 }
1819
1820 if (c != 0x88)
1821 {
1822 printf("error: x != 0x88; (%d)\n", c);
1823 goto bail;
1824 }
1825
1826 if (i1 != 9)
1827 {
1828 printf("error: i1 != 9; (%d)\n", i1);
1829 goto bail;
1830 }
1831
1832 if (i2 != 0xA3)
1833 {
1834 printf("error: i2 != 0xA3; (0x%02X)\n", i2);
1835 goto bail;
1836 }
1837
1838 if (l != 0xDEADBEEF)
1839 {
1840 printf("error: l != 0xDEADBEEF; (0x%08X)\n", (unsigned int)l);
1841 goto bail;
1842 }
1843
1844 if (strcmp(str, static_string) != 0)
1845 {
1846 printf("error:%d: strcmp(str,static_string) != 0\n", __LINE__);
1847 goto bail;
1848 }
1849
1850 if (memcmp(eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0)
1851 {
1852 printf("error:%d: memcmp(eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0\n", __LINE__);
1853 goto bail;
1854 }
1855 }
1856
1857 {
1858 uint8_t c = 0;
1859 unsigned int i1 = 0;
1860 unsigned int i2 = 0;
1861 uint32_t l = 0;
1862 char str[sizeof(static_string)];
1863 spinel_eui64_t eui64 = {{0}};
1864
1865 len = spinel_datatype_unpack_in_place(buffer, (spinel_size_t)len, "Cit(iL)UE", &c, &i1, &i2, &l, &str,
1866 sizeof(str), &eui64);
1867
1868 if (len != 32)
1869 {
1870 printf("error:%d: len != 24; (%d)\n", __LINE__, (int)len);
1871 goto bail;
1872 }
1873
1874 if (c != 0x88)
1875 {
1876 printf("error: x != 0x88; (%d)\n", c);
1877 goto bail;
1878 }
1879
1880 if (i1 != 9)
1881 {
1882 printf("error: i1 != 9; (%d)\n", i1);
1883 goto bail;
1884 }
1885
1886 if (i2 != 0xA3)
1887 {
1888 printf("error: i2 != 0xA3; (0x%02X)\n", i2);
1889 goto bail;
1890 }
1891
1892 if (l != 0xDEADBEEF)
1893 {
1894 printf("error: l != 0xDEADBEEF; (0x%08X)\n", (unsigned int)l);
1895 goto bail;
1896 }
1897
1898 if (strcmp(str, static_string) != 0)
1899 {
1900 printf("error:%d: strcmp(str,static_string) != 0\n", __LINE__);
1901 goto bail;
1902 }
1903
1904 if (memcmp(&eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0)
1905 {
1906 printf("error:%d: memcmp(&eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0\n", __LINE__);
1907 goto bail;
1908 }
1909 }
1910
1911 {
1912 // Test UTF8 validation - Good/Valid strings
1913
1914 // Single symbols
1915 const uint8_t single1[] = {0}; // 0000
1916 const uint8_t single2[] = {0x7F, 0x00}; // 007F
1917 const uint8_t single3[] = {0xC2, 0x80, 0x00}; // 080
1918 const uint8_t single4[] = {0xDF, 0xBF, 0x00}; // 07FF
1919 const uint8_t single5[] = {0xE0, 0xA0, 0x80, 0x00}; // 0800
1920 const uint8_t single6[] = {0xEF, 0xBF, 0xBF, 0x00}; // FFFF
1921 const uint8_t single7[] = {0xF0, 0x90, 0x80, 0x80, 0x00}; // 010000
1922 const uint8_t single8[] = {0xF4, 0x8F, 0xBF, 0xBF, 0x00}; // 10FFFF
1923
1924 // Strings
1925 const uint8_t str1[] = "spinel";
1926 const uint8_t str2[] = "OpenThread";
1927 const uint8_t str3[] = {0x41, 0x7F, 0xEF, 0xBF, 0xBF, 0xC2, 0x80, 0x21, 0x33, 0x00};
1928 const uint8_t str4[] = {0xCE, 0xBA, 0xE1, 0xBD, 0xB9, 0xCF, 0x83, 0xCE, 0xBC, 0xCE, 0xB5, 0x00}; // κόσμε
1929 const uint8_t str5[] = {0x3D, 0xF4, 0x8F, 0xBF, 0xBF, 0x01, 0xE0, 0xA0, 0x83, 0x22, 0xEF, 0xBF, 0xBF, 0x00};
1930 const uint8_t str6[] = {0xE5, 0xA2, 0x82, 0xE0, 0xA0, 0x80, 0xC2, 0x83, 0xC2, 0x80, 0xF4,
1931 0x8F, 0xBF, 0xBF, 0xF4, 0x8F, 0xBF, 0xBF, 0xDF, 0xBF, 0x21, 0x00};
1932
1933 const uint8_t * good_strings[] = {single1, single2, single3, single4, single5, single6, single7, single8,
1934 str1, str2, str3, str4, str5, str6, NULL};
1935 const uint8_t **str_ptr;
1936
1937 for (str_ptr = &good_strings[0]; *str_ptr != NULL; str_ptr++)
1938 {
1939 if (!spinel_validate_utf8(*str_ptr))
1940 {
1941 printf("error: spinel_validate_utf8() did not correctly detect a valid UTF8 sequence!\n");
1942 goto bail;
1943 }
1944 }
1945 }
1946
1947 {
1948 // Test UTF8 validation - Bad/Invalid strings
1949
1950 // Single symbols (invalid)
1951 const uint8_t single1[] = {0xF8, 0x00};
1952 const uint8_t single2[] = {0xF9, 0x00};
1953 const uint8_t single3[] = {0xFA, 0x00};
1954 const uint8_t single4[] = {0xFF, 0x00};
1955
1956 // Bad continuations
1957 const uint8_t bad1[] = {0xDF, 0x0F, 0x00};
1958 const uint8_t bad2[] = {0xE0, 0xA0, 0x10, 0x00};
1959 const uint8_t bad3[] = {0xF0, 0x90, 0x80, 0x60, 0x00};
1960 const uint8_t bad4[] = {0xF4, 0x8F, 0xBF, 0x0F, 0x00};
1961 const uint8_t bad5[] = {0x21, 0xA0, 0x00};
1962 const uint8_t bad6[] = {0xCE, 0xBA, 0xE1, 0xBD, 0xB9, 0xCF, 0x83, 0xCE, 0xBC, 0xCE, 0x00};
1963
1964 const uint8_t * bad_strings[] = {single1, single2, single3, single4, bad1, bad2, bad3, bad4, bad5, bad6, NULL};
1965 const uint8_t **str_ptr;
1966
1967 for (str_ptr = &bad_strings[0]; *str_ptr != NULL; str_ptr++)
1968 {
1969 if (spinel_validate_utf8(*str_ptr))
1970 {
1971 printf("error: spinel_validate_utf8() did not correctly detect an invalid UTF8 sequence\n");
1972 goto bail;
1973 }
1974 }
1975 }
1976
1977 printf("OK\n");
1978 ret = 0;
1979 return ret;
1980
1981 bail:
1982 printf("FAILURE\n");
1983 return ret;
1984 }
1985
1986 #endif // #if SPINEL_SELF_TEST
1987