xref: /netbsd-src/lib/libbluetooth/sdp_get.c (revision da9817918ec7e88db2912a2882967c7570a83f47)
1 /*	$NetBSD: sdp_get.c,v 1.1 2009/05/12 10:05:06 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.1 2009/05/12 10:05:06 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 
49 bool
50 sdp_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 
65 bool
66 sdp_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 
82 bool
83 sdp_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 
125 bool
126 sdp_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 
152 bool
153 sdp_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 		if (v > UINTMAX_MAX)
192 			return false;
193 
194 		p += 8;
195 		break;
196 
197 	case SDP_DATA_UINT128:
198 		if (p + 16 > data->end)
199 			return false;
200 
201 		x = be64dec(p);
202 		v = be64dec(p + 8);
203 		if (x != 0 || v > UINTMAX_MAX)
204 			return false;
205 
206 		p += 16;
207 		break;
208 
209 	default:
210 		return false;
211 	}
212 
213 	data->next = p;
214 	*value = (uintmax_t)v;
215 	return true;
216 }
217 
218 bool
219 sdp_get_int(sdp_data_t *data, intmax_t *value)
220 {
221 	uint8_t *p = data->next;
222 	int64_t v, x;
223 
224 	if (p + 1 > data->end)
225 		return false;
226 
227 	switch (*p++) {
228 	case SDP_DATA_INT8:
229 		if (p + 1 > data->end)
230 			return false;
231 
232 		v = *(int8_t *)p;
233 		p += 1;
234 		break;
235 
236 	case SDP_DATA_INT16:
237 		if (p + 2 > data->end)
238 			return false;
239 
240 		v = (int16_t)be16dec(p);
241 		p += 2;
242 		break;
243 
244 	case SDP_DATA_INT32:
245 		if (p + 4 > data->end)
246 			return false;
247 
248 		v = (int32_t)be32dec(p);
249 		p += 4;
250 		break;
251 
252 	case SDP_DATA_INT64:
253 		if (p + 8 > data->end)
254 			return false;
255 
256 		v = (int64_t)be64dec(p);
257 		if (v > INTMAX_MAX || v < INTMAX_MIN)
258 			return false;
259 
260 		p += 8;
261 		break;
262 
263 	case SDP_DATA_INT128:
264 		if (p + 16 > data->end)
265 			return false;
266 
267 		x = (int64_t)be64dec(p);
268 		v = (int64_t)be64dec(p + 8);
269 		if (x == 0) {
270 			if (v > INTMAX_MAX)
271 				return false;
272 		} else if (x == -1) {
273 			if (v < INTMAX_MIN)
274 				return false;
275 		} else {
276 			return false;
277 		}
278 
279 		p += 16;
280 		break;
281 
282 	default:
283 		return false;
284 	}
285 
286 	data->next = p;
287 	*value = (intmax_t)v;
288 	return true;
289 }
290 
291 static bool
292 _sdp_get_ext(uint8_t type, sdp_data_t *data, sdp_data_t *ext)
293 {
294 	uint8_t *p = data->next;
295 	uint32_t l;
296 
297 	if (p + 1 > data->end
298 	    || SDP_DATA_TYPE(*p) != type)
299 		return false;
300 
301 	switch (SDP_DATA_SIZE(*p++)) {
302 	case SDP_DATA_EXT8:
303 		if (p + 1 > data->end)
304 			return false;
305 
306 		l = *p;
307 		p += 1;
308 		break;
309 
310 	case SDP_DATA_EXT16:
311 		if (p + 2 > data->end)
312 			return false;
313 
314 		l = be16dec(p);
315 		p += 2;
316 		break;
317 
318 	case SDP_DATA_EXT32:
319 		if (p + 4 > data->end)
320 			return false;
321 
322 		l = be32dec(p);
323 		p += 4;
324 		break;
325 
326 	default:
327 		return false;
328 	}
329 
330 	if (p + l > data->end)
331 		return false;
332 
333 	data->next = p + l;
334 	ext->next = p;
335 	ext->end = p + l;
336 	return true;
337 }
338 
339 bool
340 sdp_get_seq(sdp_data_t *data, sdp_data_t *seq)
341 {
342 
343 	return _sdp_get_ext(SDP_DATA_SEQ, data, seq);
344 }
345 
346 bool
347 sdp_get_alt(sdp_data_t *data, sdp_data_t *alt)
348 {
349 
350 	return _sdp_get_ext(SDP_DATA_ALT, data, alt);
351 }
352 
353 bool
354 sdp_get_str(sdp_data_t *data, char **str, size_t *len)
355 {
356 	sdp_data_t s;
357 
358 	if (!_sdp_get_ext(SDP_DATA_STR, data, &s))
359 		return false;
360 
361 	*str = (char *)s.next;
362 	*len = s.end - s.next;
363 	return true;
364 }
365 
366 bool
367 sdp_get_url(sdp_data_t *data, char **url, size_t *len)
368 {
369 	sdp_data_t u;
370 
371 	if (!_sdp_get_ext(SDP_DATA_URL, data, &u))
372 		return false;
373 
374 	*url = (char *)u.next;
375 	*len = u.end - u.next;
376 	return true;
377 }
378