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_PARENT_RESPONSE_INFO, "PARENT_RESPONSE_INFO"},
1404         {SPINEL_PROP_SLAAC_ENABLED, "SLAAC_ENABLED"},
1405         {SPINEL_PROP_SUPPORTED_RADIO_LINKS, "SUPPORTED_RADIO_LINKS"},
1406         {SPINEL_PROP_NEIGHBOR_TABLE_MULTI_RADIO_INFO, "NEIGHBOR_TABLE_MULTI_RADIO_INFO"},
1407         {SPINEL_PROP_SRP_CLIENT_START, "SRP_CLIENT_START"},
1408         {SPINEL_PROP_SRP_CLIENT_LEASE_INTERVAL, "SRP_CLIENT_LEASE_INTERVAL"},
1409         {SPINEL_PROP_SRP_CLIENT_KEY_LEASE_INTERVAL, "SRP_CLIENT_KEY_LEASE_INTERVAL"},
1410         {SPINEL_PROP_SRP_CLIENT_HOST_INFO, "SRP_CLIENT_HOST_INFO"},
1411         {SPINEL_PROP_SRP_CLIENT_HOST_NAME, "SRP_CLIENT_HOST_NAME"},
1412         {SPINEL_PROP_SRP_CLIENT_HOST_ADDRESSES, "SRP_CLIENT_HOST_ADDRESSES"},
1413         {SPINEL_PROP_SRP_CLIENT_SERVICES, "SRP_CLIENT_SERVICES"},
1414         {SPINEL_PROP_SRP_CLIENT_HOST_SERVICES_REMOVE, "SRP_CLIENT_HOST_SERVICES_REMOVE"},
1415         {SPINEL_PROP_SRP_CLIENT_HOST_SERVICES_CLEAR, "SRP_CLIENT_HOST_SERVICES_CLEAR"},
1416         {SPINEL_PROP_SRP_CLIENT_EVENT, "SRP_CLIENT_EVENT"},
1417         {SPINEL_PROP_SRP_CLIENT_SERVICE_KEY_ENABLED, "SRP_CLIENT_SERVICE_KEY_ENABLED"},
1418         {SPINEL_PROP_SERVER_ALLOW_LOCAL_DATA_CHANGE, "SERVER_ALLOW_LOCAL_DATA_CHANGE"},
1419         {SPINEL_PROP_SERVER_SERVICES, "SERVER_SERVICES"},
1420         {SPINEL_PROP_SERVER_LEADER_SERVICES, "SERVER_LEADER_SERVICES"},
1421         {SPINEL_PROP_RCP_API_VERSION, "RCP_API_VERSION"},
1422         {SPINEL_PROP_UART_BITRATE, "UART_BITRATE"},
1423         {SPINEL_PROP_UART_XON_XOFF, "UART_XON_XOFF"},
1424         {SPINEL_PROP_15_4_PIB_PHY_CHANNELS_SUPPORTED, "15_4_PIB_PHY_CHANNELS_SUPPORTED"},
1425         {SPINEL_PROP_15_4_PIB_MAC_PROMISCUOUS_MODE, "15_4_PIB_MAC_PROMISCUOUS_MODE"},
1426         {SPINEL_PROP_15_4_PIB_MAC_SECURITY_ENABLED, "15_4_PIB_MAC_SECURITY_ENABLED"},
1427         {SPINEL_PROP_CNTR_RESET, "CNTR_RESET"},
1428         {SPINEL_PROP_CNTR_TX_PKT_TOTAL, "CNTR_TX_PKT_TOTAL"},
1429         {SPINEL_PROP_CNTR_TX_PKT_ACK_REQ, "CNTR_TX_PKT_ACK_REQ"},
1430         {SPINEL_PROP_CNTR_TX_PKT_ACKED, "CNTR_TX_PKT_ACKED"},
1431         {SPINEL_PROP_CNTR_TX_PKT_NO_ACK_REQ, "CNTR_TX_PKT_NO_ACK_REQ"},
1432         {SPINEL_PROP_CNTR_TX_PKT_DATA, "CNTR_TX_PKT_DATA"},
1433         {SPINEL_PROP_CNTR_TX_PKT_DATA_POLL, "CNTR_TX_PKT_DATA_POLL"},
1434         {SPINEL_PROP_CNTR_TX_PKT_BEACON, "CNTR_TX_PKT_BEACON"},
1435         {SPINEL_PROP_CNTR_TX_PKT_BEACON_REQ, "CNTR_TX_PKT_BEACON_REQ"},
1436         {SPINEL_PROP_CNTR_TX_PKT_OTHER, "CNTR_TX_PKT_OTHER"},
1437         {SPINEL_PROP_CNTR_TX_PKT_RETRY, "CNTR_TX_PKT_RETRY"},
1438         {SPINEL_PROP_CNTR_TX_ERR_CCA, "CNTR_TX_ERR_CCA"},
1439         {SPINEL_PROP_CNTR_TX_PKT_UNICAST, "CNTR_TX_PKT_UNICAST"},
1440         {SPINEL_PROP_CNTR_TX_PKT_BROADCAST, "CNTR_TX_PKT_BROADCAST"},
1441         {SPINEL_PROP_CNTR_TX_ERR_ABORT, "CNTR_TX_ERR_ABORT"},
1442         {SPINEL_PROP_CNTR_RX_PKT_TOTAL, "CNTR_RX_PKT_TOTAL"},
1443         {SPINEL_PROP_CNTR_RX_PKT_DATA, "CNTR_RX_PKT_DATA"},
1444         {SPINEL_PROP_CNTR_RX_PKT_DATA_POLL, "CNTR_RX_PKT_DATA_POLL"},
1445         {SPINEL_PROP_CNTR_RX_PKT_BEACON, "CNTR_RX_PKT_BEACON"},
1446         {SPINEL_PROP_CNTR_RX_PKT_BEACON_REQ, "CNTR_RX_PKT_BEACON_REQ"},
1447         {SPINEL_PROP_CNTR_RX_PKT_OTHER, "CNTR_RX_PKT_OTHER"},
1448         {SPINEL_PROP_CNTR_RX_PKT_FILT_WL, "CNTR_RX_PKT_FILT_WL"},
1449         {SPINEL_PROP_CNTR_RX_PKT_FILT_DA, "CNTR_RX_PKT_FILT_DA"},
1450         {SPINEL_PROP_CNTR_RX_ERR_EMPTY, "CNTR_RX_ERR_EMPTY"},
1451         {SPINEL_PROP_CNTR_RX_ERR_UKWN_NBR, "CNTR_RX_ERR_UKWN_NBR"},
1452         {SPINEL_PROP_CNTR_RX_ERR_NVLD_SADDR, "CNTR_RX_ERR_NVLD_SADDR"},
1453         {SPINEL_PROP_CNTR_RX_ERR_SECURITY, "CNTR_RX_ERR_SECURITY"},
1454         {SPINEL_PROP_CNTR_RX_ERR_BAD_FCS, "CNTR_RX_ERR_BAD_FCS"},
1455         {SPINEL_PROP_CNTR_RX_ERR_OTHER, "CNTR_RX_ERR_OTHER"},
1456         {SPINEL_PROP_CNTR_RX_PKT_DUP, "CNTR_RX_PKT_DUP"},
1457         {SPINEL_PROP_CNTR_RX_PKT_UNICAST, "CNTR_RX_PKT_UNICAST"},
1458         {SPINEL_PROP_CNTR_RX_PKT_BROADCAST, "CNTR_RX_PKT_BROADCAST"},
1459         {SPINEL_PROP_CNTR_TX_IP_SEC_TOTAL, "CNTR_TX_IP_SEC_TOTAL"},
1460         {SPINEL_PROP_CNTR_TX_IP_INSEC_TOTAL, "CNTR_TX_IP_INSEC_TOTAL"},
1461         {SPINEL_PROP_CNTR_TX_IP_DROPPED, "CNTR_TX_IP_DROPPED"},
1462         {SPINEL_PROP_CNTR_RX_IP_SEC_TOTAL, "CNTR_RX_IP_SEC_TOTAL"},
1463         {SPINEL_PROP_CNTR_RX_IP_INSEC_TOTAL, "CNTR_RX_IP_INSEC_TOTAL"},
1464         {SPINEL_PROP_CNTR_RX_IP_DROPPED, "CNTR_RX_IP_DROPPED"},
1465         {SPINEL_PROP_CNTR_TX_SPINEL_TOTAL, "CNTR_TX_SPINEL_TOTAL"},
1466         {SPINEL_PROP_CNTR_RX_SPINEL_TOTAL, "CNTR_RX_SPINEL_TOTAL"},
1467         {SPINEL_PROP_CNTR_RX_SPINEL_ERR, "CNTR_RX_SPINEL_ERR"},
1468         {SPINEL_PROP_CNTR_RX_SPINEL_OUT_OF_ORDER_TID, "CNTR_RX_SPINEL_OUT_OF_ORDER_TID"},
1469         {SPINEL_PROP_CNTR_IP_TX_SUCCESS, "CNTR_IP_TX_SUCCESS"},
1470         {SPINEL_PROP_CNTR_IP_RX_SUCCESS, "CNTR_IP_RX_SUCCESS"},
1471         {SPINEL_PROP_CNTR_IP_TX_FAILURE, "CNTR_IP_TX_FAILURE"},
1472         {SPINEL_PROP_CNTR_IP_RX_FAILURE, "CNTR_IP_RX_FAILURE"},
1473         {SPINEL_PROP_MSG_BUFFER_COUNTERS, "MSG_BUFFER_COUNTERS"},
1474         {SPINEL_PROP_CNTR_ALL_MAC_COUNTERS, "CNTR_ALL_MAC_COUNTERS"},
1475         {SPINEL_PROP_CNTR_MLE_COUNTERS, "CNTR_MLE_COUNTERS"},
1476         {SPINEL_PROP_CNTR_ALL_IP_COUNTERS, "CNTR_ALL_IP_COUNTERS"},
1477         {SPINEL_PROP_CNTR_MAC_RETRY_HISTOGRAM, "CNTR_MAC_RETRY_HISTOGRAM"},
1478         {SPINEL_PROP_NEST_STREAM_MFG, "NEST_STREAM_MFG"},
1479         {SPINEL_PROP_NEST_LEGACY_ULA_PREFIX, "NEST_LEGACY_ULA_PREFIX"},
1480         {SPINEL_PROP_NEST_LEGACY_LAST_NODE_JOINED, "NEST_LEGACY_LAST_NODE_JOINED"},
1481         {SPINEL_PROP_DEBUG_TEST_ASSERT, "DEBUG_TEST_ASSERT"},
1482         {SPINEL_PROP_DEBUG_NCP_LOG_LEVEL, "DEBUG_NCP_LOG_LEVEL"},
1483         {SPINEL_PROP_DEBUG_TEST_WATCHDOG, "DEBUG_TEST_WATCHDOG"},
1484         {SPINEL_PROP_RCP_MAC_FRAME_COUNTER, "RCP_MAC_FRAME_COUNTER"},
1485         {SPINEL_PROP_RCP_MAC_KEY, "RCP_MAC_KEY"},
1486         {SPINEL_PROP_DEBUG_LOG_TIMESTAMP_BASE, "DEBUG_LOG_TIMESTAMP_BASE"},
1487         {SPINEL_PROP_DEBUG_TREL_TEST_MODE_ENABLE, "DEBUG_TREL_TEST_MODE_ENABLE"},
1488         {0, NULL},
1489     };
1490 
1491     return spinel_to_cstr(spinel_prop_cstr, prop_key);
1492 }
1493 
spinel_net_role_to_cstr(uint8_t net_role)1494 const char *spinel_net_role_to_cstr(uint8_t net_role)
1495 {
1496     static const struct spinel_cstr spinel_net_cstr[] = {
1497         {SPINEL_NET_ROLE_DETACHED, "NET_ROLE_DETACHED"},
1498         {SPINEL_NET_ROLE_CHILD, "NET_ROLE_CHILD"},
1499         {SPINEL_NET_ROLE_ROUTER, "NET_ROLE_ROUTER"},
1500         {SPINEL_NET_ROLE_LEADER, "NET_ROLE_LEADER"},
1501         {0, NULL},
1502     };
1503 
1504     return spinel_to_cstr(spinel_net_cstr, net_role);
1505 }
1506 
spinel_mcu_power_state_to_cstr(uint8_t mcu_power_state)1507 const char *spinel_mcu_power_state_to_cstr(uint8_t mcu_power_state)
1508 {
1509     static const struct spinel_cstr spinel_mcu_power_state_cstr[] = {
1510         {SPINEL_MCU_POWER_STATE_ON, "MCU_POWER_STATE_ON"},
1511         {SPINEL_MCU_POWER_STATE_LOW_POWER, "MCU_POWER_STATE_LOW_POWER"},
1512         {SPINEL_MCU_POWER_STATE_OFF, "MCU_POWER_STATE_OFF"},
1513         {0, NULL},
1514     };
1515 
1516     return spinel_to_cstr(spinel_mcu_power_state_cstr, mcu_power_state);
1517 }
1518 
spinel_status_to_cstr(spinel_status_t status)1519 const char *spinel_status_to_cstr(spinel_status_t status)
1520 {
1521     static const struct spinel_cstr spinel_status_cstr[] = {
1522         {SPINEL_STATUS_OK, "OK"},
1523         {SPINEL_STATUS_FAILURE, "FAILURE"},
1524         {SPINEL_STATUS_UNIMPLEMENTED, "UNIMPLEMENTED"},
1525         {SPINEL_STATUS_INVALID_ARGUMENT, "INVALID_ARGUMENT"},
1526         {SPINEL_STATUS_INVALID_STATE, "INVALID_STATE"},
1527         {SPINEL_STATUS_INVALID_COMMAND, "INVALID_COMMAND"},
1528         {SPINEL_STATUS_INVALID_INTERFACE, "INVALID_INTERFACE"},
1529         {SPINEL_STATUS_INTERNAL_ERROR, "INTERNAL_ERROR"},
1530         {SPINEL_STATUS_SECURITY_ERROR, "SECURITY_ERROR"},
1531         {SPINEL_STATUS_PARSE_ERROR, "PARSE_ERROR"},
1532         {SPINEL_STATUS_IN_PROGRESS, "IN_PROGRESS"},
1533         {SPINEL_STATUS_NOMEM, "NOMEM"},
1534         {SPINEL_STATUS_BUSY, "BUSY"},
1535         {SPINEL_STATUS_PROP_NOT_FOUND, "PROP_NOT_FOUND"},
1536         {SPINEL_STATUS_DROPPED, "DROPPED"},
1537         {SPINEL_STATUS_EMPTY, "EMPTY"},
1538         {SPINEL_STATUS_CMD_TOO_BIG, "CMD_TOO_BIG"},
1539         {SPINEL_STATUS_NO_ACK, "NO_ACK"},
1540         {SPINEL_STATUS_CCA_FAILURE, "CCA_FAILURE"},
1541         {SPINEL_STATUS_ALREADY, "ALREADY"},
1542         {SPINEL_STATUS_ITEM_NOT_FOUND, "ITEM_NOT_FOUND"},
1543         {SPINEL_STATUS_INVALID_COMMAND_FOR_PROP, "INVALID_COMMAND_FOR_PROP"},
1544         {SPINEL_STATUS_RESPONSE_TIMEOUT, "RESPONSE_TIMEOUT"},
1545         {SPINEL_STATUS_JOIN_FAILURE, "JOIN_FAILURE"},
1546         {SPINEL_STATUS_JOIN_SECURITY, "JOIN_SECURITY"},
1547         {SPINEL_STATUS_JOIN_NO_PEERS, "JOIN_NO_PEERS"},
1548         {SPINEL_STATUS_JOIN_INCOMPATIBLE, "JOIN_INCOMPATIBLE"},
1549         {SPINEL_STATUS_JOIN_RSP_TIMEOUT, "JOIN_RSP_TIMEOUT"},
1550         {SPINEL_STATUS_JOIN_SUCCESS, "JOIN_SUCCESS"},
1551         {SPINEL_STATUS_RESET_POWER_ON, "RESET_POWER_ON"},
1552         {SPINEL_STATUS_RESET_EXTERNAL, "RESET_EXTERNAL"},
1553         {SPINEL_STATUS_RESET_SOFTWARE, "RESET_SOFTWARE"},
1554         {SPINEL_STATUS_RESET_FAULT, "RESET_FAULT"},
1555         {SPINEL_STATUS_RESET_CRASH, "RESET_CRASH"},
1556         {SPINEL_STATUS_RESET_ASSERT, "RESET_ASSERT"},
1557         {SPINEL_STATUS_RESET_OTHER, "RESET_OTHER"},
1558         {SPINEL_STATUS_RESET_UNKNOWN, "RESET_UNKNOWN"},
1559         {SPINEL_STATUS_RESET_WATCHDOG, "RESET_WATCHDOG"},
1560         {0, NULL},
1561     };
1562 
1563     return spinel_to_cstr(spinel_status_cstr, status);
1564 }
1565 
spinel_capability_to_cstr(spinel_capability_t capability)1566 const char *spinel_capability_to_cstr(spinel_capability_t capability)
1567 {
1568     static const struct spinel_cstr spinel_cap_cstr[] = {
1569         {SPINEL_CAP_LOCK, "LOCK"},
1570         {SPINEL_CAP_NET_SAVE, "NET_SAVE"},
1571         {SPINEL_CAP_HBO, "HBO"},
1572         {SPINEL_CAP_POWER_SAVE, "POWER_SAVE"},
1573         {SPINEL_CAP_COUNTERS, "COUNTERS"},
1574         {SPINEL_CAP_JAM_DETECT, "JAM_DETECT"},
1575         {SPINEL_CAP_PEEK_POKE, "PEEK_POKE"},
1576         {SPINEL_CAP_WRITABLE_RAW_STREAM, "WRITABLE_RAW_STREAM"},
1577         {SPINEL_CAP_GPIO, "GPIO"},
1578         {SPINEL_CAP_TRNG, "TRNG"},
1579         {SPINEL_CAP_CMD_MULTI, "CMD_MULTI"},
1580         {SPINEL_CAP_UNSOL_UPDATE_FILTER, "UNSOL_UPDATE_FILTER"},
1581         {SPINEL_CAP_MCU_POWER_STATE, "MCU_POWER_STATE"},
1582         {SPINEL_CAP_PCAP, "PCAP"},
1583         {SPINEL_CAP_802_15_4_2003, "802_15_4_2003"},
1584         {SPINEL_CAP_802_15_4_2006, "802_15_4_2006"},
1585         {SPINEL_CAP_802_15_4_2011, "802_15_4_2011"},
1586         {SPINEL_CAP_802_15_4_PIB, "802_15_4_PIB"},
1587         {SPINEL_CAP_802_15_4_2450MHZ_OQPSK, "802_15_4_2450MHZ_OQPSK"},
1588         {SPINEL_CAP_802_15_4_915MHZ_OQPSK, "802_15_4_915MHZ_OQPSK"},
1589         {SPINEL_CAP_802_15_4_868MHZ_OQPSK, "802_15_4_868MHZ_OQPSK"},
1590         {SPINEL_CAP_802_15_4_915MHZ_BPSK, "802_15_4_915MHZ_BPSK"},
1591         {SPINEL_CAP_802_15_4_868MHZ_BPSK, "802_15_4_868MHZ_BPSK"},
1592         {SPINEL_CAP_802_15_4_915MHZ_ASK, "802_15_4_915MHZ_ASK"},
1593         {SPINEL_CAP_802_15_4_868MHZ_ASK, "802_15_4_868MHZ_ASK"},
1594         {SPINEL_CAP_CONFIG_FTD, "CONFIG_FTD"},
1595         {SPINEL_CAP_CONFIG_MTD, "CONFIG_MTD"},
1596         {SPINEL_CAP_CONFIG_RADIO, "CONFIG_RADIO"},
1597         {SPINEL_CAP_ROLE_ROUTER, "ROLE_ROUTER"},
1598         {SPINEL_CAP_ROLE_SLEEPY, "ROLE_SLEEPY"},
1599         {SPINEL_CAP_NET_THREAD_1_0, "NET_THREAD_1_0"},
1600         {SPINEL_CAP_NET_THREAD_1_1, "NET_THREAD_1_1"},
1601         {SPINEL_CAP_NET_THREAD_1_2, "NET_THREAD_1_2"},
1602         {SPINEL_CAP_RCP_API_VERSION, "RCP_API_VERSION"},
1603         {SPINEL_CAP_MAC_ALLOWLIST, "MAC_ALLOWLIST"},
1604         {SPINEL_CAP_MAC_RAW, "MAC_RAW"},
1605         {SPINEL_CAP_OOB_STEERING_DATA, "OOB_STEERING_DATA"},
1606         {SPINEL_CAP_CHANNEL_MONITOR, "CHANNEL_MONITOR"},
1607         {SPINEL_CAP_CHANNEL_MANAGER, "CHANNEL_MANAGER"},
1608         {SPINEL_CAP_OPENTHREAD_LOG_METADATA, "OPENTHREAD_LOG_METADATA"},
1609         {SPINEL_CAP_TIME_SYNC, "TIME_SYNC"},
1610         {SPINEL_CAP_CHILD_SUPERVISION, "CHILD_SUPERVISION"},
1611         {SPINEL_CAP_POSIX, "POSIX"},
1612         {SPINEL_CAP_SLAAC, "SLAAC"},
1613         {SPINEL_CAP_RADIO_COEX, "RADIO_COEX"},
1614         {SPINEL_CAP_MAC_RETRY_HISTOGRAM, "MAC_RETRY_HISTOGRAM"},
1615         {SPINEL_CAP_MULTI_RADIO, "MULTI_RADIO"},
1616         {SPINEL_CAP_SRP_CLIENT, "SRP_CLIENT"},
1617         {SPINEL_CAP_DUA, "DUA"},
1618         {SPINEL_CAP_REFERENCE_DEVICE, "REFERENCE_DEVICE"},
1619         {SPINEL_CAP_ERROR_RATE_TRACKING, "ERROR_RATE_TRACKING"},
1620         {SPINEL_CAP_THREAD_COMMISSIONER, "THREAD_COMMISSIONER"},
1621         {SPINEL_CAP_THREAD_TMF_PROXY, "THREAD_TMF_PROXY"},
1622         {SPINEL_CAP_THREAD_UDP_FORWARD, "THREAD_UDP_FORWARD"},
1623         {SPINEL_CAP_THREAD_JOINER, "THREAD_JOINER"},
1624         {SPINEL_CAP_THREAD_BORDER_ROUTER, "THREAD_BORDER_ROUTER"},
1625         {SPINEL_CAP_THREAD_SERVICE, "THREAD_SERVICE"},
1626         {SPINEL_CAP_THREAD_CSL_RECEIVER, "THREAD_CSL_RECEIVER"},
1627         {SPINEL_CAP_THREAD_BACKBONE_ROUTER, "THREAD_BACKBONE_ROUTER"},
1628         {SPINEL_CAP_NEST_LEGACY_INTERFACE, "NEST_LEGACY_INTERFACE"},
1629         {SPINEL_CAP_NEST_LEGACY_NET_WAKE, "NEST_LEGACY_NET_WAKE"},
1630         {SPINEL_CAP_NEST_TRANSMIT_HOOK, "NEST_TRANSMIT_HOOK"},
1631         {0, NULL},
1632     };
1633 
1634     return spinel_to_cstr(spinel_cap_cstr, capability);
1635 }
1636 
1637 // LCOV_EXCL_STOP
1638 
1639 /* -------------------------------------------------------------------------- */
1640 
1641 #if SPINEL_SELF_TEST
1642 
main(void)1643 int main(void)
1644 {
1645     int                  ret             = -1;
1646     const spinel_eui64_t static_eui64    = {{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}};
1647     const char           static_string[] = "static_string";
1648     uint8_t              buffer[1024];
1649     ssize_t              len;
1650 
1651     len =
1652         spinel_datatype_pack(buffer, sizeof(buffer), "CiiLUE", 0x88, 9, 0xA3, 0xDEADBEEF, static_string, &static_eui64);
1653 
1654     if (len != 30)
1655     {
1656         printf("error:%d: len != 30; (%d)\n", __LINE__, (int)len);
1657         goto bail;
1658     }
1659 
1660     {
1661         const char *str = NULL;
1662 
1663         // Length ends right before the string.
1664         len = spinel_datatype_unpack(buffer, 8, "CiiLU", NULL, NULL, NULL, NULL, &str);
1665 
1666         if (len != -1)
1667         {
1668             printf("error:%d: len != -1; (%d)\n", __LINE__, (int)len);
1669             goto bail;
1670         }
1671 
1672         if (str != NULL)
1673         {
1674             printf("error:%d: str != NULL\n", __LINE__);
1675             goto bail;
1676         }
1677     }
1678 
1679     len = 30;
1680 
1681     {
1682         uint8_t               c     = 0;
1683         unsigned int          i1    = 0;
1684         unsigned int          i2    = 0;
1685         uint32_t              l     = 0;
1686         const char *          str   = NULL;
1687         const spinel_eui64_t *eui64 = NULL;
1688 
1689         len = spinel_datatype_unpack(buffer, (spinel_size_t)len, "CiiLUE", &c, &i1, &i2, &l, &str, &eui64);
1690 
1691         if (len != 30)
1692         {
1693             printf("error:%d: len != 30; (%d)\n", __LINE__, (int)len);
1694             goto bail;
1695         }
1696 
1697         if (c != 0x88)
1698         {
1699             printf("error: x != 0x88; (%d)\n", c);
1700             goto bail;
1701         }
1702 
1703         if (i1 != 9)
1704         {
1705             printf("error: i1 != 9; (%d)\n", i1);
1706             goto bail;
1707         }
1708 
1709         if (i2 != 0xA3)
1710         {
1711             printf("error: i2 != 0xA3; (0x%02X)\n", i2);
1712             goto bail;
1713         }
1714 
1715         if (l != 0xDEADBEEF)
1716         {
1717             printf("error: l != 0xDEADBEEF; (0x%08X)\n", (unsigned int)l);
1718             goto bail;
1719         }
1720 
1721         if (strcmp(str, static_string) != 0)
1722         {
1723             printf("error:%d: strcmp(str,static_string) != 0\n", __LINE__);
1724             goto bail;
1725         }
1726 
1727         if (memcmp(eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0)
1728         {
1729             printf("error:%d: memcmp(eui64, &eui64, sizeof(spinel_eui64_t)) != 0\n", __LINE__);
1730             goto bail;
1731         }
1732     }
1733 
1734     {
1735         uint8_t        c  = 0;
1736         unsigned int   i1 = 0;
1737         unsigned int   i2 = 0;
1738         uint32_t       l  = 0;
1739         char           str[sizeof(static_string)];
1740         spinel_eui64_t eui64 = {{0}};
1741 
1742         len = spinel_datatype_unpack_in_place(buffer, (spinel_size_t)len, "CiiLUE", &c, &i1, &i2, &l, &str, sizeof(str),
1743                                               &eui64);
1744 
1745         if (len != 30)
1746         {
1747             printf("error:%d: len != 30; (%d)\n", __LINE__, (int)len);
1748             goto bail;
1749         }
1750 
1751         if (c != 0x88)
1752         {
1753             printf("error: x != 0x88; (%d)\n", c);
1754             goto bail;
1755         }
1756 
1757         if (i1 != 9)
1758         {
1759             printf("error: i1 != 9; (%d)\n", i1);
1760             goto bail;
1761         }
1762 
1763         if (i2 != 0xA3)
1764         {
1765             printf("error: i2 != 0xA3; (0x%02X)\n", i2);
1766             goto bail;
1767         }
1768 
1769         if (l != 0xDEADBEEF)
1770         {
1771             printf("error: l != 0xDEADBEEF; (0x%08X)\n", (unsigned int)l);
1772             goto bail;
1773         }
1774 
1775         if (strcmp(str, static_string) != 0)
1776         {
1777             printf("error:%d: strcmp(str,static_string) != 0\n", __LINE__);
1778             goto bail;
1779         }
1780 
1781         if (memcmp(&eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0)
1782         {
1783             printf("error:%d: memcmp(&eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0\n", __LINE__);
1784             goto bail;
1785         }
1786     }
1787 
1788     // -----------------------------------
1789 
1790     memset(buffer, 0xAA, sizeof(buffer));
1791 
1792     len = spinel_datatype_pack(buffer, sizeof(buffer), "Cit(iL)UE", 0x88, 9, 0xA3, 0xDEADBEEF, static_string,
1793                                &static_eui64);
1794 
1795     if (len != 32)
1796     {
1797         printf("error:%d: len != 32; (%d)\n", __LINE__, (int)len);
1798         goto bail;
1799     }
1800 
1801     {
1802         uint8_t         c     = 0;
1803         unsigned int    i1    = 0;
1804         unsigned int    i2    = 0;
1805         uint32_t        l     = 0;
1806         const char *    str   = NULL;
1807         spinel_eui64_t *eui64 = NULL;
1808 
1809         len = spinel_datatype_unpack(buffer, (spinel_size_t)len, "Cit(iL)UE", &c, &i1, &i2, &l, &str, &eui64);
1810 
1811         if (len != 32)
1812         {
1813             printf("error:%d: len != 24; (%d)\n", __LINE__, (int)len);
1814             goto bail;
1815         }
1816 
1817         if (c != 0x88)
1818         {
1819             printf("error: x != 0x88; (%d)\n", c);
1820             goto bail;
1821         }
1822 
1823         if (i1 != 9)
1824         {
1825             printf("error: i1 != 9; (%d)\n", i1);
1826             goto bail;
1827         }
1828 
1829         if (i2 != 0xA3)
1830         {
1831             printf("error: i2 != 0xA3; (0x%02X)\n", i2);
1832             goto bail;
1833         }
1834 
1835         if (l != 0xDEADBEEF)
1836         {
1837             printf("error: l != 0xDEADBEEF; (0x%08X)\n", (unsigned int)l);
1838             goto bail;
1839         }
1840 
1841         if (strcmp(str, static_string) != 0)
1842         {
1843             printf("error:%d: strcmp(str,static_string) != 0\n", __LINE__);
1844             goto bail;
1845         }
1846 
1847         if (memcmp(eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0)
1848         {
1849             printf("error:%d: memcmp(eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0\n", __LINE__);
1850             goto bail;
1851         }
1852     }
1853 
1854     {
1855         uint8_t        c  = 0;
1856         unsigned int   i1 = 0;
1857         unsigned int   i2 = 0;
1858         uint32_t       l  = 0;
1859         char           str[sizeof(static_string)];
1860         spinel_eui64_t eui64 = {{0}};
1861 
1862         len = spinel_datatype_unpack_in_place(buffer, (spinel_size_t)len, "Cit(iL)UE", &c, &i1, &i2, &l, &str,
1863                                               sizeof(str), &eui64);
1864 
1865         if (len != 32)
1866         {
1867             printf("error:%d: len != 24; (%d)\n", __LINE__, (int)len);
1868             goto bail;
1869         }
1870 
1871         if (c != 0x88)
1872         {
1873             printf("error: x != 0x88; (%d)\n", c);
1874             goto bail;
1875         }
1876 
1877         if (i1 != 9)
1878         {
1879             printf("error: i1 != 9; (%d)\n", i1);
1880             goto bail;
1881         }
1882 
1883         if (i2 != 0xA3)
1884         {
1885             printf("error: i2 != 0xA3; (0x%02X)\n", i2);
1886             goto bail;
1887         }
1888 
1889         if (l != 0xDEADBEEF)
1890         {
1891             printf("error: l != 0xDEADBEEF; (0x%08X)\n", (unsigned int)l);
1892             goto bail;
1893         }
1894 
1895         if (strcmp(str, static_string) != 0)
1896         {
1897             printf("error:%d: strcmp(str,static_string) != 0\n", __LINE__);
1898             goto bail;
1899         }
1900 
1901         if (memcmp(&eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0)
1902         {
1903             printf("error:%d: memcmp(&eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0\n", __LINE__);
1904             goto bail;
1905         }
1906     }
1907 
1908     {
1909         // Test UTF8 validation - Good/Valid strings
1910 
1911         // Single symbols
1912         const uint8_t single1[] = {0};                            // 0000
1913         const uint8_t single2[] = {0x7F, 0x00};                   // 007F
1914         const uint8_t single3[] = {0xC2, 0x80, 0x00};             // 080
1915         const uint8_t single4[] = {0xDF, 0xBF, 0x00};             // 07FF
1916         const uint8_t single5[] = {0xE0, 0xA0, 0x80, 0x00};       // 0800
1917         const uint8_t single6[] = {0xEF, 0xBF, 0xBF, 0x00};       // FFFF
1918         const uint8_t single7[] = {0xF0, 0x90, 0x80, 0x80, 0x00}; // 010000
1919         const uint8_t single8[] = {0xF4, 0x8F, 0xBF, 0xBF, 0x00}; // 10FFFF
1920 
1921         // Strings
1922         const uint8_t str1[] = "spinel";
1923         const uint8_t str2[] = "OpenThread";
1924         const uint8_t str3[] = {0x41, 0x7F, 0xEF, 0xBF, 0xBF, 0xC2, 0x80, 0x21, 0x33, 0x00};
1925         const uint8_t str4[] = {0xCE, 0xBA, 0xE1, 0xBD, 0xB9, 0xCF, 0x83, 0xCE, 0xBC, 0xCE, 0xB5, 0x00}; // κόσμε
1926         const uint8_t str5[] = {0x3D, 0xF4, 0x8F, 0xBF, 0xBF, 0x01, 0xE0, 0xA0, 0x83, 0x22, 0xEF, 0xBF, 0xBF, 0x00};
1927         const uint8_t str6[] = {0xE5, 0xA2, 0x82, 0xE0, 0xA0, 0x80, 0xC2, 0x83, 0xC2, 0x80, 0xF4,
1928                                 0x8F, 0xBF, 0xBF, 0xF4, 0x8F, 0xBF, 0xBF, 0xDF, 0xBF, 0x21, 0x00};
1929 
1930         const uint8_t * good_strings[] = {single1, single2, single3, single4, single5, single6, single7, single8,
1931                                          str1,    str2,    str3,    str4,    str5,    str6,    NULL};
1932         const uint8_t **str_ptr;
1933 
1934         for (str_ptr = &good_strings[0]; *str_ptr != NULL; str_ptr++)
1935         {
1936             if (!spinel_validate_utf8(*str_ptr))
1937             {
1938                 printf("error: spinel_validate_utf8() did not correctly detect a valid UTF8 sequence!\n");
1939                 goto bail;
1940             }
1941         }
1942     }
1943 
1944     {
1945         // Test UTF8 validation - Bad/Invalid strings
1946 
1947         // Single symbols (invalid)
1948         const uint8_t single1[] = {0xF8, 0x00};
1949         const uint8_t single2[] = {0xF9, 0x00};
1950         const uint8_t single3[] = {0xFA, 0x00};
1951         const uint8_t single4[] = {0xFF, 0x00};
1952 
1953         // Bad continuations
1954         const uint8_t bad1[] = {0xDF, 0x0F, 0x00};
1955         const uint8_t bad2[] = {0xE0, 0xA0, 0x10, 0x00};
1956         const uint8_t bad3[] = {0xF0, 0x90, 0x80, 0x60, 0x00};
1957         const uint8_t bad4[] = {0xF4, 0x8F, 0xBF, 0x0F, 0x00};
1958         const uint8_t bad5[] = {0x21, 0xA0, 0x00};
1959         const uint8_t bad6[] = {0xCE, 0xBA, 0xE1, 0xBD, 0xB9, 0xCF, 0x83, 0xCE, 0xBC, 0xCE, 0x00};
1960 
1961         const uint8_t * bad_strings[] = {single1, single2, single3, single4, bad1, bad2, bad3, bad4, bad5, bad6, NULL};
1962         const uint8_t **str_ptr;
1963 
1964         for (str_ptr = &bad_strings[0]; *str_ptr != NULL; str_ptr++)
1965         {
1966             if (spinel_validate_utf8(*str_ptr))
1967             {
1968                 printf("error: spinel_validate_utf8() did not correctly detect an invalid UTF8 sequence\n");
1969                 goto bail;
1970             }
1971         }
1972     }
1973 
1974     printf("OK\n");
1975     ret = 0;
1976     return ret;
1977 
1978 bail:
1979     printf("FAILURE\n");
1980     return ret;
1981 }
1982 
1983 #endif // #if SPINEL_SELF_TEST
1984