1/*	$NetBSD: sdp_get.c,v 1.2 2011/04/04 16:19:25 plunky Exp $	*/
2
3/*-
4 * Copyright (c) 2009 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Iain Hibbert.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__RCSID("$NetBSD: sdp_get.c,v 1.2 2011/04/04 16:19:25 plunky Exp $");
34
35#include <sdp.h>
36#include <limits.h>
37
38/******************************************************************************
39 *	sdp_get_xxxx(data, value)
40 *
41 * examine first SDP data element in list for xxx type, extracting to given
42 * storage and advancing pointer if found.
43 * - these functions will not modify data pointer unless the value was
44 *   extracted successfully
45 * - these functions always update the data pointer before the value pointer,
46 *   so where the value is a sdp_data_t the data struct can be discarded.
47 */
48
49bool
50sdp_get_data(sdp_data_t *data, sdp_data_t *value)
51{
52	uint8_t *p = data->next;
53	ssize_t l = sdp_data_size(data);
54
55	if (l == -1
56	    || p + l > data->end)
57		return false;
58
59	data->next = p + l;
60	value->next = p;
61	value->end = p + l;
62	return true;
63}
64
65bool
66sdp_get_attr(sdp_data_t *data, uint16_t *attr, sdp_data_t *value)
67{
68	sdp_data_t v, d = *data;
69	uintmax_t a;
70
71	if (sdp_data_type(&d) != SDP_DATA_UINT16
72	    || !sdp_get_uint(&d, &a)
73	    || !sdp_get_data(&d, &v))
74		return false;
75
76	*attr = (uint16_t)a;
77	*data = d;
78	*value = v;
79	return true;
80}
81
82bool
83sdp_get_uuid(sdp_data_t *data, uuid_t *uuid)
84{
85	uint8_t *p = data->next;
86
87	if (p + 1 > data->end)
88		return false;
89
90	switch (*p++) {
91	case SDP_DATA_UUID16:
92		if (p + 2 > data->end)
93			return false;
94
95		*uuid = BLUETOOTH_BASE_UUID;
96		uuid->time_low = be16dec(p);
97		p += 2;
98		break;
99
100	case SDP_DATA_UUID32:
101		if (p + 4 > data->end)
102			return false;
103
104		*uuid = BLUETOOTH_BASE_UUID;
105		uuid->time_low = be32dec(p);
106		p += 4;
107		break;
108
109	case SDP_DATA_UUID128:
110		if (p + 16 > data->end)
111			return false;
112
113		uuid_dec_be(p, uuid);
114		p += 16;
115		break;
116
117	default:
118		return false;
119	}
120
121	data->next = p;
122	return true;
123}
124
125bool
126sdp_get_bool(sdp_data_t *data, bool *value)
127{
128	uint8_t *p = data->next;
129	uint8_t v;
130
131	if (p + 1 > data->end)
132		return false;
133
134	switch (*p++) {
135	case SDP_DATA_BOOL:
136		if (p + 1 > data->end)
137			return false;
138
139		v = *p;
140		p += 1;
141		break;
142
143	default:
144		return false;
145	}
146
147	data->next = p;
148	*value = ((v != 0) ? true : false);
149	return true;
150}
151
152bool
153sdp_get_uint(sdp_data_t *data, uintmax_t *value)
154{
155	uint8_t *p = data->next;
156	uint64_t v, x;
157
158	if (p + 1 > data->end)
159		return false;
160
161	switch (*p++) {
162	case SDP_DATA_UINT8:
163		if (p + 1 > data->end)
164			return false;
165
166		v = *p;
167		p += 1;
168		break;
169
170	case SDP_DATA_UINT16:
171		if (p + 2 > data->end)
172			return false;
173
174		v = be16dec(p);
175		p += 2;
176		break;
177
178	case SDP_DATA_UINT32:
179		if (p + 4 > data->end)
180			return false;
181
182		v = be32dec(p);
183		p += 4;
184		break;
185
186	case SDP_DATA_UINT64:
187		if (p + 8 > data->end)
188			return false;
189
190		v = be64dec(p);
191		p += 8;
192		break;
193
194	case SDP_DATA_UINT128:
195		if (p + 16 > data->end)
196			return false;
197
198		x = be64dec(p);
199		v = be64dec(p + 8);
200		if (x != 0)
201			return false;
202
203		p += 16;
204		break;
205
206	default:
207		return false;
208	}
209
210	data->next = p;
211	*value = (uintmax_t)v;
212	return true;
213}
214
215bool
216sdp_get_int(sdp_data_t *data, intmax_t *value)
217{
218	uint8_t *p = data->next;
219	int64_t v, x;
220
221	if (p + 1 > data->end)
222		return false;
223
224	switch (*p++) {
225	case SDP_DATA_INT8:
226		if (p + 1 > data->end)
227			return false;
228
229		v = *(int8_t *)p;
230		p += 1;
231		break;
232
233	case SDP_DATA_INT16:
234		if (p + 2 > data->end)
235			return false;
236
237		v = (int16_t)be16dec(p);
238		p += 2;
239		break;
240
241	case SDP_DATA_INT32:
242		if (p + 4 > data->end)
243			return false;
244
245		v = (int32_t)be32dec(p);
246		p += 4;
247		break;
248
249	case SDP_DATA_INT64:
250		if (p + 8 > data->end)
251			return false;
252
253		v = (int64_t)be64dec(p);
254		p += 8;
255		break;
256
257	case SDP_DATA_INT128:
258		if (p + 16 > data->end)
259			return false;
260
261		x = (int64_t)be64dec(p);
262		v = (int64_t)be64dec(p + 8);
263		if (x == 0) {
264			if (v < 0)
265				return false;
266		} else if (x == -1) {
267			if (v >= 0)
268				return false;
269		} else {
270			return false;
271		}
272
273		p += 16;
274		break;
275
276	default:
277		return false;
278	}
279
280	data->next = p;
281	*value = (intmax_t)v;
282	return true;
283}
284
285static bool
286_sdp_get_ext(uint8_t type, sdp_data_t *data, sdp_data_t *ext)
287{
288	uint8_t *p = data->next;
289	uint32_t l;
290
291	if (p + 1 > data->end
292	    || SDP_DATA_TYPE(*p) != type)
293		return false;
294
295	switch (SDP_DATA_SIZE(*p++)) {
296	case SDP_DATA_EXT8:
297		if (p + 1 > data->end)
298			return false;
299
300		l = *p;
301		p += 1;
302		break;
303
304	case SDP_DATA_EXT16:
305		if (p + 2 > data->end)
306			return false;
307
308		l = be16dec(p);
309		p += 2;
310		break;
311
312	case SDP_DATA_EXT32:
313		if (p + 4 > data->end)
314			return false;
315
316		l = be32dec(p);
317		p += 4;
318		break;
319
320	default:
321		return false;
322	}
323
324	if (p + l > data->end)
325		return false;
326
327	data->next = p + l;
328	ext->next = p;
329	ext->end = p + l;
330	return true;
331}
332
333bool
334sdp_get_seq(sdp_data_t *data, sdp_data_t *seq)
335{
336
337	return _sdp_get_ext(SDP_DATA_SEQ, data, seq);
338}
339
340bool
341sdp_get_alt(sdp_data_t *data, sdp_data_t *alt)
342{
343
344	return _sdp_get_ext(SDP_DATA_ALT, data, alt);
345}
346
347bool
348sdp_get_str(sdp_data_t *data, char **str, size_t *len)
349{
350	sdp_data_t s;
351
352	if (!_sdp_get_ext(SDP_DATA_STR, data, &s))
353		return false;
354
355	*str = (char *)s.next;
356	*len = s.end - s.next;
357	return true;
358}
359
360bool
361sdp_get_url(sdp_data_t *data, char **url, size_t *len)
362{
363	sdp_data_t u;
364
365	if (!_sdp_get_ext(SDP_DATA_URL, data, &u))
366		return false;
367
368	*url = (char *)u.next;
369	*len = u.end - u.next;
370	return true;
371}
372