1 /* $NetBSD: search.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $ */
2 /* $DragonFly: src/lib/libsdp/search.c,v 1.1 2008/01/03 11:47:53 hasso Exp $ */
7 * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * $Id: search.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $
32 * $FreeBSD: src/lib/libsdp/search.c,v 1.7 2004/12/09 18:57:12 emax Exp $
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <bluetooth.h>
50 uint32_t plen
, uint16_t const *pp
,
51 uint32_t alen
, uint32_t const *ap
,
52 uint32_t vlen
, sdp_attr_t
*vp
)
57 } __attribute__ ((packed
)) xpdu
;
59 sdp_session_p ss
= (sdp_session_p
) xss
;
60 uint8_t *req
= NULL
, *rsp
= NULL
, *rsp_tmp
= NULL
;
67 if (ss
->req
== NULL
|| ss
->rsp
== NULL
||
68 plen
== 0 || pp
== NULL
|| alen
== 0 || ap
== NULL
) {
75 /* Calculate ServiceSearchPattern length */
76 plen
= plen
* (sizeof(pp
[0]) + 1);
78 /* Calculate AttributeIDList length */
79 for (len
= 0, t
= 0; t
< alen
; t
++) {
80 lo
= (uint16_t) (ap
[t
] >> 16);
81 hi
= (uint16_t) (ap
[t
]);
89 len
+= (sizeof(ap
[t
]) + 1);
91 len
+= (sizeof(lo
) + 1);
95 /* Calculate length of the request */
96 len
= plen
+ sizeof(uint8_t) + sizeof(uint16_t) +
97 /* ServiceSearchPattern */
99 /* MaximumAttributeByteCount */
100 alen
+ sizeof(uint8_t) + sizeof(uint16_t);
101 /* AttributeIDList */
103 if (ss
->req_e
- req
< len
) {
108 /* Put ServiceSearchPattern */
109 SDP_PUT8(SDP_DATA_SEQ16
, req
);
110 SDP_PUT16(plen
, req
);
111 for (; plen
> 0; pp
++, plen
-= (sizeof(pp
[0]) + 1)) {
112 SDP_PUT8(SDP_DATA_UUID16
, req
);
116 /* Put MaximumAttributeByteCount */
117 SDP_PUT16(0xffff, req
);
119 /* Put AttributeIDList */
120 SDP_PUT8(SDP_DATA_SEQ16
, req
);
121 SDP_PUT16(alen
, req
);
122 for (; alen
> 0; ap
++) {
123 lo
= (uint16_t) (*ap
>> 16);
124 hi
= (uint16_t) (*ap
);
127 /* Put attribute range */
128 SDP_PUT8(SDP_DATA_UINT32
, req
);
130 alen
-= (sizeof(ap
[0]) + 1);
133 SDP_PUT8(SDP_DATA_UINT16
, req
);
135 alen
-= (sizeof(lo
) + 1);
139 /* Submit ServiceSearchAttributeRequest and wait for response */
145 uint8_t *req_cs
= req
;
147 /* Add continuation state (if any) */
148 if (ss
->req_e
- req_cs
< ss
->cslen
+ 1) {
153 SDP_PUT8(ss
->cslen
, req_cs
);
155 memcpy(req_cs
, ss
->cs
, ss
->cslen
);
159 /* Prepare SDP PDU header */
160 xpdu
.pdu
.pid
= SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST
;
161 xpdu
.pdu
.tid
= htons(ss
->tid
);
162 xpdu
.pdu
.len
= htons(req_cs
- ss
->req
);
165 iov
[0].iov_base
= (void *) &xpdu
;
166 iov
[0].iov_len
= sizeof(xpdu
.pdu
);
167 iov
[1].iov_base
= (void *) ss
->req
;
168 iov
[1].iov_len
= req_cs
- ss
->req
;
171 len
= writev(ss
->s
, iov
, sizeof(iov
)/sizeof(iov
[0]));
172 } while (len
< 0 && errno
== EINTR
);
180 iov
[0].iov_base
= (void *) &xpdu
;
181 iov
[0].iov_len
= sizeof(xpdu
);
182 iov
[1].iov_base
= (void *) rsp
;
183 iov
[1].iov_len
= ss
->imtu
;
186 len
= readv(ss
->s
, iov
, sizeof(iov
)/sizeof(iov
[0]));
187 } while (len
< 0 && errno
== EINTR
);
193 if (len
< sizeof(xpdu
)) {
198 xpdu
.pdu
.tid
= ntohs(xpdu
.pdu
.tid
);
199 xpdu
.pdu
.len
= ntohs(xpdu
.pdu
.len
);
200 xpdu
.len
= ntohs(xpdu
.len
);
202 if (xpdu
.pdu
.pid
== SDP_PDU_ERROR_RESPONSE
||
203 xpdu
.pdu
.tid
!= ss
->tid
||
204 xpdu
.pdu
.len
> len
||
205 xpdu
.len
> xpdu
.pdu
.len
) {
210 /* Save continuation state (if any) */
211 ss
->cslen
= rsp
[xpdu
.len
];
213 if (ss
->cslen
> sizeof(ss
->cs
)) {
218 memcpy(ss
->cs
, rsp
+ xpdu
.len
+ 1, ss
->cslen
);
221 * Ensure that we always have ss->imtu bytes
222 * available in the ss->rsp buffer
225 if (ss
->rsp_e
- rsp
<= ss
->imtu
) {
226 uint32_t size
, offset
;
228 size
= ss
->rsp_e
- ss
->rsp
+ ss
->imtu
;
229 offset
= rsp
- ss
->rsp
;
231 rsp_tmp
= realloc(ss
->rsp
, size
);
232 if (rsp_tmp
== NULL
) {
238 ss
->rsp_e
= ss
->rsp
+ size
;
239 rsp
= ss
->rsp
+ offset
;
245 } while (ss
->cslen
> 0);
248 * If we got here then we have completed SDP transaction and now
249 * we must populate attribute values into vp array. At this point
250 * ss->rsp points to the beginning of the response and rsp points
251 * to the end of the response.
253 * From Bluetooth v1.1 spec page 364
255 * The AttributeLists is a data element sequence where each element
256 * in turn is a data element sequence representing an attribute list.
257 * Each attribute list contains attribute IDs and attribute values
258 * from one service record. The first element in each attribute list
259 * contains the attribute ID of the first attribute to be returned for
260 * that service record. The second element in each attribute list
261 * contains the corresponding attribute value. Successive pairs of
262 * elements in each attribute list contain additional attribute ID
263 * and value pairs. Only attributes that have non-null values within
264 * the service record and whose attribute IDs were specified in the
265 * SDP_ServiceSearchAttributeRequest are contained in the AttributeLists
266 * Neither an attribute ID nor attribute value is placed in
267 * AttributeLists for attributes in the service record that have no
268 * value. Within each attribute list, the attributes are listed in
269 * ascending order of attribute ID value.
277 /* Skip the first SEQ */
278 SDP_GET8(t
, rsp_tmp
);
281 SDP_GET8(len
, rsp_tmp
);
285 SDP_GET16(len
, rsp_tmp
);
289 SDP_GET32(len
, rsp_tmp
);
298 for (; rsp_tmp
< rsp
&& vlen
> 0; ) {
299 /* Get set of attributes for the next record */
300 SDP_GET8(t
, rsp_tmp
);
303 SDP_GET8(len
, rsp_tmp
);
307 SDP_GET16(len
, rsp_tmp
);
311 SDP_GET32(len
, rsp_tmp
);
320 /* Now rsp_tmp points to list of (attr,value) pairs */
321 for (; len
> 0 && vlen
> 0; vp
++, vlen
--) {
323 SDP_GET8(t
, rsp_tmp
);
324 if (t
!= SDP_DATA_UINT16
) {
328 SDP_GET16(vp
->attr
, rsp_tmp
);
330 /* Attribute value */
331 switch (rsp_tmp
[0]) {
339 alen
= sizeof(uint8_t);
342 case SDP_DATA_UINT16
:
344 case SDP_DATA_UUID16
:
345 alen
= sizeof(uint16_t);
348 case SDP_DATA_UINT32
:
350 case SDP_DATA_UUID32
:
351 alen
= sizeof(uint32_t);
354 case SDP_DATA_UINT64
:
356 alen
= sizeof(uint64_t);
359 case SDP_DATA_UINT128
:
360 case SDP_DATA_INT128
:
361 case SDP_DATA_UUID128
:
362 alen
= sizeof(uint128_t
);
369 alen
= rsp_tmp
[1] + sizeof(uint8_t);
376 alen
= ((uint16_t)rsp_tmp
[1] << 8)
377 | ((uint16_t)rsp_tmp
[2]);
378 alen
+= sizeof(uint16_t);
385 alen
= ((uint32_t)rsp_tmp
[1] << 24)
386 | ((uint32_t)rsp_tmp
[2] << 16)
387 | ((uint32_t)rsp_tmp
[3] << 8)
388 | ((uint32_t)rsp_tmp
[4]);
389 alen
+= sizeof(uint32_t);
398 alen
+= sizeof(uint8_t);
400 if (vp
->value
!= NULL
) {
401 if (alen
<= vp
->vlen
) {
402 vp
->flags
= SDP_ATTR_OK
;
405 vp
->flags
= SDP_ATTR_TRUNCATED
;
407 memcpy(vp
->value
, rsp_tmp
, vp
->vlen
);
409 vp
->flags
= SDP_ATTR_INVALID
;
412 sizeof(uint8_t) + sizeof(uint16_t) +