/* * Copyright (c) 2016, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * ------------------------------------------------------------------- * * ## Unit Test ## * * This file includes its own unit test. To compile the unit test, * simply compile this file with the macro SPINEL_SELF_TEST set to 1. * For example: * * cc spinel.c -Wall -DSPINEL_SELF_TEST=1 -o spinel * * ------------------------------------------------------------------- */ // ---------------------------------------------------------------------------- // MARK: - // MARK: Headers #include "spinel.h" #include #include #ifndef SPINEL_PLATFORM_HEADER /* These are all already included in the spinel platform header * if SPINEL_PLATFORM_HEADER was defined. */ #include #include #include #endif // #ifndef SPINEL_PLATFORM_HEADER // ---------------------------------------------------------------------------- // MARK: - // IAR's errno.h apparently doesn't define EOVERFLOW. #ifndef EOVERFLOW // There is no real good choice for what to set // errno to in this case, so we just pick the // value '1' somewhat arbitrarily. #define EOVERFLOW 1 #endif // IAR's errno.h apparently doesn't define EINVAL. #ifndef EINVAL // There is no real good choice for what to set // errno to in this case, so we just pick the // value '1' somewhat arbitrarily. #define EINVAL 1 #endif // IAR's errno.h apparently doesn't define ENOMEM. #ifndef ENOMEM // There is no real good choice for what to set // errno to in this case, so we just pick the // value '1' somewhat arbitrarily. #define ENOMEM 1 #endif #ifndef SPINEL_PLATFORM_SHOULD_LOG_ASSERTS #define SPINEL_PLATFORM_SHOULD_LOG_ASSERTS 0 #endif #ifndef SPINEL_PLATFORM_DOESNT_IMPLEMENT_ERRNO_VAR #define SPINEL_PLATFORM_DOESNT_IMPLEMENT_ERRNO_VAR 0 #endif #ifndef SPINEL_PLATFORM_DOESNT_IMPLEMENT_FPRINTF #define SPINEL_PLATFORM_DOESNT_IMPLEMENT_FPRINTF 0 #endif #ifndef SPINEL_SELF_TEST #define SPINEL_SELF_TEST 0 #endif #if defined(errno) && SPINEL_PLATFORM_DOESNT_IMPLEMENT_ERRNO_VAR #error "SPINEL_PLATFORM_DOESNT_IMPLEMENT_ERRNO_VAR is set but errno is already defined." #endif // Work-around for platforms that don't implement the `errno` variable. #if !defined(errno) && SPINEL_PLATFORM_DOESNT_IMPLEMENT_ERRNO_VAR static int spinel_errno_workaround_; #define errno spinel_errno_workaround_ #endif // SPINEL_PLATFORM_DOESNT_IMPLEMENT_ERRNO_VAR #ifndef assert_printf #if SPINEL_PLATFORM_DOESNT_IMPLEMENT_FPRINTF #define assert_printf(fmt, ...) printf(__FILE__ ":%d: " fmt "\n", __LINE__, __VA_ARGS__) #else // if SPINEL_PLATFORM_DOESNT_IMPLEMENT_FPRINTF #define assert_printf(fmt, ...) fprintf(stderr, __FILE__ ":%d: " fmt "\n", __LINE__, __VA_ARGS__) #endif // else SPINEL_PLATFORM_DOESNT_IMPLEMENT_FPRINTF #endif #ifndef require_action #if SPINEL_PLATFORM_SHOULD_LOG_ASSERTS #define require_action(c, l, a) \ do \ { \ if (!(c)) \ { \ assert_printf("Requirement Failed (%s)", #c); \ a; \ goto l; \ } \ } while (0) #else // if DEBUG #define require_action(c, l, a) \ do \ { \ if (!(c)) \ { \ a; \ goto l; \ } \ } while (0) #endif // else DEBUG #endif // ifndef require_action #ifndef require #define require(c, l) require_action(c, l, {}) #endif #ifndef strnlen static size_t spinel_strnlen(const char *s, size_t maxlen) { size_t ret; for (ret = 0; (ret < maxlen) && (s[ret] != 0); ret++) { // Empty loop. } return ret; } #else #define spinel_strnlen strnlen #endif typedef struct { va_list obj; } va_list_obj; #define SPINEL_MAX_PACK_LENGTH 32767 // ---------------------------------------------------------------------------- // This function validates whether a given byte sequence (string) follows UTF8 encoding. static bool spinel_validate_utf8(const uint8_t *string) { bool ret = true; uint8_t byte; uint8_t continuation_bytes = 0; while ((byte = *string++) != 0) { if ((byte & 0x80) == 0) { continue; } // This is a leading byte 1xxx-xxxx. if ((byte & 0x40) == 0) // 10xx-xxxx { // We got a continuation byte pattern without seeing a leading byte earlier. ret = false; goto bail; } else if ((byte & 0x20) == 0) // 110x-xxxx { continuation_bytes = 1; } else if ((byte & 0x10) == 0) // 1110-xxxx { continuation_bytes = 2; } else if ((byte & 0x08) == 0) // 1111-0xxx { continuation_bytes = 3; } else // 1111-1xxx (invalid pattern). { ret = false; goto bail; } while (continuation_bytes-- != 0) { byte = *string++; // Verify the continuation byte pattern 10xx-xxxx if ((byte & 0xc0) != 0x80) { ret = false; goto bail; } } } bail: return ret; } // ---------------------------------------------------------------------------- // MARK: - spinel_ssize_t spinel_packed_uint_decode(const uint8_t *bytes, spinel_size_t len, unsigned int *value_ptr) { spinel_ssize_t ret = 0; unsigned int value = 0; unsigned int i = 0; do { if ((len < sizeof(uint8_t)) || (i >= sizeof(unsigned int) * CHAR_BIT)) { ret = -1; break; } value |= (unsigned int)(bytes[0] & 0x7F) << i; i += 7; ret += sizeof(uint8_t); bytes += sizeof(uint8_t); len -= sizeof(uint8_t); } while ((bytes[-1] & 0x80) == 0x80); if ((ret > 0) && (value_ptr != NULL)) { *value_ptr = value; } return ret; } spinel_ssize_t spinel_packed_uint_size(unsigned int value) { spinel_ssize_t ret; if (value < (1 << 7)) { ret = 1; } else if (value < (1 << 14)) { ret = 2; } else if (value < (1 << 21)) { ret = 3; } else if (value < (1 << 28)) { ret = 4; } else { ret = 5; } return ret; } spinel_ssize_t spinel_packed_uint_encode(uint8_t *bytes, spinel_size_t len, unsigned int value) { const spinel_ssize_t encoded_size = spinel_packed_uint_size(value); if ((spinel_ssize_t)len >= encoded_size) { spinel_ssize_t i; for (i = 0; i != encoded_size - 1; ++i) { *bytes++ = (value & 0x7F) | 0x80; value = (value >> 7); } *bytes++ = (value & 0x7F); } return encoded_size; } const char *spinel_next_packed_datatype(const char *pack_format) { int depth = 0; do { switch (*++pack_format) { case '(': depth++; break; case ')': depth--; if (depth == 0) { pack_format++; } break; } } while ((depth > 0) && *pack_format != 0); return pack_format; } static spinel_ssize_t spinel_datatype_vunpack_(bool in_place, const uint8_t *data_in, spinel_size_t data_len, const char * pack_format, va_list_obj * args) { spinel_ssize_t ret = 0; // Buffer length sanity check require_action(data_len <= SPINEL_MAX_PACK_LENGTH, bail, (ret = -1, errno = EINVAL)); for (; *pack_format != 0; pack_format = spinel_next_packed_datatype(pack_format)) { if (*pack_format == ')') { // Don't go past the end of a struct. break; } switch ((spinel_datatype_t)pack_format[0]) { case SPINEL_DATATYPE_BOOL_C: { bool *arg_ptr = va_arg(args->obj, bool *); require_action(data_len >= sizeof(uint8_t), bail, (ret = -1, errno = EOVERFLOW)); if (arg_ptr) { *arg_ptr = data_in[0] != 0; } ret += sizeof(uint8_t); data_in += sizeof(uint8_t); data_len -= sizeof(uint8_t); break; } case SPINEL_DATATYPE_INT8_C: case SPINEL_DATATYPE_UINT8_C: { uint8_t *arg_ptr = va_arg(args->obj, uint8_t *); require_action(data_len >= sizeof(uint8_t), bail, (ret = -1, errno = EOVERFLOW)); if (arg_ptr) { *arg_ptr = data_in[0]; } ret += sizeof(uint8_t); data_in += sizeof(uint8_t); data_len -= sizeof(uint8_t); break; } case SPINEL_DATATYPE_INT16_C: case SPINEL_DATATYPE_UINT16_C: { uint16_t *arg_ptr = va_arg(args->obj, uint16_t *); require_action(data_len >= sizeof(uint16_t), bail, (ret = -1, errno = EOVERFLOW)); if (arg_ptr) { *arg_ptr = (uint16_t)((data_in[1] << 8) | data_in[0]); } ret += sizeof(uint16_t); data_in += sizeof(uint16_t); data_len -= sizeof(uint16_t); break; } case SPINEL_DATATYPE_INT32_C: case SPINEL_DATATYPE_UINT32_C: { uint32_t *arg_ptr = va_arg(args->obj, uint32_t *); require_action(data_len >= sizeof(uint32_t), bail, (ret = -1, errno = EOVERFLOW)); if (arg_ptr) { *arg_ptr = (uint32_t)((data_in[3] << 24) | (data_in[2] << 16) | (data_in[1] << 8) | data_in[0]); } ret += sizeof(uint32_t); data_in += sizeof(uint32_t); data_len -= sizeof(uint32_t); break; } case SPINEL_DATATYPE_INT64_C: case SPINEL_DATATYPE_UINT64_C: { uint64_t *arg_ptr = va_arg(args->obj, uint64_t *); require_action(data_len >= sizeof(uint64_t), bail, (ret = -1, errno = EOVERFLOW)); if (arg_ptr) { uint32_t l32 = (uint32_t)((data_in[3] << 24) | (data_in[2] << 16) | (data_in[1] << 8) | data_in[0]); uint32_t h32 = (uint32_t)((data_in[7] << 24) | (data_in[6] << 16) | (data_in[5] << 8) | data_in[4]); *arg_ptr = ((uint64_t)l32) | (((uint64_t)h32) << 32); } ret += sizeof(uint64_t); data_in += sizeof(uint64_t); data_len -= sizeof(uint64_t); break; } case SPINEL_DATATYPE_IPv6ADDR_C: { require_action(data_len >= sizeof(spinel_ipv6addr_t), bail, (ret = -1, errno = EOVERFLOW)); if (in_place) { spinel_ipv6addr_t *arg = va_arg(args->obj, spinel_ipv6addr_t *); if (arg) { memcpy(arg, data_in, sizeof(spinel_ipv6addr_t)); } } else { const spinel_ipv6addr_t **arg_ptr = va_arg(args->obj, const spinel_ipv6addr_t **); if (arg_ptr) { *arg_ptr = (const spinel_ipv6addr_t *)data_in; } } ret += sizeof(spinel_ipv6addr_t); data_in += sizeof(spinel_ipv6addr_t); data_len -= sizeof(spinel_ipv6addr_t); break; } case SPINEL_DATATYPE_EUI64_C: { require_action(data_len >= sizeof(spinel_eui64_t), bail, (ret = -1, errno = EOVERFLOW)); if (in_place) { spinel_eui64_t *arg = va_arg(args->obj, spinel_eui64_t *); if (arg) { memcpy(arg, data_in, sizeof(spinel_eui64_t)); } } else { const spinel_eui64_t **arg_ptr = va_arg(args->obj, const spinel_eui64_t **); if (arg_ptr) { *arg_ptr = (const spinel_eui64_t *)data_in; } } ret += sizeof(spinel_eui64_t); data_in += sizeof(spinel_eui64_t); data_len -= sizeof(spinel_eui64_t); break; } case SPINEL_DATATYPE_EUI48_C: { require_action(data_len >= sizeof(spinel_eui48_t), bail, (ret = -1, errno = EOVERFLOW)); if (in_place) { spinel_eui48_t *arg = va_arg(args->obj, spinel_eui48_t *); if (arg) { memcpy(arg, data_in, sizeof(spinel_eui48_t)); } } else { const spinel_eui48_t **arg_ptr = va_arg(args->obj, const spinel_eui48_t **); if (arg_ptr) { *arg_ptr = (const spinel_eui48_t *)data_in; } } ret += sizeof(spinel_eui48_t); data_in += sizeof(spinel_eui48_t); data_len -= sizeof(spinel_eui48_t); break; } case SPINEL_DATATYPE_UINT_PACKED_C: { unsigned int * arg_ptr = va_arg(args->obj, unsigned int *); spinel_ssize_t pui_len = spinel_packed_uint_decode(data_in, data_len, arg_ptr); // Range check require_action(NULL == arg_ptr || (*arg_ptr < SPINEL_MAX_UINT_PACKED), bail, (ret = -1, errno = ERANGE)); require(pui_len > 0, bail); require(pui_len <= (spinel_ssize_t)data_len, bail); ret += pui_len; data_in += pui_len; data_len -= (spinel_size_t)pui_len; break; } case SPINEL_DATATYPE_UTF8_C: { size_t len; // Make sure we have at least one byte. require_action(data_len > 0, bail, (ret = -1, errno = EOVERFLOW)); // Add 1 for zero termination. If not zero terminated, // len will then be data_len+1, which we will detect // in the next check. len = spinel_strnlen((const char *)data_in, data_len) + 1; // Verify that the string is zero terminated. require_action(len <= data_len, bail, (ret = -1, errno = EOVERFLOW)); // Verify the string follows valid UTF8 encoding. require_action(spinel_validate_utf8(data_in), bail, (ret = -1, errno = EINVAL)); if (in_place) { char * arg = va_arg(args->obj, char *); size_t len_arg = va_arg(args->obj, size_t); if (arg) { require_action(len_arg >= len, bail, (ret = -1, errno = ENOMEM)); memcpy(arg, data_in, len); } } else { const char **arg_ptr = va_arg(args->obj, const char **); if (arg_ptr) { *arg_ptr = (const char *)data_in; } } ret += (spinel_size_t)len; data_in += len; data_len -= (spinel_size_t)len; break; } case SPINEL_DATATYPE_DATA_C: case SPINEL_DATATYPE_DATA_WLEN_C: { spinel_ssize_t pui_len = 0; uint16_t block_len = 0; const uint8_t *block_ptr = data_in; void * arg_ptr = va_arg(args->obj, void *); unsigned int * block_len_ptr = va_arg(args->obj, unsigned int *); char nextformat = *spinel_next_packed_datatype(pack_format); if ((pack_format[0] == SPINEL_DATATYPE_DATA_WLEN_C) || ((nextformat != 0) && (nextformat != ')'))) { pui_len = spinel_datatype_unpack(data_in, data_len, SPINEL_DATATYPE_UINT16_S, &block_len); block_ptr += pui_len; require(pui_len > 0, bail); require(block_len < SPINEL_FRAME_MAX_SIZE, bail); } else { block_len = (uint16_t)data_len; pui_len = 0; } require_action((spinel_ssize_t)data_len >= (block_len + pui_len), bail, (ret = -1, errno = EOVERFLOW)); if (in_place) { require_action(NULL != block_len_ptr && *block_len_ptr >= block_len, bail, (ret = -1, errno = EINVAL)); memcpy(arg_ptr, block_ptr, block_len); } else { const uint8_t **block_ptr_ptr = (const uint8_t **)arg_ptr; if (NULL != block_ptr_ptr) { *block_ptr_ptr = block_ptr; } } if (NULL != block_len_ptr) { *block_len_ptr = block_len; } block_len += (uint16_t)pui_len; ret += block_len; data_in += block_len; data_len -= block_len; break; } case 'T': case SPINEL_DATATYPE_STRUCT_C: { spinel_ssize_t pui_len = 0; uint16_t block_len = 0; spinel_ssize_t actual_len = 0; const uint8_t *block_ptr = data_in; char nextformat = *spinel_next_packed_datatype(pack_format); if ((pack_format[0] == SPINEL_DATATYPE_STRUCT_C) || ((nextformat != 0) && (nextformat != ')'))) { pui_len = spinel_datatype_unpack(data_in, data_len, SPINEL_DATATYPE_UINT16_S, &block_len); block_ptr += pui_len; require(pui_len > 0, bail); require(block_len < SPINEL_FRAME_MAX_SIZE, bail); } else { block_len = (uint16_t)data_len; pui_len = 0; } require_action((spinel_ssize_t)data_len >= (block_len + pui_len), bail, (ret = -1, errno = EOVERFLOW)); actual_len = spinel_datatype_vunpack_(false, block_ptr, block_len, pack_format + 2, args); require_action(actual_len > -1, bail, (ret = -1, errno = EOVERFLOW)); if (pui_len) { block_len += (uint16_t)pui_len; } else { block_len = (uint16_t)actual_len; } ret += block_len; data_in += block_len; data_len -= block_len; break; } case '.': // Skip. break; case SPINEL_DATATYPE_ARRAY_C: default: // Unsupported Type! ret = -1; errno = EINVAL; goto bail; } } return ret; bail: return ret; } spinel_ssize_t spinel_datatype_unpack_in_place(const uint8_t *data_in, spinel_size_t data_len, const char * pack_format, ...) { spinel_ssize_t ret; va_list_obj args; va_start(args.obj, pack_format); ret = spinel_datatype_vunpack_(true, data_in, data_len, pack_format, &args); va_end(args.obj); return ret; } spinel_ssize_t spinel_datatype_unpack(const uint8_t *data_in, spinel_size_t data_len, const char *pack_format, ...) { spinel_ssize_t ret; va_list_obj args; va_start(args.obj, pack_format); ret = spinel_datatype_vunpack_(false, data_in, data_len, pack_format, &args); va_end(args.obj); return ret; } spinel_ssize_t spinel_datatype_vunpack_in_place(const uint8_t *data_in, spinel_size_t data_len, const char * pack_format, va_list args) { spinel_ssize_t ret; va_list_obj args_obj; va_copy(args_obj.obj, args); ret = spinel_datatype_vunpack_(true, data_in, data_len, pack_format, &args_obj); va_end(args_obj.obj); return ret; } spinel_ssize_t spinel_datatype_vunpack(const uint8_t *data_in, spinel_size_t data_len, const char * pack_format, va_list args) { spinel_ssize_t ret; va_list_obj args_obj; va_copy(args_obj.obj, args); ret = spinel_datatype_vunpack_(false, data_in, data_len, pack_format, &args_obj); va_end(args_obj.obj); return ret; } static spinel_ssize_t spinel_datatype_vpack_(uint8_t * data_out, spinel_size_t data_len_max, const char * pack_format, va_list_obj * args) { spinel_ssize_t ret = 0; // Buffer length sanity check require_action(data_len_max <= SPINEL_MAX_PACK_LENGTH, bail, (ret = -1, errno = EINVAL)); if (data_out == NULL) { data_len_max = 0; } for (; *pack_format != 0; pack_format = spinel_next_packed_datatype(pack_format)) { if (*pack_format == ')') { // Don't go past the end of a struct. break; } switch ((spinel_datatype_t)*pack_format) { case SPINEL_DATATYPE_BOOL_C: { bool arg = (bool)va_arg(args->obj, int); ret += sizeof(uint8_t); if (data_len_max >= sizeof(uint8_t)) { data_out[0] = (arg != false); data_out += sizeof(uint8_t); data_len_max -= sizeof(uint8_t); } else { data_len_max = 0; } break; } case SPINEL_DATATYPE_INT8_C: case SPINEL_DATATYPE_UINT8_C: { uint8_t arg = (uint8_t)va_arg(args->obj, int); ret += sizeof(uint8_t); if (data_len_max >= sizeof(uint8_t)) { data_out[0] = arg; data_out += sizeof(uint8_t); data_len_max -= sizeof(uint8_t); } else { data_len_max = 0; } break; } case SPINEL_DATATYPE_INT16_C: case SPINEL_DATATYPE_UINT16_C: { uint16_t arg = (uint16_t)va_arg(args->obj, int); ret += sizeof(uint16_t); if (data_len_max >= sizeof(uint16_t)) { data_out[1] = (arg >> 8) & 0xff; data_out[0] = (arg >> 0) & 0xff; data_out += sizeof(uint16_t); data_len_max -= sizeof(uint16_t); } else { data_len_max = 0; } break; } case SPINEL_DATATYPE_INT32_C: case SPINEL_DATATYPE_UINT32_C: { uint32_t arg = (uint32_t)va_arg(args->obj, int); ret += sizeof(uint32_t); if (data_len_max >= sizeof(uint32_t)) { data_out[3] = (arg >> 24) & 0xff; data_out[2] = (arg >> 16) & 0xff; data_out[1] = (arg >> 8) & 0xff; data_out[0] = (arg >> 0) & 0xff; data_out += sizeof(uint32_t); data_len_max -= sizeof(uint32_t); } else { data_len_max = 0; } break; } case SPINEL_DATATYPE_INT64_C: case SPINEL_DATATYPE_UINT64_C: { uint64_t arg = va_arg(args->obj, uint64_t); ret += sizeof(uint64_t); if (data_len_max >= sizeof(uint64_t)) { data_out[7] = (arg >> 56) & 0xff; data_out[6] = (arg >> 48) & 0xff; data_out[5] = (arg >> 40) & 0xff; data_out[4] = (arg >> 32) & 0xff; data_out[3] = (arg >> 24) & 0xff; data_out[2] = (arg >> 16) & 0xff; data_out[1] = (arg >> 8) & 0xff; data_out[0] = (arg >> 0) & 0xff; data_out += sizeof(uint64_t); data_len_max -= sizeof(uint64_t); } else { data_len_max = 0; } break; } case SPINEL_DATATYPE_IPv6ADDR_C: { spinel_ipv6addr_t *arg = va_arg(args->obj, spinel_ipv6addr_t *); ret += sizeof(spinel_ipv6addr_t); if (data_len_max >= sizeof(spinel_ipv6addr_t)) { *(spinel_ipv6addr_t *)data_out = *arg; data_out += sizeof(spinel_ipv6addr_t); data_len_max -= sizeof(spinel_ipv6addr_t); } else { data_len_max = 0; } break; } case SPINEL_DATATYPE_EUI48_C: { spinel_eui48_t *arg = va_arg(args->obj, spinel_eui48_t *); ret += sizeof(spinel_eui48_t); if (data_len_max >= sizeof(spinel_eui48_t)) { *(spinel_eui48_t *)data_out = *arg; data_out += sizeof(spinel_eui48_t); data_len_max -= sizeof(spinel_eui48_t); } else { data_len_max = 0; } break; } case SPINEL_DATATYPE_EUI64_C: { spinel_eui64_t *arg = va_arg(args->obj, spinel_eui64_t *); ret += sizeof(spinel_eui64_t); if (data_len_max >= sizeof(spinel_eui64_t)) { *(spinel_eui64_t *)data_out = *arg; data_out += sizeof(spinel_eui64_t); data_len_max -= sizeof(spinel_eui64_t); } else { data_len_max = 0; } break; } case SPINEL_DATATYPE_UINT_PACKED_C: { uint32_t arg = va_arg(args->obj, uint32_t); spinel_ssize_t encoded_size; // Range Check require_action(arg < SPINEL_MAX_UINT_PACKED, bail, { ret = -1; errno = EINVAL; }); encoded_size = spinel_packed_uint_encode(data_out, data_len_max, arg); ret += encoded_size; if ((spinel_ssize_t)data_len_max >= encoded_size) { data_out += encoded_size; data_len_max -= (spinel_size_t)encoded_size; } else { data_len_max = 0; } break; } case SPINEL_DATATYPE_UTF8_C: { const char *string_arg = va_arg(args->obj, const char *); size_t string_arg_len = 0; if (string_arg) { string_arg_len = strlen(string_arg) + 1; } else { string_arg = ""; string_arg_len = 1; } ret += (spinel_size_t)string_arg_len; if (data_len_max >= string_arg_len) { memcpy(data_out, string_arg, string_arg_len); data_out += string_arg_len; data_len_max -= (spinel_size_t)string_arg_len; } else { data_len_max = 0; } break; } case SPINEL_DATATYPE_DATA_WLEN_C: case SPINEL_DATATYPE_DATA_C: { const uint8_t *arg = va_arg(args->obj, const uint8_t *); uint32_t data_size_arg = va_arg(args->obj, uint32_t); spinel_ssize_t size_len = 0; char nextformat = *spinel_next_packed_datatype(pack_format); if ((pack_format[0] == SPINEL_DATATYPE_DATA_WLEN_C) || ((nextformat != 0) && (nextformat != ')'))) { size_len = spinel_datatype_pack(data_out, data_len_max, SPINEL_DATATYPE_UINT16_S, data_size_arg); require_action(size_len > 0, bail, { ret = -1; errno = EINVAL; }); } ret += (spinel_size_t)size_len + data_size_arg; if (data_len_max >= (spinel_size_t)size_len + data_size_arg) { data_out += size_len; data_len_max -= (spinel_size_t)size_len; if (data_out && arg) { memcpy(data_out, arg, data_size_arg); } data_out += data_size_arg; data_len_max -= data_size_arg; } else { data_len_max = 0; } break; } case 'T': case SPINEL_DATATYPE_STRUCT_C: { spinel_ssize_t struct_len = 0; spinel_ssize_t size_len = 0; char nextformat = *spinel_next_packed_datatype(pack_format); require_action(pack_format[1] == '(', bail, { ret = -1; errno = EINVAL; }); // First we figure out the size of the struct { va_list_obj subargs; va_copy(subargs.obj, args->obj); struct_len = spinel_datatype_vpack_(NULL, 0, pack_format + 2, &subargs); va_end(subargs.obj); } if ((pack_format[0] == SPINEL_DATATYPE_STRUCT_C) || ((nextformat != 0) && (nextformat != ')'))) { size_len = spinel_datatype_pack(data_out, data_len_max, SPINEL_DATATYPE_UINT16_S, struct_len); require_action(size_len > 0, bail, { ret = -1; errno = EINVAL; }); } ret += size_len + struct_len; if (struct_len + size_len <= (spinel_ssize_t)data_len_max) { data_out += size_len; data_len_max -= (spinel_size_t)size_len; struct_len = spinel_datatype_vpack_(data_out, data_len_max, pack_format + 2, args); data_out += struct_len; data_len_max -= (spinel_size_t)struct_len; } else { data_len_max = 0; } break; } case '.': // Skip. break; default: // Unsupported Type! ret = -1; errno = EINVAL; goto bail; } } bail: return ret; } spinel_ssize_t spinel_datatype_pack(uint8_t *data_out, spinel_size_t data_len_max, const char *pack_format, ...) { int ret; va_list_obj args; va_start(args.obj, pack_format); ret = spinel_datatype_vpack_(data_out, data_len_max, pack_format, &args); va_end(args.obj); return ret; } spinel_ssize_t spinel_datatype_vpack(uint8_t * data_out, spinel_size_t data_len_max, const char * pack_format, va_list args) { int ret; va_list_obj args_obj; va_copy(args_obj.obj, args); ret = spinel_datatype_vpack_(data_out, data_len_max, pack_format, &args_obj); va_end(args_obj.obj); return ret; } // ---------------------------------------------------------------------------- // MARK: - // LCOV_EXCL_START const char *spinel_command_to_cstr(spinel_command_t command) { const char *ret = "UNKNOWN"; switch (command) { case SPINEL_CMD_NOOP: ret = "NOOP"; break; case SPINEL_CMD_RESET: ret = "RESET"; break; case SPINEL_CMD_PROP_VALUE_GET: ret = "PROP_VALUE_GET"; break; case SPINEL_CMD_PROP_VALUE_SET: ret = "PROP_VALUE_SET"; break; case SPINEL_CMD_PROP_VALUE_INSERT: ret = "PROP_VALUE_INSERT"; break; case SPINEL_CMD_PROP_VALUE_REMOVE: ret = "PROP_VALUE_REMOVE"; break; case SPINEL_CMD_PROP_VALUE_IS: ret = "PROP_VALUE_IS"; break; case SPINEL_CMD_PROP_VALUE_INSERTED: ret = "PROP_VALUE_INSERTED"; break; case SPINEL_CMD_PROP_VALUE_REMOVED: ret = "PROP_VALUE_REMOVED"; break; case SPINEL_CMD_NET_SAVE: ret = "NET_SAVE"; break; case SPINEL_CMD_NET_CLEAR: ret = "NET_CLEAR"; break; case SPINEL_CMD_NET_RECALL: ret = "NET_RECALL"; break; case SPINEL_CMD_HBO_OFFLOAD: ret = "HBO_OFFLOAD"; break; case SPINEL_CMD_HBO_RECLAIM: ret = "HBO_RECLAIM"; break; case SPINEL_CMD_HBO_DROP: ret = "HBO_DROP"; break; case SPINEL_CMD_HBO_OFFLOADED: ret = "HBO_OFFLOADED"; break; case SPINEL_CMD_HBO_RECLAIMED: ret = "HBO_RECLAIMED"; break; case SPINEL_CMD_HBO_DROPPED: ret = "HBO_DROPPED"; break; case SPINEL_CMD_PEEK: ret = "PEEK"; break; case SPINEL_CMD_PEEK_RET: ret = "PEEK_RET"; break; case SPINEL_CMD_POKE: ret = "POKE"; break; case SPINEL_CMD_PROP_VALUE_MULTI_GET: ret = "PROP_VALUE_MULTI_GET"; break; case SPINEL_CMD_PROP_VALUE_MULTI_SET: ret = "PROP_VALUE_MULTI_SET"; break; case SPINEL_CMD_PROP_VALUES_ARE: ret = "PROP_VALUES_ARE"; break; default: break; } return ret; } const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) { const char *ret = "UNKNOWN"; switch (prop_key) { case SPINEL_PROP_LAST_STATUS: ret = "LAST_STATUS"; break; case SPINEL_PROP_PROTOCOL_VERSION: ret = "PROTOCOL_VERSION"; break; case SPINEL_PROP_NCP_VERSION: ret = "NCP_VERSION"; break; case SPINEL_PROP_INTERFACE_TYPE: ret = "INTERFACE_TYPE"; break; case SPINEL_PROP_VENDOR_ID: ret = "VENDOR_ID"; break; case SPINEL_PROP_CAPS: ret = "CAPS"; break; case SPINEL_PROP_INTERFACE_COUNT: ret = "INTERFACE_COUNT"; break; case SPINEL_PROP_POWER_STATE: ret = "POWER_STATE"; break; case SPINEL_PROP_HWADDR: ret = "HWADDR"; break; case SPINEL_PROP_LOCK: ret = "LOCK"; break; case SPINEL_PROP_HBO_MEM_MAX: ret = "HBO_MEM_MAX"; break; case SPINEL_PROP_HBO_BLOCK_MAX: ret = "HBO_BLOCK_MAX"; break; case SPINEL_PROP_HOST_POWER_STATE: ret = "HOST_POWER_STATE"; break; case SPINEL_PROP_MCU_POWER_STATE: ret = "MCU_POWER_STATE"; break; case SPINEL_PROP_GPIO_CONFIG: ret = "GPIO_CONFIG"; break; case SPINEL_PROP_GPIO_STATE: ret = "GPIO_STATE"; break; case SPINEL_PROP_GPIO_STATE_SET: ret = "GPIO_STATE_SET"; break; case SPINEL_PROP_GPIO_STATE_CLEAR: ret = "GPIO_STATE_CLEAR"; break; case SPINEL_PROP_TRNG_32: ret = "TRNG_32"; break; case SPINEL_PROP_TRNG_128: ret = "TRNG_128"; break; case SPINEL_PROP_TRNG_RAW_32: ret = "TRNG_RAW_32"; break; case SPINEL_PROP_UNSOL_UPDATE_FILTER: ret = "UNSOL_UPDATE_FILTER"; break; case SPINEL_PROP_UNSOL_UPDATE_LIST: ret = "UNSOL_UPDATE_LIST"; break; case SPINEL_PROP_PHY_ENABLED: ret = "PHY_ENABLED"; break; case SPINEL_PROP_PHY_CHAN: ret = "PHY_CHAN"; break; case SPINEL_PROP_PHY_CHAN_SUPPORTED: ret = "PHY_CHAN_SUPPORTED"; break; case SPINEL_PROP_PHY_FREQ: ret = "PHY_FREQ"; break; case SPINEL_PROP_PHY_CCA_THRESHOLD: ret = "PHY_CCA_THRESHOLD"; break; case SPINEL_PROP_PHY_TX_POWER: ret = "PHY_TX_POWER"; break; case SPINEL_PROP_PHY_RSSI: ret = "PHY_RSSI"; break; case SPINEL_PROP_PHY_RX_SENSITIVITY: ret = "PHY_RX_SENSITIVITY"; break; case SPINEL_PROP_PHY_PCAP_ENABLED: ret = "PHY_PCAP_ENABLED"; break; case SPINEL_PROP_PHY_CHAN_PREFERRED: ret = "PHY_CHAN_PREFERRED"; break; case SPINEL_PROP_JAM_DETECT_ENABLE: ret = "JAM_DETECT_ENABLE"; break; case SPINEL_PROP_JAM_DETECTED: ret = "JAM_DETECTED"; break; case SPINEL_PROP_JAM_DETECT_RSSI_THRESHOLD: ret = "JAM_DETECT_RSSI_THRESHOLD"; break; case SPINEL_PROP_JAM_DETECT_WINDOW: ret = "JAM_DETECT_WINDOW"; break; case SPINEL_PROP_JAM_DETECT_BUSY: ret = "JAM_DETECT_BUSY"; break; case SPINEL_PROP_JAM_DETECT_HISTORY_BITMAP: ret = "JAM_DETECT_HISTORY_BITMAP"; break; case SPINEL_PROP_CHANNEL_MONITOR_SAMPLE_INTERVAL: ret = "CHANNEL_MONITOR_SAMPLE_INTERVAL"; break; case SPINEL_PROP_CHANNEL_MONITOR_RSSI_THRESHOLD: ret = "CHANNEL_MONITOR_RSSI_THRESHOLD"; break; case SPINEL_PROP_CHANNEL_MONITOR_SAMPLE_WINDOW: ret = "CHANNEL_MONITOR_SAMPLE_WINDOW"; break; case SPINEL_PROP_CHANNEL_MONITOR_SAMPLE_COUNT: ret = "CHANNEL_MONITOR_SAMPLE_COUNT"; break; case SPINEL_PROP_CHANNEL_MONITOR_CHANNEL_OCCUPANCY: ret = "CHANNEL_MONITOR_CHANNEL_OCCUPANCY"; break; case SPINEL_PROP_RADIO_CAPS: ret = "RADIO_CAPS"; break; case SPINEL_PROP_RADIO_COEX_METRICS: ret = "RADIO_COEX_METRICS"; break; case SPINEL_PROP_RADIO_COEX_ENABLE: ret = "RADIO_COEX_ENABLE"; break; case SPINEL_PROP_MAC_SCAN_STATE: ret = "MAC_SCAN_STATE"; break; case SPINEL_PROP_MAC_SCAN_MASK: ret = "MAC_SCAN_MASK"; break; case SPINEL_PROP_MAC_SCAN_PERIOD: ret = "MAC_SCAN_PERIOD"; break; case SPINEL_PROP_MAC_SCAN_BEACON: ret = "MAC_SCAN_BEACON"; break; case SPINEL_PROP_MAC_15_4_LADDR: ret = "MAC_15_4_LADDR"; break; case SPINEL_PROP_MAC_15_4_SADDR: ret = "MAC_15_4_SADDR"; break; case SPINEL_PROP_MAC_15_4_PANID: ret = "MAC_15_4_PANID"; break; case SPINEL_PROP_MAC_RAW_STREAM_ENABLED: ret = "MAC_RAW_STREAM_ENABLED"; break; case SPINEL_PROP_MAC_PROMISCUOUS_MODE: ret = "MAC_PROMISCUOUS_MODE"; break; case SPINEL_PROP_MAC_ENERGY_SCAN_RESULT: ret = "MAC_ENERGY_SCAN_RESULT"; break; case SPINEL_PROP_MAC_DATA_POLL_PERIOD: ret = "MAC_DATA_POLL_PERIOD"; break; case SPINEL_PROP_MAC_WHITELIST: ret = "MAC_WHITELIST"; break; case SPINEL_PROP_MAC_WHITELIST_ENABLED: ret = "MAC_WHITELIST_ENABLED"; break; case SPINEL_PROP_MAC_EXTENDED_ADDR: ret = "MAC_EXTENDED_ADDR"; break; case SPINEL_PROP_MAC_SRC_MATCH_ENABLED: ret = "MAC_SRC_MATCH_ENABLED"; break; case SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES: ret = "MAC_SRC_MATCH_SHORT_ADDRESSES"; break; case SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES: ret = "MAC_SRC_MATCH_EXTENDED_ADDRESSES"; break; case SPINEL_PROP_MAC_BLACKLIST: ret = "MAC_BLACKLIST"; break; case SPINEL_PROP_MAC_BLACKLIST_ENABLED: ret = "MAC_BLACKLIST_ENABLED"; break; case SPINEL_PROP_MAC_FIXED_RSS: ret = "MAC_FIXED_RSS"; break; case SPINEL_PROP_MAC_CCA_FAILURE_RATE: ret = "MAC_CCA_FAILURE_RATE"; break; case SPINEL_PROP_MAC_MAX_RETRY_NUMBER_DIRECT: ret = "MAC_MAX_RETRY_NUMBER_DIRECT"; break; case SPINEL_PROP_MAC_MAX_RETRY_NUMBER_INDIRECT: ret = "MAC_MAX_RETRY_NUMBER_INDIRECT"; break; case SPINEL_PROP_NET_SAVED: ret = "NET_SAVED"; break; case SPINEL_PROP_NET_IF_UP: ret = "NET_IF_UP"; break; case SPINEL_PROP_NET_STACK_UP: ret = "NET_STACK_UP"; break; case SPINEL_PROP_NET_ROLE: ret = "NET_ROLE"; break; case SPINEL_PROP_NET_NETWORK_NAME: ret = "NET_NETWORK_NAME"; break; case SPINEL_PROP_NET_XPANID: ret = "NET_XPANID"; break; case SPINEL_PROP_NET_MASTER_KEY: ret = "NET_MASTER_KEY"; break; case SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER: ret = "NET_KEY_SEQUENCE_COUNTER"; break; case SPINEL_PROP_NET_PARTITION_ID: ret = "NET_PARTITION_ID"; break; case SPINEL_PROP_NET_REQUIRE_JOIN_EXISTING: ret = "NET_REQUIRE_JOIN_EXISTING"; break; case SPINEL_PROP_NET_KEY_SWITCH_GUARDTIME: ret = "NET_KEY_SWITCH_GUARDTIME"; break; case SPINEL_PROP_NET_PSKC: ret = "NET_PSKC"; break; case SPINEL_PROP_THREAD_LEADER_ADDR: ret = "THREAD_LEADER_ADDR"; break; case SPINEL_PROP_THREAD_PARENT: ret = "THREAD_PARENT"; break; case SPINEL_PROP_THREAD_CHILD_TABLE: ret = "THREAD_CHILD_TABLE"; break; case SPINEL_PROP_THREAD_LEADER_RID: ret = "THREAD_LEADER_RID"; break; case SPINEL_PROP_THREAD_LEADER_WEIGHT: ret = "THREAD_LEADER_WEIGHT"; break; case SPINEL_PROP_THREAD_LOCAL_LEADER_WEIGHT: ret = "THREAD_LOCAL_LEADER_WEIGHT"; break; case SPINEL_PROP_THREAD_NETWORK_DATA: ret = "THREAD_NETWORK_DATA"; break; case SPINEL_PROP_THREAD_NETWORK_DATA_VERSION: ret = "THREAD_NETWORK_DATA_VERSION"; break; case SPINEL_PROP_THREAD_STABLE_NETWORK_DATA: ret = "THREAD_STABLE_NETWORK_DATA"; break; case SPINEL_PROP_THREAD_STABLE_NETWORK_DATA_VERSION: ret = "THREAD_STABLE_NETWORK_DATA_VERSION"; break; case SPINEL_PROP_THREAD_ON_MESH_NETS: ret = "THREAD_ON_MESH_NETS"; break; case SPINEL_PROP_THREAD_OFF_MESH_ROUTES: ret = "THREAD_OFF_MESH_ROUTES"; break; case SPINEL_PROP_THREAD_ASSISTING_PORTS: ret = "THREAD_ASSISTING_PORTS"; break; case SPINEL_PROP_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE: ret = "THREAD_ALLOW_LOCAL_NET_DATA_CHANGE"; break; case SPINEL_PROP_THREAD_MODE: ret = "THREAD_MODE"; break; case SPINEL_PROP_THREAD_CHILD_TIMEOUT: ret = "THREAD_CHILD_TIMEOUT"; break; case SPINEL_PROP_THREAD_RLOC16: ret = "THREAD_RLOC16"; break; case SPINEL_PROP_THREAD_ROUTER_UPGRADE_THRESHOLD: ret = "THREAD_ROUTER_UPGRADE_THRESHOLD"; break; case SPINEL_PROP_THREAD_CONTEXT_REUSE_DELAY: ret = "THREAD_CONTEXT_REUSE_DELAY"; break; case SPINEL_PROP_THREAD_NETWORK_ID_TIMEOUT: ret = "THREAD_NETWORK_ID_TIMEOUT"; break; case SPINEL_PROP_THREAD_ACTIVE_ROUTER_IDS: ret = "THREAD_ACTIVE_ROUTER_IDS"; break; case SPINEL_PROP_THREAD_RLOC16_DEBUG_PASSTHRU: ret = "THREAD_RLOC16_DEBUG_PASSTHRU"; break; case SPINEL_PROP_THREAD_ROUTER_ROLE_ENABLED: ret = "THREAD_ROUTER_ROLE_ENABLED"; break; case SPINEL_PROP_THREAD_ROUTER_DOWNGRADE_THRESHOLD: ret = "THREAD_ROUTER_DOWNGRADE_THRESHOLD"; break; case SPINEL_PROP_THREAD_ROUTER_SELECTION_JITTER: ret = "THREAD_ROUTER_SELECTION_JITTER"; break; case SPINEL_PROP_THREAD_PREFERRED_ROUTER_ID: ret = "THREAD_PREFERRED_ROUTER_ID"; break; case SPINEL_PROP_THREAD_NEIGHBOR_TABLE: ret = "THREAD_NEIGHBOR_TABLE"; break; case SPINEL_PROP_THREAD_CHILD_COUNT_MAX: ret = "THREAD_CHILD_COUNT_MAX"; break; case SPINEL_PROP_THREAD_LEADER_NETWORK_DATA: ret = "THREAD_LEADER_NETWORK_DATA"; break; case SPINEL_PROP_THREAD_STABLE_LEADER_NETWORK_DATA: ret = "THREAD_STABLE_LEADER_NETWORK_DATA"; break; case SPINEL_PROP_THREAD_JOINERS: ret = "THREAD_JOINERS"; break; case SPINEL_PROP_THREAD_COMMISSIONER_ENABLED: ret = "THREAD_COMMISSIONER_ENABLED"; break; case SPINEL_PROP_THREAD_TMF_PROXY_ENABLED: ret = "THREAD_TMF_PROXY_ENABLED"; break; case SPINEL_PROP_THREAD_TMF_PROXY_STREAM: ret = "THREAD_TMF_PROXY_STREAM"; break; case SPINEL_PROP_THREAD_UDP_FORWARD_STREAM: ret = "THREAD_UDP_FORWARD_STREAM"; break; case SPINEL_PROP_THREAD_DISCOVERY_SCAN_JOINER_FLAG: ret = "THREAD_DISCOVERY_SCAN_JOINER_FLAG"; break; case SPINEL_PROP_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING: ret = "THREAD_DISCOVERY_SCAN_ENABLE_FILTERING"; break; case SPINEL_PROP_THREAD_DISCOVERY_SCAN_PANID: ret = "THREAD_DISCOVERY_SCAN_PANID"; break; case SPINEL_PROP_THREAD_STEERING_DATA: ret = "THREAD_STEERING_DATA"; break; case SPINEL_PROP_THREAD_ROUTER_TABLE: ret = "THREAD_ROUTER_TABLE"; break; case SPINEL_PROP_THREAD_ACTIVE_DATASET: ret = "THREAD_ACTIVE_DATASET"; break; case SPINEL_PROP_THREAD_PENDING_DATASET: ret = "THREAD_PENDING_DATASET"; break; case SPINEL_PROP_THREAD_MGMT_SET_ACTIVE_DATASET: ret = "THREAD_MGMT_SET_ACTIVE_DATASET"; break; case SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET: ret = "THREAD_MGMT_SET_PENDING_DATASET"; break; case SPINEL_PROP_DATASET_ACTIVE_TIMESTAMP: ret = "DATASET_ACTIVE_TIMESTAMP"; break; case SPINEL_PROP_DATASET_PENDING_TIMESTAMP: ret = "DATASET_PENDING_TIMESTAMP"; break; case SPINEL_PROP_DATASET_DELAY_TIMER: ret = "DATASET_DELAY_TIMER"; break; case SPINEL_PROP_DATASET_SECURITY_POLICY: ret = "DATASET_SECURITY_POLICY"; break; case SPINEL_PROP_DATASET_RAW_TLVS: ret = "DATASET_RAW_TLVS"; break; case SPINEL_PROP_THREAD_CHILD_TABLE_ADDRESSES: ret = "THREAD_CHILD_TABLE_ADDRESSES"; break; case SPINEL_PROP_THREAD_NEIGHBOR_TABLE_ERROR_RATES: ret = "THREAD_NEIGHBOR_TABLE_ERROR_RATES"; break; case SPINEL_PROP_THREAD_ADDRESS_CACHE_TABLE: ret = "THREAD_ADDRESS_CACHE_TABLE"; break; case SPINEL_PROP_THREAD_MGMT_GET_ACTIVE_DATASET: ret = "THREAD_MGMT_GET_ACTIVE_DATASET"; break; case SPINEL_PROP_THREAD_MGMT_GET_PENDING_DATASET: ret = "THREAD_MGMT_GET_PENDING_DATASET"; break; case SPINEL_PROP_DATASET_DEST_ADDRESS: ret = "DATASET_DEST_ADDRESS"; break; case SPINEL_PROP_THREAD_NEW_DATASET: ret = "THREAD_NEW_DATASET"; break; case SPINEL_PROP_MESHCOP_JOINER_STATE: ret = "MESHCOP_JOINER_STATE"; break; case SPINEL_PROP_MESHCOP_JOINER_COMMISSIONING: ret = "MESHCOP_JOINER_COMMISSIONING"; break; case SPINEL_PROP_IPV6_LL_ADDR: ret = "IPV6_LL_ADDR"; break; case SPINEL_PROP_IPV6_ML_ADDR: ret = "IPV6_ML_ADDR"; break; case SPINEL_PROP_IPV6_ML_PREFIX: ret = "IPV6_ML_PREFIX"; break; case SPINEL_PROP_IPV6_ADDRESS_TABLE: ret = "IPV6_ADDRESS_TABLE"; break; case SPINEL_PROP_IPV6_ROUTE_TABLE: ret = "IPV6_ROUTE_TABLE"; break; case SPINEL_PROP_IPV6_ICMP_PING_OFFLOAD: ret = "IPV6_ICMP_PING_OFFLOAD"; break; case SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE: ret = "IPV6_MULTICAST_ADDRESS_TABLE"; break; case SPINEL_PROP_IPV6_ICMP_PING_OFFLOAD_MODE: ret = "IPV6_ICMP_PING_OFFLOAD_MODE"; break; case SPINEL_PROP_STREAM_DEBUG: ret = "STREAM_DEBUG"; break; case SPINEL_PROP_STREAM_RAW: ret = "STREAM_RAW"; break; case SPINEL_PROP_STREAM_NET: ret = "STREAM_NET"; break; case SPINEL_PROP_STREAM_NET_INSECURE: ret = "STREAM_NET_INSECURE"; break; case SPINEL_PROP_STREAM_LOG: ret = "STREAM_LOG"; break; case SPINEL_PROP_MESHCOP_COMMISSIONER_STATE: ret = "MESHCOP_COMMISSIONER_STATE"; break; case SPINEL_PROP_MESHCOP_COMMISSIONER_JOINERS: ret = "MESHCOP_COMMISSIONER_JOINERS"; break; case SPINEL_PROP_MESHCOP_COMMISSIONER_PROVISIONING_URL: ret = "MESHCOP_COMMISSIONER_PROVISIONING_URL"; break; case SPINEL_PROP_MESHCOP_COMMISSIONER_SESSION_ID: ret = "MESHCOP_COMMISSIONER_SESSION_ID"; break; case SPINEL_PROP_MESHCOP_JOINER_DISCERNER: ret = "MESHCOP_JOINER_DISCERNER"; break; case SPINEL_PROP_MESHCOP_COMMISSIONER_ANNOUNCE_BEGIN: ret = "MESHCOP_COMMISSIONER_ANNOUNCE_BEGIN"; break; case SPINEL_PROP_MESHCOP_COMMISSIONER_ENERGY_SCAN: ret = "MESHCOP_COMMISSIONER_ENERGY_SCAN"; break; case SPINEL_PROP_MESHCOP_COMMISSIONER_ENERGY_SCAN_RESULT: ret = "MESHCOP_COMMISSIONER_ENERGY_SCAN_RESULT"; break; case SPINEL_PROP_MESHCOP_COMMISSIONER_PAN_ID_QUERY: ret = "MESHCOP_COMMISSIONER_PAN_ID_QUERY"; break; case SPINEL_PROP_MESHCOP_COMMISSIONER_PAN_ID_CONFLICT_RESULT: ret = "MESHCOP_COMMISSIONER_PAN_ID_CONFLICT_RESULT"; break; case SPINEL_PROP_MESHCOP_COMMISSIONER_MGMT_GET: ret = "MESHCOP_COMMISSIONER_MGMT_GET"; break; case SPINEL_PROP_MESHCOP_COMMISSIONER_MGMT_SET: ret = "MESHCOP_COMMISSIONER_MGMT_SET"; break; case SPINEL_PROP_MESHCOP_COMMISSIONER_GENERATE_PSKC: ret = "MESHCOP_COMMISSIONER_GENERATE_PSKC"; break; case SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL: ret = "CHANNEL_MANAGER_NEW_CHANNEL"; break; case SPINEL_PROP_CHANNEL_MANAGER_DELAY: ret = "CHANNEL_MANAGER_DELAY"; break; case SPINEL_PROP_CHANNEL_MANAGER_SUPPORTED_CHANNELS: ret = "CHANNEL_MANAGER_SUPPORTED_CHANNELS"; break; case SPINEL_PROP_CHANNEL_MANAGER_FAVORED_CHANNELS: ret = "CHANNEL_MANAGER_FAVORED_CHANNELS"; break; case SPINEL_PROP_CHANNEL_MANAGER_CHANNEL_SELECT: ret = "CHANNEL_MANAGER_CHANNEL_SELECT"; break; case SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_ENABLED: ret = "CHANNEL_MANAGER_AUTO_SELECT_ENABLED"; break; case SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL: ret = "CHANNEL_MANAGER_AUTO_SELECT_INTERVAL"; break; case SPINEL_PROP_THREAD_NETWORK_TIME: ret = "THREAD_NETWORK_TIME"; break; case SPINEL_PROP_TIME_SYNC_PERIOD: ret = "TIME_SYNC_PERIOD"; break; case SPINEL_PROP_TIME_SYNC_XTAL_THRESHOLD: ret = "TIME_SYNC_XTAL_THRESHOLD"; break; case SPINEL_PROP_CHILD_SUPERVISION_INTERVAL: ret = "CHILD_SUPERVISION_INTERVAL"; break; case SPINEL_PROP_CHILD_SUPERVISION_CHECK_TIMEOUT: ret = "CHILD_SUPERVISION_CHECK_TIMEOUT"; break; case SPINEL_PROP_RCP_VERSION: ret = "RCP_VERSION"; break; case SPINEL_PROP_PARENT_RESPONSE_INFO: ret = "PARENT_RESPONSE_INFO"; break; case SPINEL_PROP_SLAAC_ENABLED: ret = "SLAAC_ENABLED"; break; case SPINEL_PROP_SERVER_ALLOW_LOCAL_DATA_CHANGE: ret = "SERVER_ALLOW_LOCAL_DATA_CHANGE"; break; case SPINEL_PROP_SERVER_SERVICES: ret = "SERVER_SERVICES"; break; case SPINEL_PROP_SERVER_LEADER_SERVICES: ret = "SERVER_LEADER_SERVICES"; break; case SPINEL_PROP_UART_BITRATE: ret = "UART_BITRATE"; break; case SPINEL_PROP_UART_XON_XOFF: ret = "UART_XON_XOFF"; break; case SPINEL_PROP_15_4_PIB_PHY_CHANNELS_SUPPORTED: ret = "15_4_PIB_PHY_CHANNELS_SUPPORTED"; break; case SPINEL_PROP_15_4_PIB_MAC_PROMISCUOUS_MODE: ret = "15_4_PIB_MAC_PROMISCUOUS_MODE"; break; case SPINEL_PROP_15_4_PIB_MAC_SECURITY_ENABLED: ret = "15_4_PIB_MAC_SECURITY_ENABLED"; break; case SPINEL_PROP_CNTR_RESET: ret = "CNTR_RESET"; break; case SPINEL_PROP_CNTR_TX_PKT_TOTAL: ret = "CNTR_TX_PKT_TOTAL"; break; case SPINEL_PROP_CNTR_TX_PKT_ACK_REQ: ret = "CNTR_TX_PKT_ACK_REQ"; break; case SPINEL_PROP_CNTR_TX_PKT_ACKED: ret = "CNTR_TX_PKT_ACKED"; break; case SPINEL_PROP_CNTR_TX_PKT_NO_ACK_REQ: ret = "CNTR_TX_PKT_NO_ACK_REQ"; break; case SPINEL_PROP_CNTR_TX_PKT_DATA: ret = "CNTR_TX_PKT_DATA"; break; case SPINEL_PROP_CNTR_TX_PKT_DATA_POLL: ret = "CNTR_TX_PKT_DATA_POLL"; break; case SPINEL_PROP_CNTR_TX_PKT_BEACON: ret = "CNTR_TX_PKT_BEACON"; break; case SPINEL_PROP_CNTR_TX_PKT_BEACON_REQ: ret = "CNTR_TX_PKT_BEACON_REQ"; break; case SPINEL_PROP_CNTR_TX_PKT_OTHER: ret = "CNTR_TX_PKT_OTHER"; break; case SPINEL_PROP_CNTR_TX_PKT_RETRY: ret = "CNTR_TX_PKT_RETRY"; break; case SPINEL_PROP_CNTR_TX_ERR_CCA: ret = "CNTR_TX_ERR_CCA"; break; case SPINEL_PROP_CNTR_TX_PKT_UNICAST: ret = "CNTR_TX_PKT_UNICAST"; break; case SPINEL_PROP_CNTR_TX_PKT_BROADCAST: ret = "CNTR_TX_PKT_BROADCAST"; break; case SPINEL_PROP_CNTR_TX_ERR_ABORT: ret = "CNTR_TX_ERR_ABORT"; break; case SPINEL_PROP_CNTR_RX_PKT_TOTAL: ret = "CNTR_RX_PKT_TOTAL"; break; case SPINEL_PROP_CNTR_RX_PKT_DATA: ret = "CNTR_RX_PKT_DATA"; break; case SPINEL_PROP_CNTR_RX_PKT_DATA_POLL: ret = "CNTR_RX_PKT_DATA_POLL"; break; case SPINEL_PROP_CNTR_RX_PKT_BEACON: ret = "CNTR_RX_PKT_BEACON"; break; case SPINEL_PROP_CNTR_RX_PKT_BEACON_REQ: ret = "CNTR_RX_PKT_BEACON_REQ"; break; case SPINEL_PROP_CNTR_RX_PKT_OTHER: ret = "CNTR_RX_PKT_OTHER"; break; case SPINEL_PROP_CNTR_RX_PKT_FILT_WL: ret = "CNTR_RX_PKT_FILT_WL"; break; case SPINEL_PROP_CNTR_RX_PKT_FILT_DA: ret = "CNTR_RX_PKT_FILT_DA"; break; case SPINEL_PROP_CNTR_RX_ERR_EMPTY: ret = "CNTR_RX_ERR_EMPTY"; break; case SPINEL_PROP_CNTR_RX_ERR_UKWN_NBR: ret = "CNTR_RX_ERR_UKWN_NBR"; break; case SPINEL_PROP_CNTR_RX_ERR_NVLD_SADDR: ret = "CNTR_RX_ERR_NVLD_SADDR"; break; case SPINEL_PROP_CNTR_RX_ERR_SECURITY: ret = "CNTR_RX_ERR_SECURITY"; break; case SPINEL_PROP_CNTR_RX_ERR_BAD_FCS: ret = "CNTR_RX_ERR_BAD_FCS"; break; case SPINEL_PROP_CNTR_RX_ERR_OTHER: ret = "CNTR_RX_ERR_OTHER"; break; case SPINEL_PROP_CNTR_RX_PKT_DUP: ret = "CNTR_RX_PKT_DUP"; break; case SPINEL_PROP_CNTR_RX_PKT_UNICAST: ret = "CNTR_RX_PKT_UNICAST"; break; case SPINEL_PROP_CNTR_RX_PKT_BROADCAST: ret = "CNTR_RX_PKT_BROADCAST"; break; case SPINEL_PROP_CNTR_TX_IP_SEC_TOTAL: ret = "CNTR_TX_IP_SEC_TOTAL"; break; case SPINEL_PROP_CNTR_TX_IP_INSEC_TOTAL: ret = "CNTR_TX_IP_INSEC_TOTAL"; break; case SPINEL_PROP_CNTR_TX_IP_DROPPED: ret = "CNTR_TX_IP_DROPPED"; break; case SPINEL_PROP_CNTR_RX_IP_SEC_TOTAL: ret = "CNTR_RX_IP_SEC_TOTAL"; break; case SPINEL_PROP_CNTR_RX_IP_INSEC_TOTAL: ret = "CNTR_RX_IP_INSEC_TOTAL"; break; case SPINEL_PROP_CNTR_RX_IP_DROPPED: ret = "CNTR_RX_IP_DROPPED"; break; case SPINEL_PROP_CNTR_TX_SPINEL_TOTAL: ret = "CNTR_TX_SPINEL_TOTAL"; break; case SPINEL_PROP_CNTR_RX_SPINEL_TOTAL: ret = "CNTR_RX_SPINEL_TOTAL"; break; case SPINEL_PROP_CNTR_RX_SPINEL_ERR: ret = "CNTR_RX_SPINEL_ERR"; break; case SPINEL_PROP_CNTR_RX_SPINEL_OUT_OF_ORDER_TID: ret = "CNTR_RX_SPINEL_OUT_OF_ORDER_TID"; break; case SPINEL_PROP_CNTR_IP_TX_SUCCESS: ret = "CNTR_IP_TX_SUCCESS"; break; case SPINEL_PROP_CNTR_IP_RX_SUCCESS: ret = "CNTR_IP_RX_SUCCESS"; break; case SPINEL_PROP_CNTR_IP_TX_FAILURE: ret = "CNTR_IP_TX_FAILURE"; break; case SPINEL_PROP_CNTR_IP_RX_FAILURE: ret = "CNTR_IP_RX_FAILURE"; break; case SPINEL_PROP_MSG_BUFFER_COUNTERS: ret = "MSG_BUFFER_COUNTERS"; break; case SPINEL_PROP_CNTR_ALL_MAC_COUNTERS: ret = "CNTR_ALL_MAC_COUNTERS"; break; case SPINEL_PROP_CNTR_MLE_COUNTERS: ret = "CNTR_MLE_COUNTERS"; break; case SPINEL_PROP_CNTR_ALL_IP_COUNTERS: ret = "CNTR_ALL_IP_COUNTERS"; break; case SPINEL_PROP_CNTR_MAC_RETRY_HISTOGRAM: ret = "CNTR_MAC_RETRY_HISTOGRAM"; break; case SPINEL_PROP_NEST_STREAM_MFG: ret = "NEST_STREAM_MFG"; break; case SPINEL_PROP_NEST_LEGACY_ULA_PREFIX: ret = "NEST_LEGACY_ULA_PREFIX"; break; case SPINEL_PROP_NEST_LEGACY_LAST_NODE_JOINED: ret = "NEST_LEGACY_LAST_NODE_JOINED"; break; case SPINEL_PROP_DEBUG_TEST_ASSERT: ret = "DEBUG_TEST_ASSERT"; break; case SPINEL_PROP_DEBUG_NCP_LOG_LEVEL: ret = "DEBUG_NCP_LOG_LEVEL"; break; case SPINEL_PROP_DEBUG_TEST_WATCHDOG: ret = "DEBUG_TEST_WATCHDOG"; break; default: break; } return ret; } const char *spinel_net_role_to_cstr(uint8_t net_role) { const char *ret = "NET_ROLE_UNKNOWN"; switch (net_role) { case SPINEL_NET_ROLE_DETACHED: ret = "NET_ROLE_DETACHED"; break; case SPINEL_NET_ROLE_CHILD: ret = "NET_ROLE_CHILD"; break; case SPINEL_NET_ROLE_ROUTER: ret = "NET_ROLE_ROUTER"; break; case SPINEL_NET_ROLE_LEADER: ret = "NET_ROLE_LEADER"; break; default: break; } return ret; } const char *spinel_mcu_power_state_to_cstr(uint8_t mcu_power_state) { const char *ret = "MCU_POWER_STATE_UNKNOWN"; switch (mcu_power_state) { case SPINEL_MCU_POWER_STATE_ON: ret = "MCU_POWER_STATE_ON"; break; case SPINEL_MCU_POWER_STATE_LOW_POWER: ret = "MCU_POWER_STATE_LOW_POWER"; break; case SPINEL_MCU_POWER_STATE_OFF: ret = "MCU_POWER_STATE_OFF"; break; default: break; } return ret; } const char *spinel_status_to_cstr(spinel_status_t status) { const char *ret = "UNKNOWN"; switch (status) { case SPINEL_STATUS_OK: ret = "OK"; break; case SPINEL_STATUS_FAILURE: ret = "FAILURE"; break; case SPINEL_STATUS_UNIMPLEMENTED: ret = "UNIMPLEMENTED"; break; case SPINEL_STATUS_INVALID_ARGUMENT: ret = "INVALID_ARGUMENT"; break; case SPINEL_STATUS_INVALID_STATE: ret = "INVALID_STATE"; break; case SPINEL_STATUS_INVALID_COMMAND: ret = "INVALID_COMMAND"; break; case SPINEL_STATUS_INVALID_INTERFACE: ret = "INVALID_INTERFACE"; break; case SPINEL_STATUS_INTERNAL_ERROR: ret = "INTERNAL_ERROR"; break; case SPINEL_STATUS_SECURITY_ERROR: ret = "SECURITY_ERROR"; break; case SPINEL_STATUS_PARSE_ERROR: ret = "PARSE_ERROR"; break; case SPINEL_STATUS_IN_PROGRESS: ret = "IN_PROGRESS"; break; case SPINEL_STATUS_NOMEM: ret = "NOMEM"; break; case SPINEL_STATUS_BUSY: ret = "BUSY"; break; case SPINEL_STATUS_PROP_NOT_FOUND: ret = "PROP_NOT_FOUND"; break; case SPINEL_STATUS_DROPPED: ret = "DROPPED"; break; case SPINEL_STATUS_EMPTY: ret = "EMPTY"; break; case SPINEL_STATUS_CMD_TOO_BIG: ret = "CMD_TOO_BIG"; break; case SPINEL_STATUS_NO_ACK: ret = "NO_ACK"; break; case SPINEL_STATUS_CCA_FAILURE: ret = "CCA_FAILURE"; break; case SPINEL_STATUS_ALREADY: ret = "ALREADY"; break; case SPINEL_STATUS_ITEM_NOT_FOUND: ret = "ITEM_NOT_FOUND"; break; case SPINEL_STATUS_INVALID_COMMAND_FOR_PROP: ret = "INVALID_COMMAND_FOR_PROP"; break; case SPINEL_STATUS_JOIN_FAILURE: ret = "JOIN_FAILURE"; break; case SPINEL_STATUS_JOIN_SECURITY: ret = "JOIN_SECURITY"; break; case SPINEL_STATUS_JOIN_NO_PEERS: ret = "JOIN_NO_PEERS"; break; case SPINEL_STATUS_JOIN_INCOMPATIBLE: ret = "JOIN_INCOMPATIBLE"; break; case SPINEL_STATUS_JOIN_RSP_TIMEOUT: ret = "JOIN_RSP_TIMEOUT"; break; case SPINEL_STATUS_JOIN_SUCCESS: ret = "JOIN_SUCCESS"; break; case SPINEL_STATUS_RESET_POWER_ON: ret = "RESET_POWER_ON"; break; case SPINEL_STATUS_RESET_EXTERNAL: ret = "RESET_EXTERNAL"; break; case SPINEL_STATUS_RESET_SOFTWARE: ret = "RESET_SOFTWARE"; break; case SPINEL_STATUS_RESET_FAULT: ret = "RESET_FAULT"; break; case SPINEL_STATUS_RESET_CRASH: ret = "RESET_CRASH"; break; case SPINEL_STATUS_RESET_ASSERT: ret = "RESET_ASSERT"; break; case SPINEL_STATUS_RESET_OTHER: ret = "RESET_OTHER"; break; case SPINEL_STATUS_RESET_UNKNOWN: ret = "RESET_UNKNOWN"; break; case SPINEL_STATUS_RESET_WATCHDOG: ret = "RESET_WATCHDOG"; break; default: break; } return ret; } const char *spinel_capability_to_cstr(spinel_capability_t capability) { const char *ret = "UNKNOWN"; switch (capability) { case SPINEL_CAP_LOCK: ret = "LOCK"; break; case SPINEL_CAP_NET_SAVE: ret = "NET_SAVE"; break; case SPINEL_CAP_HBO: ret = "HBO"; break; case SPINEL_CAP_POWER_SAVE: ret = "POWER_SAVE"; break; case SPINEL_CAP_COUNTERS: ret = "COUNTERS"; break; case SPINEL_CAP_JAM_DETECT: ret = "JAM_DETECT"; break; case SPINEL_CAP_PEEK_POKE: ret = "PEEK_POKE"; break; case SPINEL_CAP_WRITABLE_RAW_STREAM: ret = "WRITABLE_RAW_STREAM"; break; case SPINEL_CAP_GPIO: ret = "GPIO"; break; case SPINEL_CAP_TRNG: ret = "TRNG"; break; case SPINEL_CAP_CMD_MULTI: ret = "CMD_MULTI"; break; case SPINEL_CAP_UNSOL_UPDATE_FILTER: ret = "UNSOL_UPDATE_FILTER"; break; case SPINEL_CAP_MCU_POWER_STATE: ret = "MCU_POWER_STATE"; break; case SPINEL_CAP_PCAP: ret = "PCAP"; break; case SPINEL_CAP_802_15_4_2003: ret = "802_15_4_2003"; break; case SPINEL_CAP_802_15_4_2006: ret = "802_15_4_2006"; break; case SPINEL_CAP_802_15_4_2011: ret = "802_15_4_2011"; break; case SPINEL_CAP_802_15_4_PIB: ret = "802_15_4_PIB"; break; case SPINEL_CAP_802_15_4_2450MHZ_OQPSK: ret = "802_15_4_2450MHZ_OQPSK"; break; case SPINEL_CAP_802_15_4_915MHZ_OQPSK: ret = "802_15_4_915MHZ_OQPSK"; break; case SPINEL_CAP_802_15_4_868MHZ_OQPSK: ret = "802_15_4_868MHZ_OQPSK"; break; case SPINEL_CAP_802_15_4_915MHZ_BPSK: ret = "802_15_4_915MHZ_BPSK"; break; case SPINEL_CAP_802_15_4_868MHZ_BPSK: ret = "802_15_4_868MHZ_BPSK"; break; case SPINEL_CAP_802_15_4_915MHZ_ASK: ret = "802_15_4_915MHZ_ASK"; break; case SPINEL_CAP_802_15_4_868MHZ_ASK: ret = "802_15_4_868MHZ_ASK"; break; case SPINEL_CAP_CONFIG_FTD: ret = "CONFIG_FTD"; break; case SPINEL_CAP_CONFIG_MTD: ret = "CONFIG_MTD"; break; case SPINEL_CAP_CONFIG_RADIO: ret = "CONFIG_RADIO"; break; case SPINEL_CAP_ROLE_ROUTER: ret = "ROLE_ROUTER"; break; case SPINEL_CAP_ROLE_SLEEPY: ret = "ROLE_SLEEPY"; break; case SPINEL_CAP_NET_THREAD_1_0: ret = "NET_THREAD_1_0"; break; case SPINEL_CAP_NET_THREAD_1_1: ret = "NET_THREAD_1_1"; break; case SPINEL_CAP_MAC_WHITELIST: ret = "MAC_WHITELIST"; break; case SPINEL_CAP_MAC_RAW: ret = "MAC_RAW"; break; case SPINEL_CAP_OOB_STEERING_DATA: ret = "OOB_STEERING_DATA"; break; case SPINEL_CAP_CHANNEL_MONITOR: ret = "CHANNEL_MONITOR"; break; case SPINEL_CAP_CHANNEL_MANAGER: ret = "CHANNEL_MANAGER"; break; case SPINEL_CAP_OPENTHREAD_LOG_METADATA: ret = "OPENTHREAD_LOG_METADATA"; break; case SPINEL_CAP_TIME_SYNC: ret = "TIME_SYNC"; break; case SPINEL_CAP_CHILD_SUPERVISION: ret = "CHILD_SUPERVISION"; break; case SPINEL_CAP_POSIX: ret = "POSIX"; break; case SPINEL_CAP_SLAAC: ret = "SLAAC"; break; case SPINEL_CAP_RADIO_COEX: ret = "RADIO_COEX"; break; case SPINEL_CAP_MAC_RETRY_HISTOGRAM: ret = "MAC_RETRY_HISTOGRAM"; break; case SPINEL_CAP_ERROR_RATE_TRACKING: ret = "ERROR_RATE_TRACKING"; break; case SPINEL_CAP_THREAD_COMMISSIONER: ret = "THREAD_COMMISSIONER"; break; case SPINEL_CAP_THREAD_TMF_PROXY: ret = "THREAD_TMF_PROXY"; break; case SPINEL_CAP_THREAD_UDP_FORWARD: ret = "THREAD_UDP_FORWARD"; break; case SPINEL_CAP_THREAD_JOINER: ret = "THREAD_JOINER"; break; case SPINEL_CAP_THREAD_BORDER_ROUTER: ret = "THREAD_BORDER_ROUTER"; break; case SPINEL_CAP_THREAD_SERVICE: ret = "THREAD_SERVICE"; break; case SPINEL_CAP_NEST_LEGACY_INTERFACE: ret = "NEST_LEGACY_INTERFACE"; break; case SPINEL_CAP_NEST_LEGACY_NET_WAKE: ret = "NEST_LEGACY_NET_WAKE"; break; case SPINEL_CAP_NEST_TRANSMIT_HOOK: ret = "NEST_TRANSMIT_HOOK"; break; default: break; } return ret; } // LCOV_EXCL_STOP /* -------------------------------------------------------------------------- */ #if SPINEL_SELF_TEST int main(void) { int ret = -1; const spinel_eui64_t static_eui64 = {{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}}; const char static_string[] = "static_string"; uint8_t buffer[1024]; ssize_t len; len = spinel_datatype_pack(buffer, sizeof(buffer), "CiiLUE", 0x88, 9, 0xA3, 0xDEADBEEF, static_string, &static_eui64); if (len != 30) { printf("error:%d: len != 30; (%d)\n", __LINE__, (int)len); goto bail; } { const char *str = NULL; // Length ends right before the string. len = spinel_datatype_unpack(buffer, 8, "CiiLU", NULL, NULL, NULL, NULL, &str); if (len != -1) { printf("error:%d: len != -1; (%d)\n", __LINE__, (int)len); goto bail; } if (str != NULL) { printf("error:%d: str != NULL\n", __LINE__); goto bail; } } len = 30; { uint8_t c = 0; unsigned int i1 = 0; unsigned int i2 = 0; uint32_t l = 0; const char * str = NULL; const spinel_eui64_t *eui64 = NULL; len = spinel_datatype_unpack(buffer, (spinel_size_t)len, "CiiLUE", &c, &i1, &i2, &l, &str, &eui64); if (len != 30) { printf("error:%d: len != 30; (%d)\n", __LINE__, (int)len); goto bail; } if (c != 0x88) { printf("error: x != 0x88; (%d)\n", c); goto bail; } if (i1 != 9) { printf("error: i1 != 9; (%d)\n", i1); goto bail; } if (i2 != 0xA3) { printf("error: i2 != 0xA3; (0x%02X)\n", i2); goto bail; } if (l != 0xDEADBEEF) { printf("error: l != 0xDEADBEEF; (0x%08X)\n", (unsigned int)l); goto bail; } if (strcmp(str, static_string) != 0) { printf("error:%d: strcmp(str,static_string) != 0\n", __LINE__); goto bail; } if (memcmp(eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0) { printf("error:%d: memcmp(eui64, &eui64, sizeof(spinel_eui64_t)) != 0\n", __LINE__); goto bail; } } { uint8_t c = 0; unsigned int i1 = 0; unsigned int i2 = 0; uint32_t l = 0; char str[sizeof(static_string)]; spinel_eui64_t eui64 = {{0}}; len = spinel_datatype_unpack_in_place(buffer, (spinel_size_t)len, "CiiLUE", &c, &i1, &i2, &l, &str, sizeof(str), &eui64); if (len != 30) { printf("error:%d: len != 30; (%d)\n", __LINE__, (int)len); goto bail; } if (c != 0x88) { printf("error: x != 0x88; (%d)\n", c); goto bail; } if (i1 != 9) { printf("error: i1 != 9; (%d)\n", i1); goto bail; } if (i2 != 0xA3) { printf("error: i2 != 0xA3; (0x%02X)\n", i2); goto bail; } if (l != 0xDEADBEEF) { printf("error: l != 0xDEADBEEF; (0x%08X)\n", (unsigned int)l); goto bail; } if (strcmp(str, static_string) != 0) { printf("error:%d: strcmp(str,static_string) != 0\n", __LINE__); goto bail; } if (memcmp(&eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0) { printf("error:%d: memcmp(&eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0\n", __LINE__); goto bail; } } // ----------------------------------- memset(buffer, 0xAA, sizeof(buffer)); len = spinel_datatype_pack(buffer, sizeof(buffer), "Cit(iL)UE", 0x88, 9, 0xA3, 0xDEADBEEF, static_string, &static_eui64); if (len != 32) { printf("error:%d: len != 32; (%d)\n", __LINE__, (int)len); goto bail; } { uint8_t c = 0; unsigned int i1 = 0; unsigned int i2 = 0; uint32_t l = 0; const char * str = NULL; spinel_eui64_t *eui64 = NULL; len = spinel_datatype_unpack(buffer, (spinel_size_t)len, "Cit(iL)UE", &c, &i1, &i2, &l, &str, &eui64); if (len != 32) { printf("error:%d: len != 24; (%d)\n", __LINE__, (int)len); goto bail; } if (c != 0x88) { printf("error: x != 0x88; (%d)\n", c); goto bail; } if (i1 != 9) { printf("error: i1 != 9; (%d)\n", i1); goto bail; } if (i2 != 0xA3) { printf("error: i2 != 0xA3; (0x%02X)\n", i2); goto bail; } if (l != 0xDEADBEEF) { printf("error: l != 0xDEADBEEF; (0x%08X)\n", (unsigned int)l); goto bail; } if (strcmp(str, static_string) != 0) { printf("error:%d: strcmp(str,static_string) != 0\n", __LINE__); goto bail; } if (memcmp(eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0) { printf("error:%d: memcmp(eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0\n", __LINE__); goto bail; } } { uint8_t c = 0; unsigned int i1 = 0; unsigned int i2 = 0; uint32_t l = 0; char str[sizeof(static_string)]; spinel_eui64_t eui64 = {{0}}; len = spinel_datatype_unpack_in_place(buffer, (spinel_size_t)len, "Cit(iL)UE", &c, &i1, &i2, &l, &str, sizeof(str), &eui64); if (len != 32) { printf("error:%d: len != 24; (%d)\n", __LINE__, (int)len); goto bail; } if (c != 0x88) { printf("error: x != 0x88; (%d)\n", c); goto bail; } if (i1 != 9) { printf("error: i1 != 9; (%d)\n", i1); goto bail; } if (i2 != 0xA3) { printf("error: i2 != 0xA3; (0x%02X)\n", i2); goto bail; } if (l != 0xDEADBEEF) { printf("error: l != 0xDEADBEEF; (0x%08X)\n", (unsigned int)l); goto bail; } if (strcmp(str, static_string) != 0) { printf("error:%d: strcmp(str,static_string) != 0\n", __LINE__); goto bail; } if (memcmp(&eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0) { printf("error:%d: memcmp(&eui64, &static_eui64, sizeof(spinel_eui64_t)) != 0\n", __LINE__); goto bail; } } { // Test UTF8 validation - Good/Valid strings // Single symbols const uint8_t single1[] = {0}; // 0000 const uint8_t single2[] = {0x7F, 0x00}; // 007F const uint8_t single3[] = {0xC2, 0x80, 0x00}; // 080 const uint8_t single4[] = {0xDF, 0xBF, 0x00}; // 07FF const uint8_t single5[] = {0xE0, 0xA0, 0x80, 0x00}; // 0800 const uint8_t single6[] = {0xEF, 0xBF, 0xBF, 0x00}; // FFFF const uint8_t single7[] = {0xF0, 0x90, 0x80, 0x80, 0x00}; // 010000 const uint8_t single8[] = {0xF4, 0x8F, 0xBF, 0xBF, 0x00}; // 10FFFF // Strings const uint8_t str1[] = "spinel"; const uint8_t str2[] = "OpenThread"; const uint8_t str3[] = {0x41, 0x7F, 0xEF, 0xBF, 0xBF, 0xC2, 0x80, 0x21, 0x33, 0x00}; const uint8_t str4[] = {0xCE, 0xBA, 0xE1, 0xBD, 0xB9, 0xCF, 0x83, 0xCE, 0xBC, 0xCE, 0xB5, 0x00}; // κόσμε const uint8_t str5[] = {0x3D, 0xF4, 0x8F, 0xBF, 0xBF, 0x01, 0xE0, 0xA0, 0x83, 0x22, 0xEF, 0xBF, 0xBF, 0x00}; const uint8_t str6[] = {0xE5, 0xA2, 0x82, 0xE0, 0xA0, 0x80, 0xC2, 0x83, 0xC2, 0x80, 0xF4, 0x8F, 0xBF, 0xBF, 0xF4, 0x8F, 0xBF, 0xBF, 0xDF, 0xBF, 0x21, 0x00}; const uint8_t * good_strings[] = {single1, single2, single3, single4, single5, single6, single7, single8, str1, str2, str3, str4, str5, str6, NULL}; const uint8_t **str_ptr; for (str_ptr = &good_strings[0]; *str_ptr != NULL; str_ptr++) { if (!spinel_validate_utf8(*str_ptr)) { printf("error: spinel_validate_utf8() did not correctly detect a valid UTF8 sequence!\n"); goto bail; } } } { // Test UTF8 validation - Bad/Invalid strings // Single symbols (invalid) const uint8_t single1[] = {0xF8, 0x00}; const uint8_t single2[] = {0xF9, 0x00}; const uint8_t single3[] = {0xFA, 0x00}; const uint8_t single4[] = {0xFF, 0x00}; // Bad continuations const uint8_t bad1[] = {0xDF, 0x0F, 0x00}; const uint8_t bad2[] = {0xE0, 0xA0, 0x10, 0x00}; const uint8_t bad3[] = {0xF0, 0x90, 0x80, 0x60, 0x00}; const uint8_t bad4[] = {0xF4, 0x8F, 0xBF, 0x0F, 0x00}; const uint8_t bad5[] = {0x21, 0xA0, 0x00}; const uint8_t bad6[] = {0xCE, 0xBA, 0xE1, 0xBD, 0xB9, 0xCF, 0x83, 0xCE, 0xBC, 0xCE, 0x00}; const uint8_t * bad_strings[] = {single1, single2, single3, single4, bad1, bad2, bad3, bad4, bad5, bad6, NULL}; const uint8_t **str_ptr; for (str_ptr = &bad_strings[0]; *str_ptr != NULL; str_ptr++) { if (spinel_validate_utf8(*str_ptr)) { printf("error: spinel_validate_utf8() did not correctly detect an invalid UTF8 sequence\n"); goto bail; } } } printf("OK\n"); ret = 0; return ret; bail: printf("FAILURE\n"); return ret; } #endif // #if SPINEL_SELF_TEST