/* $NetBSD: sdp_data.c,v 1.4 2012/03/22 23:46:49 joerg Exp $ */ /*- * Copyright (c) 2009 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Iain Hibbert. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. */ #include __RCSID("$NetBSD: sdp_data.c,v 1.4 2012/03/22 23:46:49 joerg Exp $"); #include #include #include #include #include "sdp-int.h" /****************************************************************************** * sdp_data_type(data) * * return SDP data element type */ int sdp_data_type(const sdp_data_t *data) { if (data->next + 1 > data->end) return -1; return data->next[0]; } /****************************************************************************** * sdp_data_size(data) * * return the size of SDP data element. This will fail (return -1) if * the data element does not fit into the data space. */ ssize_t sdp_data_size(const sdp_data_t *data) { uint8_t *p = data->next; if (p + 1 > data->end) return -1; switch (*p++) { case SDP_DATA_NIL: break; case SDP_DATA_BOOL: case SDP_DATA_INT8: case SDP_DATA_UINT8: p += 1; break; case SDP_DATA_INT16: case SDP_DATA_UINT16: case SDP_DATA_UUID16: p += 2; break; case SDP_DATA_INT32: case SDP_DATA_UINT32: case SDP_DATA_UUID32: p += 4; break; case SDP_DATA_INT64: case SDP_DATA_UINT64: p += 8; break; case SDP_DATA_INT128: case SDP_DATA_UINT128: case SDP_DATA_UUID128: p += 16; break; case SDP_DATA_ALT8: case SDP_DATA_SEQ8: case SDP_DATA_STR8: case SDP_DATA_URL8: if (p + 1 > data->end) return -1; p += 1 + *p; break; case SDP_DATA_ALT16: case SDP_DATA_SEQ16: case SDP_DATA_STR16: case SDP_DATA_URL16: if (p + 2 > data->end) return -1; p += 2 + be16dec(p); break; case SDP_DATA_ALT32: case SDP_DATA_SEQ32: case SDP_DATA_STR32: case SDP_DATA_URL32: if (p + 4 > data->end) return -1; p += 4 + be32dec(p); break; default: return -1; } if (p > data->end) return -1; return (p - data->next); } /****************************************************************************** * sdp_data_valid(data) * * validate an SDP data element list recursively, ensuring elements do not * expand past the claimed length and that there is no invalid data. */ static bool _sdp_data_valid(uint8_t *ptr, uint8_t *end) { size_t len; while (ptr < end) { if (ptr + 1 > end) return false; switch (*ptr++) { case SDP_DATA_NIL: break; case SDP_DATA_BOOL: case SDP_DATA_INT8: case SDP_DATA_UINT8: if (ptr + 1 > end) return false; ptr += 1; break; case SDP_DATA_INT16: case SDP_DATA_UINT16: case SDP_DATA_UUID16: if (ptr + 2 > end) return false; ptr += 2; break; case SDP_DATA_INT32: case SDP_DATA_UINT32: case SDP_DATA_UUID32: if (ptr + 4 > end) return false; ptr += 4; break; case SDP_DATA_INT64: case SDP_DATA_UINT64: if (ptr + 8 > end) return false; ptr += 8; break; case SDP_DATA_INT128: case SDP_DATA_UINT128: case SDP_DATA_UUID128: if (ptr + 16 > end) return false; ptr += 16; break; case SDP_DATA_STR8: case SDP_DATA_URL8: if (ptr + 1 > end) return false; len = *ptr; ptr += 1; if (ptr + len > end) return false; ptr += len; break; case SDP_DATA_STR16: case SDP_DATA_URL16: if (ptr + 2 > end) return false; len = be16dec(ptr); ptr += 2; if (ptr + len > end) return false; ptr += len; break; case SDP_DATA_STR32: case SDP_DATA_URL32: if (ptr + 4 > end) return false; len = be32dec(ptr); ptr += 4; if (ptr + len > end) return false; ptr += len; break; case SDP_DATA_SEQ8: case SDP_DATA_ALT8: if (ptr + 1 > end) return false; len = *ptr; ptr += 1; if (ptr + len > end) return false; if (!_sdp_data_valid(ptr, ptr + len)) return false; ptr += len; break; case SDP_DATA_SEQ16: case SDP_DATA_ALT16: if (ptr + 2 > end) return false; len = be16dec(ptr); ptr += 2; if (ptr + len > end) return false; if (!_sdp_data_valid(ptr, ptr + len)) return false; ptr += len; break; case SDP_DATA_SEQ32: case SDP_DATA_ALT32: if (ptr + 4 > end) return false; len = be32dec(ptr); ptr += 4; if (ptr + len > end) return false; if (!_sdp_data_valid(ptr, ptr + len)) return false; ptr += len; break; default: return false; } } return true; } bool sdp_data_valid(const sdp_data_t *data) { if (data->next == NULL || data->end == NULL) return false; if (data->next >= data->end) return false; return _sdp_data_valid(data->next, data->end); } /****************************************************************************** * sdp_data_print(data, indent) * * print out a SDP data element list in human readable format */ static __printflike(3, 4) void _sdp_put(int indent, const char *type, const char *fmt, ...) { va_list ap; indent = printf("%*s%s", indent, "", type); indent = 18 - indent; if (indent < 2) indent = 2; printf("%*s", indent, ""); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); } static void _sdp_putstr(int indent, const char *type, const uint8_t *str, size_t len) { char buf[50], *dst = buf; int style; indent = printf("%*s%s(%zu)", indent, "", type, len); indent = 18 - indent; if (indent < 2) indent = 2; printf("%*s", indent, ""); style = VIS_CSTYLE | VIS_NL; buf[0] = '\0'; while (len > 0 && (dst + 5) < (buf + sizeof(buf))) { dst = vis(dst, str[0], style, (len > 0 ? str[1] : 0)); str++; len--; } printf("\"%s%s\n", buf, (len == 0 ? "\"" : " ...")); } bool _sdp_data_print(const uint8_t *next, const uint8_t *end, int indent) { size_t len; while (next < end) { if (next + 1 > end) return false; switch (*next++) { case SDP_DATA_NIL: _sdp_put(indent, "nil", ""); break; case SDP_DATA_BOOL: if (next + 1 > end) return false; _sdp_put(indent, "bool", "%s", (*next == 0x00 ? "false" : "true")); next += 1; break; case SDP_DATA_INT8: if (next + 1 > end) return false; _sdp_put(indent, "int8", "%" PRId8, *(const int8_t *)next); next += 1; break; case SDP_DATA_UINT8: if (next + 1 > end) return false; _sdp_put(indent, "uint8", "0x%02" PRIx8, *next); next += 1; break; case SDP_DATA_INT16: if (next + 2 > end) return false; _sdp_put(indent, "int16", "%" PRId16, (int16_t)be16dec(next)); next += 2; break; case SDP_DATA_UINT16: if (next + 2 > end) return false; _sdp_put(indent, "uint16", "0x%04" PRIx16, be16dec(next)); next += 2; break; case SDP_DATA_UUID16: if (next + 2 > end) return false; _sdp_put(indent, "uuid16", "0x%04" PRIx16, be16dec(next)); next += 2; break; case SDP_DATA_INT32: if (next + 4 > end) return false; _sdp_put(indent, "int32", "%" PRId32, (int32_t)be32dec(next)); next += 4; break; case SDP_DATA_UINT32: if (next + 4 > end) return false; _sdp_put(indent, "uint32", "0x%08" PRIx32, be32dec(next)); next += 4; break; case SDP_DATA_UUID32: if (next + 4 > end) return false; _sdp_put(indent, "uuid32", "0x%08" PRIx32, be32dec(next)); next += 4; break; case SDP_DATA_INT64: if (next + 8 > end) return false; _sdp_put(indent, "int64", "%" PRId64, (int64_t)be64dec(next)); next += 8; break; case SDP_DATA_UINT64: if (next + 8 > end) return false; _sdp_put(indent, "uint64", "0x%016" PRIx64, be64dec(next)); next += 8; break; case SDP_DATA_INT128: if (next + 16 > end) return false; _sdp_put(indent, "int128", "0x%02x%02x%02x%02x%02x%02x%02x%02x" "%02x%02x%02x%02x%02x%02x%02x%02x", next[0], next[1], next[2], next[3], next[4], next[5], next[6], next[7], next[8], next[9], next[10], next[11], next[12], next[13], next[14], next[15]); next += 16; break; case SDP_DATA_UINT128: if (next + 16 > end) return false; _sdp_put(indent, "uint128", "0x%02x%02x%02x%02x%02x%02x%02x%02x" "%02x%02x%02x%02x%02x%02x%02x%02x", next[0], next[1], next[2], next[3], next[4], next[5], next[6], next[7], next[8], next[9], next[10], next[11], next[12], next[13], next[14], next[15]); next += 16; break; case SDP_DATA_UUID128: if (next + 16 > end) return false; _sdp_put(indent, "uuid128", "%02x%02x%02x%02x-" "%02x%02x-" "%02x%02x-" "%02x%02x-" "%02x%02x%02x%02x%02x%02x", next[0], next[1], next[2], next[3], next[4], next[5], next[6], next[7], next[8], next[9], next[10], next[11], next[12], next[13], next[14], next[15]); next += 16; break; case SDP_DATA_STR8: if (next + 1 > end) return false; len = *next; next += 1; if (next + len > end) return false; _sdp_putstr(indent, "str8", next, len); next += len; break; case SDP_DATA_URL8: if (next + 1 > end) return false; len = *next; next += 1; if (next + len > end) return false; _sdp_putstr(indent, "url8", next, len); next += len; break; case SDP_DATA_STR16: if (next + 2 > end) return false; len = be16dec(next); next += 2; if (next + len > end) return false; _sdp_putstr(indent, "str16", next, len); next += len; break; case SDP_DATA_URL16: if (next + 2 > end) return false; len = be16dec(next); next += 2; if (next + len > end) return false; _sdp_putstr(indent, "url16", next, len); next += len; break; case SDP_DATA_STR32: if (next + 4 > end) return false; len = be32dec(next); next += 4; if (next + len > end) return false; _sdp_putstr(indent, "str32", next, len); next += len; break; case SDP_DATA_URL32: if (next + 4 > end) return false; len = be32dec(next); next += 4; if (next + len > end) return false; _sdp_putstr(indent, "url32", next, len); next += len; break; case SDP_DATA_SEQ8: if (next + 1 > end) return false; len = *next; next += 1; if (next + len > end) return false; printf("%*sseq8(%zu)\n", indent, "", len); if (!_sdp_data_print(next, next + len, indent + 1)) return false; next += len; break; case SDP_DATA_ALT8: if (next + 1 > end) return false; len = *next; next += 1; if (next + len > end) return false; printf("%*salt8(%zu)\n", indent, "", len); if (!_sdp_data_print(next, next + len, indent + 1)) return false; next += len; break; case SDP_DATA_SEQ16: if (next + 2 > end) return false; len = be16dec(next); next += 2; if (next + len > end) return false; printf("%*sseq16(%zu)\n", indent, "", len); if (!_sdp_data_print(next, next + len, indent + 1)) return false; next += len; break; case SDP_DATA_ALT16: if (next + 2 > end) return false; len = be16dec(next); next += 2; if (next + len > end) return false; printf("%*salt16(%zu)\n", indent, "", len); if (!_sdp_data_print(next, next + len, indent + 1)) return false; next += len; break; case SDP_DATA_SEQ32: if (next + 4 > end) return false; len = be32dec(next); next += 4; if (next + len > end) return false; printf("%*sseq32(%zu)\n", indent, "", len); if (!_sdp_data_print(next, next + len, indent + 1)) return false; next += len; break; case SDP_DATA_ALT32: if (next + 4 > end) return false; len = be32dec(next); next += 4; if (next + len > end) return false; printf("%*salt32(%zu)\n", indent, "", len); if (!_sdp_data_print(next, next + len, indent + 1)) return false; next += len; break; default: return false; } } return true; } void sdp_data_print(const sdp_data_t *data, int indent) { if (!_sdp_data_print(data->next, data->end, indent)) printf("SDP data error\n"); }