sdp_service.c revision 1.4 1 1.4 plunky /* $NetBSD: sdp_service.c,v 1.4 2010/11/20 12:12:21 plunky Exp $ */
2 1.1 plunky
3 1.1 plunky /*-
4 1.1 plunky * Copyright (c) 2009 The NetBSD Foundation, Inc.
5 1.1 plunky * All rights reserved.
6 1.1 plunky *
7 1.1 plunky * This code is derived from software contributed to The NetBSD Foundation
8 1.1 plunky * by Iain Hibbert.
9 1.1 plunky *
10 1.1 plunky * Redistribution and use in source and binary forms, with or without
11 1.1 plunky * modification, are permitted provided that the following conditions
12 1.1 plunky * are met:
13 1.1 plunky * 1. Redistributions of source code must retain the above copyright
14 1.1 plunky * notice, this list of conditions and the following disclaimer.
15 1.1 plunky * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 plunky * notice, this list of conditions and the following disclaimer in the
17 1.1 plunky * documentation and/or other materials provided with the distribution.
18 1.1 plunky *
19 1.1 plunky * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 plunky * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 plunky * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 plunky * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 plunky * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 plunky * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 plunky * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 plunky * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 plunky * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 plunky * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 plunky * POSSIBILITY OF SUCH DAMAGE.
30 1.1 plunky */
31 1.1 plunky
32 1.1 plunky #include <sys/cdefs.h>
33 1.4 plunky __RCSID("$NetBSD: sdp_service.c,v 1.4 2010/11/20 12:12:21 plunky Exp $");
34 1.4 plunky
35 1.4 plunky #include <sys/atomic.h>
36 1.1 plunky
37 1.1 plunky #include <errno.h>
38 1.1 plunky #include <limits.h>
39 1.1 plunky #include <sdp.h>
40 1.1 plunky #include <stdlib.h>
41 1.1 plunky #include <string.h>
42 1.1 plunky #include <unistd.h>
43 1.1 plunky
44 1.1 plunky #include "sdp-int.h"
45 1.1 plunky
46 1.1 plunky /*
47 1.1 plunky * If AttributeIDList is given as NULL, request all attributes.
48 1.4 plunky * (this is actually const data but we can't declare it const)
49 1.1 plunky */
50 1.1 plunky static uint8_t ail_default[] = { 0x0a, 0x00, 0x00, 0xff, 0xff };
51 1.1 plunky
52 1.1 plunky /*
53 1.1 plunky * This provides the maximum size that the response buffer will be
54 1.1 plunky * allowed to grow to.
55 1.1 plunky *
56 1.1 plunky * Default is UINT16_MAX but it can be overridden at runtime.
57 1.1 plunky */
58 1.1 plunky static size_t
59 1.1 plunky sdp_response_max(void)
60 1.1 plunky {
61 1.1 plunky static size_t max = UINT16_MAX;
62 1.4 plunky static unsigned int check = 1;
63 1.1 plunky char *env, *ep;
64 1.1 plunky unsigned long v;
65 1.1 plunky
66 1.4 plunky while (atomic_swap_uint(&check, 0)) { /* only check env once */
67 1.1 plunky env = getenv("SDP_RESPONSE_MAX");
68 1.1 plunky if (env == NULL)
69 1.1 plunky break;
70 1.1 plunky
71 1.1 plunky errno = 0;
72 1.1 plunky v = strtoul(env, &ep, 0);
73 1.1 plunky if (env[0] == '\0' || *ep != '\0')
74 1.1 plunky break;
75 1.1 plunky
76 1.1 plunky if (errno == ERANGE && v == ULONG_MAX)
77 1.1 plunky break;
78 1.1 plunky
79 1.1 plunky /* lower limit is arbitrary */
80 1.1 plunky if (v < UINT8_MAX || v > UINT32_MAX)
81 1.1 plunky break;
82 1.1 plunky
83 1.1 plunky max = v;
84 1.1 plunky }
85 1.1 plunky
86 1.1 plunky return max;
87 1.1 plunky }
88 1.1 plunky
89 1.1 plunky bool
90 1.1 plunky sdp_service_search(struct sdp_session *ss, const sdp_data_t *ssp,
91 1.1 plunky uint32_t *id, int *num)
92 1.1 plunky {
93 1.1 plunky struct iovec req[5];
94 1.1 plunky sdp_data_t hdr;
95 1.1 plunky uint8_t sdata[5], max[2];
96 1.1 plunky uint8_t *ptr, *end;
97 1.1 plunky ssize_t len;
98 1.1 plunky uint16_t total, count, got;
99 1.1 plunky
100 1.1 plunky /*
101 1.1 plunky * setup ServiceSearchPattern
102 1.1 plunky */
103 1.1 plunky len = ssp->end - ssp->next;
104 1.1 plunky if (len < 0 || len > UINT16_MAX) {
105 1.1 plunky errno = EINVAL;
106 1.1 plunky return false;
107 1.1 plunky }
108 1.1 plunky
109 1.1 plunky hdr.next = sdata;
110 1.1 plunky hdr.end = sdata + sizeof(sdata) + len;
111 1.1 plunky sdp_put_seq(&hdr, len);
112 1.1 plunky req[1].iov_base = sdata;
113 1.1 plunky req[1].iov_len = hdr.next - sdata;
114 1.1 plunky
115 1.1 plunky req[2].iov_base = ssp->next;
116 1.1 plunky req[2].iov_len = len;
117 1.1 plunky
118 1.1 plunky /*
119 1.1 plunky * setup MaximumServiceRecordCount
120 1.1 plunky */
121 1.1 plunky if (*num < 0 || *num > UINT16_MAX) {
122 1.1 plunky errno = EINVAL;
123 1.1 plunky return false;
124 1.1 plunky }
125 1.1 plunky be16enc(max, *num);
126 1.1 plunky req[3].iov_base = max;
127 1.1 plunky req[3].iov_len = sizeof(uint16_t);
128 1.1 plunky
129 1.1 plunky /*
130 1.1 plunky * clear ContinuationState
131 1.1 plunky */
132 1.1 plunky ss->cs[0] = 0;
133 1.1 plunky
134 1.1 plunky /*
135 1.1 plunky * ServiceSearch Transaction
136 1.1 plunky */
137 1.1 plunky got = 0;
138 1.1 plunky for (;;) {
139 1.1 plunky /*
140 1.1 plunky * setup ContinuationState
141 1.1 plunky */
142 1.1 plunky req[4].iov_base = ss->cs;
143 1.1 plunky req[4].iov_len = ss->cs[0] + 1;
144 1.1 plunky
145 1.1 plunky if (!_sdp_send_pdu(ss, SDP_PDU_SERVICE_SEARCH_REQUEST,
146 1.1 plunky req, __arraycount(req)))
147 1.1 plunky return false;
148 1.1 plunky
149 1.1 plunky len = _sdp_recv_pdu(ss, SDP_PDU_SERVICE_SEARCH_RESPONSE);
150 1.1 plunky if (len == -1)
151 1.1 plunky return false;
152 1.1 plunky
153 1.1 plunky ptr = ss->ibuf;
154 1.1 plunky end = ss->ibuf + len;
155 1.1 plunky
156 1.1 plunky /*
157 1.1 plunky * extract TotalServiceRecordCount
158 1.1 plunky */
159 1.1 plunky if (ptr + sizeof(uint16_t) > end)
160 1.1 plunky break;
161 1.1 plunky
162 1.1 plunky total = be16dec(ptr);
163 1.1 plunky ptr += sizeof(uint16_t);
164 1.1 plunky if (total > *num)
165 1.1 plunky break;
166 1.1 plunky
167 1.1 plunky /*
168 1.1 plunky * extract CurrentServiceRecordCount
169 1.1 plunky */
170 1.1 plunky if (ptr + sizeof(uint16_t) > end)
171 1.1 plunky break;
172 1.1 plunky
173 1.1 plunky count = be16dec(ptr);
174 1.1 plunky ptr += sizeof(uint16_t);
175 1.1 plunky if (got + count > total)
176 1.1 plunky break;
177 1.1 plunky
178 1.1 plunky /*
179 1.1 plunky * extract ServiceRecordHandleList
180 1.1 plunky */
181 1.1 plunky if (ptr + count * sizeof(uint32_t) > end)
182 1.1 plunky break;
183 1.1 plunky
184 1.1 plunky while (count-- > 0) {
185 1.1 plunky id[got++] = be32dec(ptr);
186 1.1 plunky ptr += sizeof(uint32_t);
187 1.1 plunky }
188 1.1 plunky
189 1.1 plunky /*
190 1.1 plunky * extract ContinuationState
191 1.1 plunky */
192 1.1 plunky if (ptr + 1 > end
193 1.1 plunky || ptr[0] > 16
194 1.1 plunky || ptr + ptr[0] + 1 != end)
195 1.1 plunky break;
196 1.1 plunky
197 1.3 plunky memcpy(ss->cs, ptr, (size_t)(ptr[0] + 1));
198 1.1 plunky
199 1.1 plunky /*
200 1.1 plunky * Complete?
201 1.1 plunky */
202 1.1 plunky if (ss->cs[0] == 0) {
203 1.1 plunky *num = got;
204 1.1 plunky return true;
205 1.1 plunky }
206 1.1 plunky }
207 1.1 plunky
208 1.1 plunky errno = EIO;
209 1.1 plunky return false;
210 1.1 plunky }
211 1.1 plunky
212 1.1 plunky bool
213 1.1 plunky sdp_service_attribute(struct sdp_session *ss, uint32_t id,
214 1.1 plunky const sdp_data_t *ail, sdp_data_t *rsp)
215 1.1 plunky {
216 1.1 plunky struct iovec req[6];
217 1.1 plunky sdp_data_t hdr;
218 1.1 plunky uint8_t adata[5], handle[4], max[2];
219 1.1 plunky uint8_t *ptr, *end, *rbuf;
220 1.1 plunky ssize_t len;
221 1.1 plunky size_t rlen, count;
222 1.1 plunky
223 1.1 plunky /*
224 1.1 plunky * setup ServiceRecordHandle
225 1.1 plunky */
226 1.1 plunky be32enc(handle, id);
227 1.1 plunky req[1].iov_base = handle;
228 1.1 plunky req[1].iov_len = sizeof(uint32_t);
229 1.1 plunky
230 1.1 plunky /*
231 1.1 plunky * setup MaximumAttributeByteCount
232 1.1 plunky */
233 1.1 plunky be16enc(max, ss->imtu - sizeof(uint16_t) - sizeof(ss->cs));
234 1.1 plunky req[2].iov_base = max;
235 1.1 plunky req[2].iov_len = sizeof(uint16_t);
236 1.1 plunky
237 1.1 plunky /*
238 1.1 plunky * setup AttributeIDList
239 1.1 plunky */
240 1.2 plunky len = (ail == NULL ? (ssize_t)sizeof(ail_default) : (ail->end - ail->next));
241 1.1 plunky if (len < 0 || len > UINT16_MAX) {
242 1.1 plunky errno = EINVAL;
243 1.1 plunky return false;
244 1.1 plunky }
245 1.1 plunky
246 1.1 plunky hdr.next = adata;
247 1.1 plunky hdr.end = adata + sizeof(adata) + len;
248 1.1 plunky sdp_put_seq(&hdr, len);
249 1.1 plunky req[3].iov_base = adata;
250 1.1 plunky req[3].iov_len = hdr.next - adata;
251 1.1 plunky
252 1.1 plunky req[4].iov_base = (ail == NULL ? ail_default : ail->next);
253 1.1 plunky req[4].iov_len = len;
254 1.1 plunky
255 1.1 plunky /*
256 1.1 plunky * clear ContinuationState
257 1.1 plunky */
258 1.1 plunky ss->cs[0] = 0;
259 1.1 plunky
260 1.1 plunky /*
261 1.1 plunky * ServiceAttribute Transaction
262 1.1 plunky */
263 1.1 plunky rlen = 0;
264 1.1 plunky for (;;) {
265 1.1 plunky /*
266 1.1 plunky * setup ContinuationState
267 1.1 plunky */
268 1.1 plunky req[5].iov_base = ss->cs;
269 1.1 plunky req[5].iov_len = ss->cs[0] + 1;
270 1.1 plunky
271 1.1 plunky if (!_sdp_send_pdu(ss, SDP_PDU_SERVICE_ATTRIBUTE_REQUEST,
272 1.1 plunky req, __arraycount(req)))
273 1.1 plunky return false;
274 1.1 plunky
275 1.1 plunky len = _sdp_recv_pdu(ss, SDP_PDU_SERVICE_ATTRIBUTE_RESPONSE);
276 1.1 plunky if (len == -1)
277 1.1 plunky return false;
278 1.1 plunky
279 1.1 plunky ptr = ss->ibuf;
280 1.1 plunky end = ss->ibuf + len;
281 1.1 plunky
282 1.1 plunky /*
283 1.1 plunky * extract AttributeListByteCount
284 1.1 plunky */
285 1.1 plunky if (ptr + sizeof(uint16_t) > end)
286 1.1 plunky break;
287 1.1 plunky
288 1.1 plunky count = be16dec(ptr);
289 1.1 plunky ptr += sizeof(uint16_t);
290 1.1 plunky if (count == 0 || ptr + count > end)
291 1.1 plunky break;
292 1.1 plunky
293 1.1 plunky /*
294 1.1 plunky * extract AttributeList
295 1.1 plunky */
296 1.1 plunky if (rlen + count > sdp_response_max())
297 1.1 plunky break;
298 1.1 plunky
299 1.1 plunky rbuf = realloc(ss->rbuf, rlen + count);
300 1.1 plunky if (rbuf == NULL)
301 1.1 plunky return false;
302 1.1 plunky
303 1.1 plunky ss->rbuf = rbuf;
304 1.1 plunky memcpy(rbuf + rlen, ptr, count);
305 1.1 plunky rlen += count;
306 1.1 plunky ptr += count;
307 1.1 plunky
308 1.1 plunky /*
309 1.1 plunky * extract ContinuationState
310 1.1 plunky */
311 1.1 plunky if (ptr + 1 > end
312 1.1 plunky || ptr[0] > 16
313 1.1 plunky || ptr + ptr[0] + 1 != end)
314 1.1 plunky break;
315 1.1 plunky
316 1.3 plunky memcpy(ss->cs, ptr, (size_t)(ptr[0] + 1));
317 1.1 plunky
318 1.1 plunky /*
319 1.1 plunky * Complete?
320 1.1 plunky */
321 1.1 plunky if (ss->cs[0] == 0) {
322 1.1 plunky rsp->next = rbuf;
323 1.1 plunky rsp->end = rbuf + rlen;
324 1.2 plunky if (sdp_data_size(rsp) != (ssize_t)rlen
325 1.1 plunky || !sdp_data_valid(rsp)
326 1.1 plunky || !sdp_get_seq(rsp, rsp))
327 1.1 plunky break;
328 1.1 plunky
329 1.1 plunky return true;
330 1.1 plunky }
331 1.1 plunky }
332 1.1 plunky
333 1.1 plunky errno = EIO;
334 1.1 plunky return false;
335 1.1 plunky }
336 1.1 plunky
337 1.1 plunky bool
338 1.1 plunky sdp_service_search_attribute(struct sdp_session *ss, const sdp_data_t *ssp,
339 1.1 plunky const sdp_data_t *ail, sdp_data_t *rsp)
340 1.1 plunky {
341 1.1 plunky struct iovec req[7];
342 1.1 plunky sdp_data_t hdr;
343 1.1 plunky uint8_t sdata[5], adata[5], max[2];
344 1.1 plunky uint8_t *ptr, *end, *rbuf;
345 1.1 plunky ssize_t len;
346 1.1 plunky size_t rlen, count;
347 1.1 plunky
348 1.1 plunky /*
349 1.1 plunky * setup ServiceSearchPattern
350 1.1 plunky */
351 1.1 plunky len = ssp->end - ssp->next;
352 1.1 plunky if (len < 0 || len > UINT16_MAX) {
353 1.1 plunky errno = EINVAL;
354 1.1 plunky return false;
355 1.1 plunky }
356 1.1 plunky
357 1.1 plunky hdr.next = sdata;
358 1.1 plunky hdr.end = sdata + sizeof(sdata) + len;
359 1.1 plunky sdp_put_seq(&hdr, len);
360 1.1 plunky req[1].iov_base = sdata;
361 1.1 plunky req[1].iov_len = hdr.next - sdata;
362 1.1 plunky
363 1.1 plunky req[2].iov_base = ssp->next;
364 1.1 plunky req[2].iov_len = len;
365 1.1 plunky
366 1.1 plunky /*
367 1.1 plunky * setup MaximumAttributeByteCount
368 1.1 plunky */
369 1.1 plunky be16enc(max, ss->imtu - sizeof(uint16_t) - sizeof(ss->cs));
370 1.1 plunky req[3].iov_base = max;
371 1.1 plunky req[3].iov_len = sizeof(uint16_t);
372 1.1 plunky
373 1.1 plunky /*
374 1.1 plunky * setup AttributeIDList
375 1.1 plunky */
376 1.2 plunky len = (ail == NULL ? (ssize_t)sizeof(ail_default) : (ail->end - ail->next));
377 1.1 plunky if (len < 0 || len > UINT16_MAX) {
378 1.1 plunky errno = EINVAL;
379 1.1 plunky return false;
380 1.1 plunky }
381 1.1 plunky
382 1.1 plunky hdr.next = adata;
383 1.1 plunky hdr.end = adata + sizeof(adata) + len;
384 1.1 plunky sdp_put_seq(&hdr, len);
385 1.1 plunky req[4].iov_base = adata;
386 1.1 plunky req[4].iov_len = hdr.next - adata;
387 1.1 plunky
388 1.1 plunky req[5].iov_base = (ail == NULL ? ail_default : ail->next);
389 1.1 plunky req[5].iov_len = len;
390 1.1 plunky
391 1.1 plunky /*
392 1.1 plunky * clear ContinuationState
393 1.1 plunky */
394 1.1 plunky ss->cs[0] = 0;
395 1.1 plunky
396 1.1 plunky /*
397 1.1 plunky * ServiceSearchAttribute Transaction
398 1.1 plunky */
399 1.1 plunky rlen = 0;
400 1.1 plunky for (;;) {
401 1.1 plunky /*
402 1.1 plunky * setup ContinuationState
403 1.1 plunky */
404 1.1 plunky req[6].iov_base = ss->cs;
405 1.1 plunky req[6].iov_len = ss->cs[0] + 1;
406 1.1 plunky
407 1.1 plunky if (!_sdp_send_pdu(ss, SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST,
408 1.1 plunky req, __arraycount(req)))
409 1.1 plunky return false;
410 1.1 plunky
411 1.1 plunky len = _sdp_recv_pdu(ss, SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_RESPONSE);
412 1.1 plunky if (len == -1)
413 1.1 plunky return false;
414 1.1 plunky
415 1.1 plunky ptr = ss->ibuf;
416 1.1 plunky end = ss->ibuf + len;
417 1.1 plunky
418 1.1 plunky /*
419 1.1 plunky * extract AttributeListsByteCount
420 1.1 plunky */
421 1.1 plunky if (ptr + sizeof(uint16_t) > end)
422 1.1 plunky break;
423 1.1 plunky
424 1.1 plunky count = be16dec(ptr);
425 1.1 plunky ptr += sizeof(uint16_t);
426 1.1 plunky if (count == 0 || ptr + count > end)
427 1.1 plunky break;
428 1.1 plunky
429 1.1 plunky /*
430 1.1 plunky * extract AttributeLists
431 1.1 plunky */
432 1.1 plunky if (rlen + count > sdp_response_max())
433 1.1 plunky break;
434 1.1 plunky
435 1.1 plunky rbuf = realloc(ss->rbuf, rlen + count);
436 1.1 plunky if (rbuf == NULL)
437 1.1 plunky return false;
438 1.1 plunky
439 1.1 plunky ss->rbuf = rbuf;
440 1.1 plunky memcpy(rbuf + rlen, ptr, count);
441 1.1 plunky rlen += count;
442 1.1 plunky ptr += count;
443 1.1 plunky
444 1.1 plunky /*
445 1.1 plunky * extract ContinuationState
446 1.1 plunky */
447 1.1 plunky if (ptr + 1 > end
448 1.1 plunky || ptr[0] > 16
449 1.1 plunky || ptr + ptr[0] + 1 != end)
450 1.1 plunky break;
451 1.1 plunky
452 1.3 plunky memcpy(ss->cs, ptr, (size_t)(ptr[0] + 1));
453 1.1 plunky
454 1.1 plunky /*
455 1.1 plunky * Complete?
456 1.1 plunky */
457 1.1 plunky if (ss->cs[0] == 0) {
458 1.1 plunky rsp->next = rbuf;
459 1.1 plunky rsp->end = rbuf + rlen;
460 1.2 plunky if (sdp_data_size(rsp) != (ssize_t)rlen
461 1.1 plunky || !sdp_data_valid(rsp)
462 1.1 plunky || !sdp_get_seq(rsp, rsp))
463 1.1 plunky break;
464 1.1 plunky
465 1.1 plunky return true;
466 1.1 plunky }
467 1.1 plunky }
468 1.1 plunky
469 1.1 plunky errno = EIO;
470 1.1 plunky return false;
471 1.1 plunky }
472