xref: /netbsd/lib/libbluetooth/sdp_get.c (revision 3702d2b6)
1 /*	$NetBSD: sdp_get.c,v 1.3 2011/04/04 18:29:47 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.3 2011/04/04 18:29:47 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
sdp_get_data(sdp_data_t * data,sdp_data_t * value)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
sdp_get_attr(sdp_data_t * data,uint16_t * attr,sdp_data_t * value)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
sdp_get_uuid(sdp_data_t * data,uuid_t * uuid)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
sdp_get_bool(sdp_data_t * data,bool * value)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
sdp_get_uint(sdp_data_t * data,uintmax_t * value)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 		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 
215 bool
sdp_get_int(sdp_data_t * data,intmax_t * value)216 sdp_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 
285 static bool
_sdp_get_ext(uint8_t type,sdp_data_t * data,sdp_data_t * ext)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 
333 bool
sdp_get_seq(sdp_data_t * data,sdp_data_t * seq)334 sdp_get_seq(sdp_data_t *data, sdp_data_t *seq)
335 {
336 
337 	return _sdp_get_ext(SDP_DATA_SEQ, data, seq);
338 }
339 
340 bool
sdp_get_alt(sdp_data_t * data,sdp_data_t * alt)341 sdp_get_alt(sdp_data_t *data, sdp_data_t *alt)
342 {
343 
344 	return _sdp_get_ext(SDP_DATA_ALT, data, alt);
345 }
346 
347 bool
sdp_get_str(sdp_data_t * data,char ** str,size_t * len)348 sdp_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 
360 bool
sdp_get_url(sdp_data_t * data,char ** url,size_t * len)361 sdp_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