sdp_get.c revision 1.2 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 #if INTMAX_MAX < INT64_MAX
39 #warning INTMAX type is not large enough to hold INT64 values
40 #endif
41
42 /******************************************************************************
43 * sdp_get_xxxx(data, value)
44 *
45 * examine first SDP data element in list for xxx type, extracting to given
46 * storage and advancing pointer if found.
47 * - these functions will not modify data pointer unless the value was
48 * extracted successfully
49 * - these functions always update the data pointer before the value pointer,
50 * so where the value is a sdp_data_t the data struct can be discarded.
51 */
52
53 bool
54 sdp_get_data(sdp_data_t *data, sdp_data_t *value)
55 {
56 uint8_t *p = data->next;
57 ssize_t l = sdp_data_size(data);
58
59 if (l == -1
60 || p + l > data->end)
61 return false;
62
63 data->next = p + l;
64 value->next = p;
65 value->end = p + l;
66 return true;
67 }
68
69 bool
70 sdp_get_attr(sdp_data_t *data, uint16_t *attr, sdp_data_t *value)
71 {
72 sdp_data_t v, d = *data;
73 uintmax_t a;
74
75 if (sdp_data_type(&d) != SDP_DATA_UINT16
76 || !sdp_get_uint(&d, &a)
77 || !sdp_get_data(&d, &v))
78 return false;
79
80 *attr = (uint16_t)a;
81 *data = d;
82 *value = v;
83 return true;
84 }
85
86 bool
87 sdp_get_uuid(sdp_data_t *data, uuid_t *uuid)
88 {
89 uint8_t *p = data->next;
90
91 if (p + 1 > data->end)
92 return false;
93
94 switch (*p++) {
95 case SDP_DATA_UUID16:
96 if (p + 2 > data->end)
97 return false;
98
99 *uuid = BLUETOOTH_BASE_UUID;
100 uuid->time_low = be16dec(p);
101 p += 2;
102 break;
103
104 case SDP_DATA_UUID32:
105 if (p + 4 > data->end)
106 return false;
107
108 *uuid = BLUETOOTH_BASE_UUID;
109 uuid->time_low = be32dec(p);
110 p += 4;
111 break;
112
113 case SDP_DATA_UUID128:
114 if (p + 16 > data->end)
115 return false;
116
117 uuid_dec_be(p, uuid);
118 p += 16;
119 break;
120
121 default:
122 return false;
123 }
124
125 data->next = p;
126 return true;
127 }
128
129 bool
130 sdp_get_bool(sdp_data_t *data, bool *value)
131 {
132 uint8_t *p = data->next;
133 uint8_t v;
134
135 if (p + 1 > data->end)
136 return false;
137
138 switch (*p++) {
139 case SDP_DATA_BOOL:
140 if (p + 1 > data->end)
141 return false;
142
143 v = *p;
144 p += 1;
145 break;
146
147 default:
148 return false;
149 }
150
151 data->next = p;
152 *value = ((v != 0) ? true : false);
153 return true;
154 }
155
156 bool
157 sdp_get_uint(sdp_data_t *data, uintmax_t *value)
158 {
159 uint8_t *p = data->next;
160 uint64_t v, x;
161
162 if (p + 1 > data->end)
163 return false;
164
165 switch (*p++) {
166 case SDP_DATA_UINT8:
167 if (p + 1 > data->end)
168 return false;
169
170 v = *p;
171 p += 1;
172 break;
173
174 case SDP_DATA_UINT16:
175 if (p + 2 > data->end)
176 return false;
177
178 v = be16dec(p);
179 p += 2;
180 break;
181
182 case SDP_DATA_UINT32:
183 if (p + 4 > data->end)
184 return false;
185
186 v = be32dec(p);
187 p += 4;
188 break;
189
190 case SDP_DATA_UINT64:
191 if (p + 8 > data->end)
192 return false;
193
194 v = be64dec(p);
195 p += 8;
196 break;
197
198 case SDP_DATA_UINT128:
199 if (p + 16 > data->end)
200 return false;
201
202 x = be64dec(p);
203 v = be64dec(p + 8);
204 if (x != 0)
205 return false;
206
207 p += 16;
208 break;
209
210 default:
211 return false;
212 }
213
214 data->next = p;
215 *value = (uintmax_t)v;
216 return true;
217 }
218
219 bool
220 sdp_get_int(sdp_data_t *data, intmax_t *value)
221 {
222 uint8_t *p = data->next;
223 int64_t v, x;
224
225 if (p + 1 > data->end)
226 return false;
227
228 switch (*p++) {
229 case SDP_DATA_INT8:
230 if (p + 1 > data->end)
231 return false;
232
233 v = *(int8_t *)p;
234 p += 1;
235 break;
236
237 case SDP_DATA_INT16:
238 if (p + 2 > data->end)
239 return false;
240
241 v = (int16_t)be16dec(p);
242 p += 2;
243 break;
244
245 case SDP_DATA_INT32:
246 if (p + 4 > data->end)
247 return false;
248
249 v = (int32_t)be32dec(p);
250 p += 4;
251 break;
252
253 case SDP_DATA_INT64:
254 if (p + 8 > data->end)
255 return false;
256
257 v = (int64_t)be64dec(p);
258 p += 8;
259 break;
260
261 case SDP_DATA_INT128:
262 if (p + 16 > data->end)
263 return false;
264
265 x = (int64_t)be64dec(p);
266 v = (int64_t)be64dec(p + 8);
267 if (x == 0) {
268 if (v < 0)
269 return false;
270 } else if (x == -1) {
271 if (v >= 0)
272 return false;
273 } else {
274 return false;
275 }
276
277 p += 16;
278 break;
279
280 default:
281 return false;
282 }
283
284 data->next = p;
285 *value = (intmax_t)v;
286 return true;
287 }
288
289 static bool
290 _sdp_get_ext(uint8_t type, sdp_data_t *data, sdp_data_t *ext)
291 {
292 uint8_t *p = data->next;
293 uint32_t l;
294
295 if (p + 1 > data->end
296 || SDP_DATA_TYPE(*p) != type)
297 return false;
298
299 switch (SDP_DATA_SIZE(*p++)) {
300 case SDP_DATA_EXT8:
301 if (p + 1 > data->end)
302 return false;
303
304 l = *p;
305 p += 1;
306 break;
307
308 case SDP_DATA_EXT16:
309 if (p + 2 > data->end)
310 return false;
311
312 l = be16dec(p);
313 p += 2;
314 break;
315
316 case SDP_DATA_EXT32:
317 if (p + 4 > data->end)
318 return false;
319
320 l = be32dec(p);
321 p += 4;
322 break;
323
324 default:
325 return false;
326 }
327
328 if (p + l > data->end)
329 return false;
330
331 data->next = p + l;
332 ext->next = p;
333 ext->end = p + l;
334 return true;
335 }
336
337 bool
338 sdp_get_seq(sdp_data_t *data, sdp_data_t *seq)
339 {
340
341 return _sdp_get_ext(SDP_DATA_SEQ, data, seq);
342 }
343
344 bool
345 sdp_get_alt(sdp_data_t *data, sdp_data_t *alt)
346 {
347
348 return _sdp_get_ext(SDP_DATA_ALT, data, alt);
349 }
350
351 bool
352 sdp_get_str(sdp_data_t *data, char **str, size_t *len)
353 {
354 sdp_data_t s;
355
356 if (!_sdp_get_ext(SDP_DATA_STR, data, &s))
357 return false;
358
359 *str = (char *)s.next;
360 *len = s.end - s.next;
361 return true;
362 }
363
364 bool
365 sdp_get_url(sdp_data_t *data, char **url, size_t *len)
366 {
367 sdp_data_t u;
368
369 if (!_sdp_get_ext(SDP_DATA_URL, data, &u))
370 return false;
371
372 *url = (char *)u.next;
373 *len = u.end - u.next;
374 return true;
375 }
376