/*-
* 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.
*/
/******************************************************************************
* 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;