1 /* $NetBSD: sdp_service.c,v 1.1 2009/05/12 10:05:06 plunky Exp $ */
4 * Copyright (c) 2009 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: sdp_service.c,v 1.1 2009/05/12 10:05:06 plunky Exp $");
45 * If AttributeIDList is given as NULL, request all attributes.
47 static uint8_t ail_default
[] = { 0x0a, 0x00, 0x00, 0xff, 0xff };
50 * This provides the maximum size that the response buffer will be
53 * Default is UINT16_MAX but it can be overridden at runtime.
56 sdp_response_max(void)
58 static size_t max
= UINT16_MAX
;
59 static bool check
= true;
64 check
= false; /* only check env once */
66 env
= getenv("SDP_RESPONSE_MAX");
71 v
= strtoul(env
, &ep
, 0);
72 if (env
[0] == '\0' || *ep
!= '\0')
75 if (errno
== ERANGE
&& v
== ULONG_MAX
)
78 /* lower limit is arbitrary */
79 if (v
< UINT8_MAX
|| v
> UINT32_MAX
)
89 sdp_service_search(struct sdp_session
*ss
, const sdp_data_t
*ssp
,
90 uint32_t *id
, int *num
)
94 uint8_t sdata
[5], max
[2];
97 uint16_t total
, count
, got
;
100 * setup ServiceSearchPattern
102 len
= ssp
->end
- ssp
->next
;
103 if (len
< 0 || len
> UINT16_MAX
) {
109 hdr
.end
= sdata
+ sizeof(sdata
) + len
;
110 sdp_put_seq(&hdr
, len
);
111 req
[1].iov_base
= sdata
;
112 req
[1].iov_len
= hdr
.next
- sdata
;
114 req
[2].iov_base
= ssp
->next
;
115 req
[2].iov_len
= len
;
118 * setup MaximumServiceRecordCount
120 if (*num
< 0 || *num
> UINT16_MAX
) {
125 req
[3].iov_base
= max
;
126 req
[3].iov_len
= sizeof(uint16_t);
129 * clear ContinuationState
134 * ServiceSearch Transaction
139 * setup ContinuationState
141 req
[4].iov_base
= ss
->cs
;
142 req
[4].iov_len
= ss
->cs
[0] + 1;
144 if (!_sdp_send_pdu(ss
, SDP_PDU_SERVICE_SEARCH_REQUEST
,
145 req
, __arraycount(req
)))
148 len
= _sdp_recv_pdu(ss
, SDP_PDU_SERVICE_SEARCH_RESPONSE
);
153 end
= ss
->ibuf
+ len
;
156 * extract TotalServiceRecordCount
158 if (ptr
+ sizeof(uint16_t) > end
)
161 total
= be16dec(ptr
);
162 ptr
+= sizeof(uint16_t);
167 * extract CurrentServiceRecordCount
169 if (ptr
+ sizeof(uint16_t) > end
)
172 count
= be16dec(ptr
);
173 ptr
+= sizeof(uint16_t);
174 if (got
+ count
> total
)
178 * extract ServiceRecordHandleList
180 if (ptr
+ count
* sizeof(uint32_t) > end
)
183 while (count
-- > 0) {
184 id
[got
++] = be32dec(ptr
);
185 ptr
+= sizeof(uint32_t);
189 * extract ContinuationState
193 || ptr
+ ptr
[0] + 1 != end
)
196 memcpy(ss
->cs
, ptr
, ptr
[0] + 1);
201 if (ss
->cs
[0] == 0) {
212 sdp_service_attribute(struct sdp_session
*ss
, uint32_t id
,
213 const sdp_data_t
*ail
, sdp_data_t
*rsp
)
217 uint8_t adata
[5], handle
[4], max
[2];
218 uint8_t *ptr
, *end
, *rbuf
;
223 * setup ServiceRecordHandle
226 req
[1].iov_base
= handle
;
227 req
[1].iov_len
= sizeof(uint32_t);
230 * setup MaximumAttributeByteCount
232 be16enc(max
, ss
->imtu
- sizeof(uint16_t) - sizeof(ss
->cs
));
233 req
[2].iov_base
= max
;
234 req
[2].iov_len
= sizeof(uint16_t);
237 * setup AttributeIDList
239 len
= (ail
== NULL
? (ssize_t
)sizeof(ail_default
) : (ail
->end
- ail
->next
));
240 if (len
< 0 || len
> UINT16_MAX
) {
246 hdr
.end
= adata
+ sizeof(adata
) + len
;
247 sdp_put_seq(&hdr
, len
);
248 req
[3].iov_base
= adata
;
249 req
[3].iov_len
= hdr
.next
- adata
;
251 req
[4].iov_base
= (ail
== NULL
? ail_default
: ail
->next
);
252 req
[4].iov_len
= len
;
255 * clear ContinuationState
260 * ServiceAttribute Transaction
265 * setup ContinuationState
267 req
[5].iov_base
= ss
->cs
;
268 req
[5].iov_len
= ss
->cs
[0] + 1;
270 if (!_sdp_send_pdu(ss
, SDP_PDU_SERVICE_ATTRIBUTE_REQUEST
,
271 req
, __arraycount(req
)))
274 len
= _sdp_recv_pdu(ss
, SDP_PDU_SERVICE_ATTRIBUTE_RESPONSE
);
279 end
= ss
->ibuf
+ len
;
282 * extract AttributeListByteCount
284 if (ptr
+ sizeof(uint16_t) > end
)
287 count
= be16dec(ptr
);
288 ptr
+= sizeof(uint16_t);
289 if (count
== 0 || ptr
+ count
> end
)
293 * extract AttributeList
295 if (rlen
+ count
> sdp_response_max())
298 rbuf
= realloc(ss
->rbuf
, rlen
+ count
);
303 memcpy(rbuf
+ rlen
, ptr
, count
);
308 * extract ContinuationState
312 || ptr
+ ptr
[0] + 1 != end
)
315 memcpy(ss
->cs
, ptr
, ptr
[0] + 1);
320 if (ss
->cs
[0] == 0) {
322 rsp
->end
= rbuf
+ rlen
;
323 if (sdp_data_size(rsp
) != (ssize_t
)rlen
324 || !sdp_data_valid(rsp
)
325 || !sdp_get_seq(rsp
, rsp
))
337 sdp_service_search_attribute(struct sdp_session
*ss
, const sdp_data_t
*ssp
,
338 const sdp_data_t
*ail
, sdp_data_t
*rsp
)
342 uint8_t sdata
[5], adata
[5], max
[2];
343 uint8_t *ptr
, *end
, *rbuf
;
348 * setup ServiceSearchPattern
350 len
= ssp
->end
- ssp
->next
;
351 if (len
< 0 || len
> UINT16_MAX
) {
357 hdr
.end
= sdata
+ sizeof(sdata
) + len
;
358 sdp_put_seq(&hdr
, len
);
359 req
[1].iov_base
= sdata
;
360 req
[1].iov_len
= hdr
.next
- sdata
;
362 req
[2].iov_base
= ssp
->next
;
363 req
[2].iov_len
= len
;
366 * setup MaximumAttributeByteCount
368 be16enc(max
, ss
->imtu
- sizeof(uint16_t) - sizeof(ss
->cs
));
369 req
[3].iov_base
= max
;
370 req
[3].iov_len
= sizeof(uint16_t);
373 * setup AttributeIDList
375 len
= (ail
== NULL
? (ssize_t
)sizeof(ail_default
) : (ail
->end
- ail
->next
));
376 if (len
< 0 || len
> UINT16_MAX
) {
382 hdr
.end
= adata
+ sizeof(adata
) + len
;
383 sdp_put_seq(&hdr
, len
);
384 req
[4].iov_base
= adata
;
385 req
[4].iov_len
= hdr
.next
- adata
;
387 req
[5].iov_base
= (ail
== NULL
? ail_default
: ail
->next
);
388 req
[5].iov_len
= len
;
391 * clear ContinuationState
396 * ServiceSearchAttribute Transaction
401 * setup ContinuationState
403 req
[6].iov_base
= ss
->cs
;
404 req
[6].iov_len
= ss
->cs
[0] + 1;
406 if (!_sdp_send_pdu(ss
, SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST
,
407 req
, __arraycount(req
)))
410 len
= _sdp_recv_pdu(ss
, SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_RESPONSE
);
415 end
= ss
->ibuf
+ len
;
418 * extract AttributeListsByteCount
420 if (ptr
+ sizeof(uint16_t) > end
)
423 count
= be16dec(ptr
);
424 ptr
+= sizeof(uint16_t);
425 if (count
== 0 || ptr
+ count
> end
)
429 * extract AttributeLists
431 if (rlen
+ count
> sdp_response_max())
434 rbuf
= realloc(ss
->rbuf
, rlen
+ count
);
439 memcpy(rbuf
+ rlen
, ptr
, count
);
444 * extract ContinuationState
448 || ptr
+ ptr
[0] + 1 != end
)
451 memcpy(ss
->cs
, ptr
, ptr
[0] + 1);
456 if (ss
->cs
[0] == 0) {
458 rsp
->end
= rbuf
+ rlen
;
459 if (sdp_data_size(rsp
) != (ssize_t
)rlen
460 || !sdp_data_valid(rsp
)
461 || !sdp_get_seq(rsp
, rsp
))