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