1 /* $NetBSD: search.c,v 1.2 2007/11/16 19:35:08 plunky Exp $ */
6 * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * $Id: search.c,v 1.3 2007/12/15 16:03:29 perry Exp $
31 * $FreeBSD: src/lib/libsdp/search.c,v 1.8 2007/11/16 15:13:12 emax Exp $
34 #include <sys/cdefs.h>
35 __RCSID("$NetBSD: search.c,v 1.2 2007/11/16 19:35:08 plunky Exp $");
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40 #include <bluetooth.h>
52 uint32_t plen
, uint16_t const *pp
,
53 uint32_t alen
, uint32_t const *ap
,
54 uint32_t vlen
, sdp_attr_t
*vp
)
61 sdp_session_p ss
= (sdp_session_p
) xss
;
62 uint8_t *req
= NULL
, *rsp
= NULL
, *rsp_tmp
= NULL
;
69 if (ss
->req
== NULL
|| ss
->rsp
== NULL
||
70 plen
== 0 || pp
== NULL
|| alen
== 0 || ap
== NULL
) {
77 /* Calculate ServiceSearchPattern length */
78 plen
= plen
* (sizeof(pp
[0]) + 1);
80 /* Calculate AttributeIDList length */
81 for (len
= 0, t
= 0; t
< alen
; t
++) {
82 lo
= (uint16_t) (ap
[t
] >> 16);
83 hi
= (uint16_t) (ap
[t
]);
91 len
+= (sizeof(ap
[t
]) + 1);
93 len
+= (sizeof(lo
) + 1);
97 /* Calculate length of the request */
98 len
= plen
+ sizeof(uint8_t) + sizeof(uint16_t) +
99 /* ServiceSearchPattern */
101 /* MaximumAttributeByteCount */
102 alen
+ sizeof(uint8_t) + sizeof(uint16_t);
103 /* AttributeIDList */
105 if (ss
->req_e
- req
< len
) {
110 /* Put ServiceSearchPattern */
111 SDP_PUT8(SDP_DATA_SEQ16
, req
);
112 SDP_PUT16(plen
, req
);
113 for (; plen
> 0; pp
++, plen
-= (sizeof(pp
[0]) + 1)) {
114 SDP_PUT8(SDP_DATA_UUID16
, req
);
118 /* Put MaximumAttributeByteCount */
119 SDP_PUT16(0xffff, req
);
121 /* Put AttributeIDList */
122 SDP_PUT8(SDP_DATA_SEQ16
, req
);
123 SDP_PUT16(alen
, req
);
124 for (; alen
> 0; ap
++) {
125 lo
= (uint16_t) (*ap
>> 16);
126 hi
= (uint16_t) (*ap
);
129 /* Put attribute range */
130 SDP_PUT8(SDP_DATA_UINT32
, req
);
132 alen
-= (sizeof(ap
[0]) + 1);
135 SDP_PUT8(SDP_DATA_UINT16
, req
);
137 alen
-= (sizeof(lo
) + 1);
141 /* Submit ServiceSearchAttributeRequest and wait for response */
147 uint8_t *req_cs
= req
;
149 /* Add continuation state (if any) */
150 if (ss
->req_e
- req_cs
< ss
->cslen
+ 1) {
155 SDP_PUT8(ss
->cslen
, req_cs
);
157 memcpy(req_cs
, ss
->cs
, ss
->cslen
);
161 /* Prepare SDP PDU header */
162 xpdu
.pdu
.pid
= SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST
;
163 xpdu
.pdu
.tid
= htons(ss
->tid
);
164 xpdu
.pdu
.len
= htons(req_cs
- ss
->req
);
167 iov
[0].iov_base
= (void *) &xpdu
;
168 iov
[0].iov_len
= sizeof(xpdu
.pdu
);
169 iov
[1].iov_base
= (void *) ss
->req
;
170 iov
[1].iov_len
= req_cs
- ss
->req
;
173 len
= writev(ss
->s
, iov
, sizeof(iov
)/sizeof(iov
[0]));
174 } while (len
< 0 && errno
== EINTR
);
182 iov
[0].iov_base
= (void *) &xpdu
;
183 iov
[0].iov_len
= sizeof(xpdu
);
184 iov
[1].iov_base
= (void *) rsp
;
185 iov
[1].iov_len
= ss
->imtu
;
188 len
= readv(ss
->s
, iov
, sizeof(iov
)/sizeof(iov
[0]));
189 } while (len
< 0 && errno
== EINTR
);
195 if (len
< sizeof(xpdu
)) {
200 xpdu
.pdu
.tid
= ntohs(xpdu
.pdu
.tid
);
201 xpdu
.pdu
.len
= ntohs(xpdu
.pdu
.len
);
202 xpdu
.len
= ntohs(xpdu
.len
);
204 if (xpdu
.pdu
.pid
== SDP_PDU_ERROR_RESPONSE
||
205 xpdu
.pdu
.tid
!= ss
->tid
||
206 xpdu
.pdu
.len
> len
||
207 xpdu
.len
> xpdu
.pdu
.len
) {
215 /* Save continuation state (if any) */
218 if (ss
->cslen
> sizeof(ss
->cs
)) {
223 memcpy(ss
->cs
, rsp
+ 1, ss
->cslen
);
226 * Ensure that we always have ss->imtu bytes
227 * available in the ss->rsp buffer
230 if (ss
->rsp_e
- rsp
<= ss
->imtu
) {
231 uint32_t size
, offset
;
233 size
= ss
->rsp_e
- ss
->rsp
+ ss
->imtu
;
234 offset
= rsp
- ss
->rsp
;
236 rsp_tmp
= realloc(ss
->rsp
, size
);
237 if (rsp_tmp
== NULL
) {
243 ss
->rsp_e
= ss
->rsp
+ size
;
244 rsp
= ss
->rsp
+ offset
;
247 } while (ss
->cslen
> 0);
250 * If we got here then we have completed SDP transaction and now
251 * we must populate attribute values into vp array. At this point
252 * ss->rsp points to the beginning of the response and rsp points
253 * to the end of the response.
255 * From Bluetooth v1.1 spec page 364
257 * The AttributeLists is a data element sequence where each element
258 * in turn is a data element sequence representing an attribute list.
259 * Each attribute list contains attribute IDs and attribute values
260 * from one service record. The first element in each attribute list
261 * contains the attribute ID of the first attribute to be returned for
262 * that service record. The second element in each attribute list
263 * contains the corresponding attribute value. Successive pairs of
264 * elements in each attribute list contain additional attribute ID
265 * and value pairs. Only attributes that have non-null values within
266 * the service record and whose attribute IDs were specified in the
267 * SDP_ServiceSearchAttributeRequest are contained in the AttributeLists
268 * Neither an attribute ID nor attribute value is placed in
269 * AttributeLists for attributes in the service record that have no
270 * value. Within each attribute list, the attributes are listed in
271 * ascending order of attribute ID value.
279 /* Skip the first SEQ */
280 SDP_GET8(t
, rsp_tmp
);
283 SDP_GET8(len
, rsp_tmp
);
287 SDP_GET16(len
, rsp_tmp
);
291 SDP_GET32(len
, rsp_tmp
);
300 for (; rsp_tmp
< rsp
&& vlen
> 0; ) {
301 /* Get set of attributes for the next record */
302 SDP_GET8(t
, rsp_tmp
);
305 SDP_GET8(len
, rsp_tmp
);
309 SDP_GET16(len
, rsp_tmp
);
313 SDP_GET32(len
, rsp_tmp
);
322 /* Now rsp_tmp points to list of (attr,value) pairs */
323 for (; len
> 0 && vlen
> 0; vp
++, vlen
--) {
325 SDP_GET8(t
, rsp_tmp
);
326 if (t
!= SDP_DATA_UINT16
) {
330 SDP_GET16(vp
->attr
, rsp_tmp
);
332 /* Attribute value */
333 switch (rsp_tmp
[0]) {
341 alen
= sizeof(uint8_t);
344 case SDP_DATA_UINT16
:
346 case SDP_DATA_UUID16
:
347 alen
= sizeof(uint16_t);
350 case SDP_DATA_UINT32
:
352 case SDP_DATA_UUID32
:
353 alen
= sizeof(uint32_t);
356 case SDP_DATA_UINT64
:
358 alen
= sizeof(uint64_t);
361 case SDP_DATA_UINT128
:
362 case SDP_DATA_INT128
:
363 case SDP_DATA_UUID128
:
364 alen
= sizeof(uint128_t
);
371 alen
= rsp_tmp
[1] + sizeof(uint8_t);
378 alen
= ((uint16_t)rsp_tmp
[1] << 8)
379 | ((uint16_t)rsp_tmp
[2]);
380 alen
+= sizeof(uint16_t);
387 alen
= ((uint32_t)rsp_tmp
[1] << 24)
388 | ((uint32_t)rsp_tmp
[2] << 16)
389 | ((uint32_t)rsp_tmp
[3] << 8)
390 | ((uint32_t)rsp_tmp
[4]);
391 alen
+= sizeof(uint32_t);
400 alen
+= sizeof(uint8_t);
402 if (vp
->value
!= NULL
) {
403 if (alen
<= vp
->vlen
) {
404 vp
->flags
= SDP_ATTR_OK
;
407 vp
->flags
= SDP_ATTR_TRUNCATED
;
409 memcpy(vp
->value
, rsp_tmp
, vp
->vlen
);
411 vp
->flags
= SDP_ATTR_INVALID
;
414 sizeof(uint8_t) + sizeof(uint16_t) +