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