4 * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * $Id: search.c,v 1.2 2003/09/04 22:12:13 max Exp $
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #define L2CAP_SOCKET_CHECKED
36 #include <bluetooth.h>
48 uint32_t plen
, uint16_t const *pp
,
49 uint32_t alen
, uint32_t const *ap
,
50 uint32_t vlen
, sdp_attr_t
*vp
)
55 } __attribute__ ((packed
)) xpdu
;
57 sdp_session_p ss
= (sdp_session_p
) xss
;
58 uint8_t *req
= NULL
, *rsp
= NULL
, *rsp_tmp
= NULL
;
65 if (ss
->req
== NULL
|| ss
->rsp
== NULL
||
66 plen
== 0 || pp
== NULL
|| alen
== 0 || ap
== NULL
) {
73 /* Calculate ServiceSearchPattern length */
74 plen
= plen
* (sizeof(pp
[0]) + 1);
76 /* Calculate AttributeIDList length */
77 for (len
= 0, t
= 0; t
< alen
; t
++) {
78 lo
= (uint16_t) (ap
[t
] >> 16);
79 hi
= (uint16_t) (ap
[t
]);
87 len
+= (sizeof(ap
[t
]) + 1);
89 len
+= (sizeof(lo
) + 1);
93 /* Calculate length of the request */
94 len
= plen
+ sizeof(uint8_t) + sizeof(uint16_t) +
95 /* ServiceSearchPattern */
97 /* MaximumAttributeByteCount */
98 alen
+ sizeof(uint8_t) + sizeof(uint16_t);
101 if (ss
->req_e
- req
< len
) {
106 /* Put ServiceSearchPattern */
107 SDP_PUT8(SDP_DATA_SEQ16
, req
);
108 SDP_PUT16(plen
, req
);
109 for (; plen
> 0; pp
++, plen
-= (sizeof(pp
[0]) + 1)) {
110 SDP_PUT8(SDP_DATA_UUID16
, req
);
114 /* Put MaximumAttributeByteCount */
115 SDP_PUT16(0xffff, req
);
117 /* Put AttributeIDList */
118 SDP_PUT8(SDP_DATA_SEQ16
, req
);
119 SDP_PUT16(alen
, req
);
120 for (; alen
> 0; ap
++) {
121 lo
= (uint16_t) (*ap
>> 16);
122 hi
= (uint16_t) (*ap
);
125 /* Put attribute range */
126 SDP_PUT8(SDP_DATA_UINT32
, req
);
128 alen
-= (sizeof(ap
[0]) + 1);
131 SDP_PUT8(SDP_DATA_UINT16
, req
);
133 alen
-= (sizeof(lo
) + 1);
137 /* Submit ServiceSearchAttributeRequest and wait for response */
143 uint8_t *req_cs
= req
;
145 /* Add continuation state (if any) */
146 if (ss
->req_e
- req_cs
< ss
->cslen
+ 1) {
151 SDP_PUT8(ss
->cslen
, req_cs
);
153 memcpy(req_cs
, ss
->cs
, ss
->cslen
);
157 /* Prepare SDP PDU header */
158 xpdu
.pdu
.pid
= SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST
;
159 xpdu
.pdu
.tid
= htons(ss
->tid
);
160 xpdu
.pdu
.len
= htons(req_cs
- ss
->req
);
163 iov
[0].iov_base
= (void *) &xpdu
;
164 iov
[0].iov_len
= sizeof(xpdu
.pdu
);
165 iov
[1].iov_base
= (void *) ss
->req
;
166 iov
[1].iov_len
= req_cs
- ss
->req
;
169 len
= writev(ss
->s
, iov
, sizeof(iov
)/sizeof(iov
[0]));
170 } while (len
< 0 && errno
== EINTR
);
178 iov
[0].iov_base
= (void *) &xpdu
;
179 iov
[0].iov_len
= sizeof(xpdu
);
180 iov
[1].iov_base
= (void *) rsp
;
181 iov
[1].iov_len
= ss
->imtu
;
184 len
= readv(ss
->s
, iov
, sizeof(iov
)/sizeof(iov
[0]));
185 } while (len
< 0 && errno
== EINTR
);
191 if (len
< sizeof(xpdu
)) {
196 xpdu
.pdu
.tid
= ntohs(xpdu
.pdu
.tid
);
197 xpdu
.pdu
.len
= ntohs(xpdu
.pdu
.len
);
198 xpdu
.len
= ntohs(xpdu
.len
);
200 if (xpdu
.pdu
.pid
== SDP_PDU_ERROR_RESPONSE
||
201 xpdu
.pdu
.tid
!= ss
->tid
||
202 xpdu
.pdu
.len
> len
||
203 xpdu
.len
> xpdu
.pdu
.len
) {
211 /* Save continuation state (if any) */
214 if (ss
->cslen
> sizeof(ss
->cs
)) {
219 memcpy(ss
->cs
, rsp
+ 1, ss
->cslen
);
222 * Ensure that we always have ss->imtu bytes
223 * available in the ss->rsp buffer
226 if (ss
->rsp_e
- rsp
<= ss
->imtu
) {
227 uint32_t size
, offset
;
229 size
= ss
->rsp_e
- ss
->rsp
+ ss
->imtu
;
230 offset
= rsp
- ss
->rsp
;
232 rsp_tmp
= realloc(ss
->rsp
, size
);
233 if (rsp_tmp
== NULL
) {
239 ss
->rsp_e
= ss
->rsp
+ size
;
240 rsp
= ss
->rsp
+ offset
;
243 } while (ss
->cslen
> 0);
246 * If we got here then we have completed SDP transaction and now
247 * we must populate attribute values into vp array. At this point
248 * ss->rsp points to the beginning of the response and rsp points
249 * to the end of the response.
251 * From Bluetooth v1.1 spec page 364
253 * The AttributeLists is a data element sequence where each element
254 * in turn is a data element sequence representing an attribute list.
255 * Each attribute list contains attribute IDs and attribute values
256 * from one service record. The first element in each attribute list
257 * contains the attribute ID of the first attribute to be returned for
258 * that service record. The second element in each attribute list
259 * contains the corresponding attribute value. Successive pairs of
260 * elements in each attribute list contain additional attribute ID
261 * and value pairs. Only attributes that have non-null values within
262 * the service record and whose attribute IDs were specified in the
263 * SDP_ServiceSearchAttributeRequest are contained in the AttributeLists
264 * Neither an attribute ID nor attribute value is placed in
265 * AttributeLists for attributes in the service record that have no
266 * value. Within each attribute list, the attributes are listed in
267 * ascending order of attribute ID value.
275 /* Skip the first SEQ */
276 SDP_GET8(t
, rsp_tmp
);
279 SDP_GET8(len
, rsp_tmp
);
283 SDP_GET16(len
, rsp_tmp
);
287 SDP_GET32(len
, rsp_tmp
);
296 for (; rsp_tmp
< rsp
&& vlen
> 0; ) {
297 /* Get set of attributes for the next record */
298 SDP_GET8(t
, rsp_tmp
);
301 SDP_GET8(len
, rsp_tmp
);
305 SDP_GET16(len
, rsp_tmp
);
309 SDP_GET32(len
, rsp_tmp
);
318 /* Now rsp_tmp points to list of (attr,value) pairs */
319 for (; len
> 0 && vlen
> 0; vp
++, vlen
--) {
321 SDP_GET8(t
, rsp_tmp
);
322 if (t
!= SDP_DATA_UINT16
) {
326 SDP_GET16(vp
->attr
, rsp_tmp
);
328 /* Attribute value */
329 switch (rsp_tmp
[0]) {
337 alen
= sizeof(uint8_t);
340 case SDP_DATA_UINT16
:
342 case SDP_DATA_UUID16
:
343 alen
= sizeof(uint16_t);
346 case SDP_DATA_UINT32
:
348 case SDP_DATA_UUID32
:
349 alen
= sizeof(uint32_t);
352 case SDP_DATA_UINT64
:
354 alen
= sizeof(uint64_t);
357 case SDP_DATA_UINT128
:
358 case SDP_DATA_INT128
:
359 case SDP_DATA_UUID128
:
360 alen
= sizeof(uint128_t
);
367 alen
= rsp_tmp
[1] + sizeof(uint8_t);
374 alen
= ((uint16_t)rsp_tmp
[1] << 8)
375 | ((uint16_t)rsp_tmp
[2]);
376 alen
+= sizeof(uint16_t);
383 alen
= ((uint32_t)rsp_tmp
[1] << 24)
384 | ((uint32_t)rsp_tmp
[2] << 16)
385 | ((uint32_t)rsp_tmp
[3] << 8)
386 | ((uint32_t)rsp_tmp
[4]);
387 alen
+= sizeof(uint32_t);
396 alen
+= sizeof(uint8_t);
398 if (vp
->value
!= NULL
) {
399 if (alen
<= vp
->vlen
) {
400 vp
->flags
= SDP_ATTR_OK
;
403 vp
->flags
= SDP_ATTR_TRUNCATED
;
405 memcpy(vp
->value
, rsp_tmp
, vp
->vlen
);
407 vp
->flags
= SDP_ATTR_INVALID
;
410 sizeof(uint8_t) + sizeof(uint16_t) +