1 /* $NetBSD: ssr.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
2 /* $DragonFly: src/usr.sbin/sdpd/ssr.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
7 * Copyright (c) 2004 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: ssr.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
32 * $FreeBSD: src/usr.sbin/bluetooth/sdpd/ssr.c,v 1.3 2005/01/05 18:37:37 emax Exp $
35 #include <sys/queue.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
40 #include <bluetooth.h>
47 #include "uuid-private.h"
50 * Extract ServiceSearchPattern from request to uuid array
51 * return count or 0 if error
54 server_get_service_search_pattern(uint8_t const **buf
, uint8_t const *end
, uint128_t
*uuid
)
56 uint8_t const *req
= *buf
;
57 uint32_t type
, ssplen
;
71 SDP_GET8(ssplen
, req
);
78 SDP_GET16(ssplen
, req
);
85 SDP_GET32(ssplen
, req
);
92 if (req
+ ssplen
> end
)
104 case SDP_DATA_UUID16
:
108 memcpy(uuid
, &uuid_base
, sizeof(*uuid
));
114 case SDP_DATA_UUID32
:
118 memcpy(uuid
, &uuid_base
, sizeof(*uuid
));
126 case SDP_DATA_UUID128
:
130 memcpy(uuid
, req
, 16);
148 * Prepare SDP Service Search Response
152 server_prepare_service_search_response(server_p srv
, int32_t fd
)
154 uint8_t const *req
= srv
->req
+ sizeof(sdp_pdu_t
);
155 uint8_t const *req_end
= req
+ ((sdp_pdu_p
)(srv
->req
))->len
;
156 uint8_t *rsp
= srv
->fdidx
[fd
].rsp
;
157 uint8_t const *rsp_end
= rsp
+ L2CAP_MTU_MAXIMUM
;
159 provider_t
*provider
= NULL
;
160 int32_t ucount
, rsp_limit
, cslen
, cs
;
164 * Minimal SDP Service Search Request
166 * seq8 len8 - 2 bytes
167 * uuid16 value16 - 3 bytes ServiceSearchPattern
168 * value16 - 2 bytes MaximumServiceRecordCount
169 * value8 - 1 byte ContinuationState
172 /* Get ServiceSearchPattern into uuid array */
173 ucount
= server_get_service_search_pattern(&req
, req_end
, ulist
);
174 if (ucount
< 1 || ucount
> 12)
175 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX
);
177 /* Get MaximumServiceRecordCount */
178 if (req
+ 2 > req_end
)
179 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX
);
181 SDP_GET16(rsp_limit
, req
);
183 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX
);
185 /* Get ContinuationState */
186 if (req
+ 1 > req_end
)
187 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX
);
189 SDP_GET8(cslen
, req
);
190 if (cslen
== 2 && req
+ 2 == req_end
)
192 else if (cslen
== 0 && req
== req_end
)
195 return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE
);
197 /* Process the request. First, check continuation state */
198 if (srv
->fdidx
[fd
].rsp_cs
!= cs
)
199 return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE
);
200 if (srv
->fdidx
[fd
].rsp_size
> 0)
204 * Service Search Response format
206 * value16 - 2 bytes TotalServiceRecordCount (not incl.)
207 * value16 - 2 bytes CurrentServiceRecordCount (not incl.)
208 * value32 - 4 bytes handle
212 /* Look for the record handles and add to the rsp buffer */
213 for (provider
= provider_get_first();
215 provider
= provider_get_next(provider
)) {
216 if (!provider_match_bdaddr(provider
, &srv
->req_sa
.bt_bdaddr
))
219 if (!provider_match_uuid(provider
, ulist
, ucount
))
222 if (rsp
+ 4 > rsp_end
)
225 SDP_PUT32(provider
->handle
, rsp
);
228 /* Set reply size (not counting PDU header and continuation state) */
229 srv
->fdidx
[fd
].rsp_limit
= srv
->fdidx
[fd
].omtu
- sizeof(sdp_pdu_t
) - 4;
230 srv
->fdidx
[fd
].rsp_size
= rsp
- srv
->fdidx
[fd
].rsp
;
231 srv
->fdidx
[fd
].rsp_cs
= 0;
237 * Send SDP Service Search Response
241 server_send_service_search_response(server_p srv
, int32_t fd
)
243 uint8_t *rsp
= srv
->fdidx
[fd
].rsp
+ srv
->fdidx
[fd
].rsp_cs
;
244 uint8_t *rsp_end
= srv
->fdidx
[fd
].rsp
+ srv
->fdidx
[fd
].rsp_size
;
252 /* First update continuation state (assume we will send all data) */
253 size
= rsp_end
- rsp
;
254 srv
->fdidx
[fd
].rsp_cs
+= size
;
256 if (size
+ 1 > srv
->fdidx
[fd
].rsp_limit
) {
258 * We need to split out response. Add 3 more bytes for the
259 * continuation state and move rsp_end and rsp_cs backwards.
262 while ((rsp_end
- rsp
) + 3 > srv
->fdidx
[fd
].rsp_limit
) {
264 srv
->fdidx
[fd
].rsp_cs
-= 4;
268 cs
[1] = srv
->fdidx
[fd
].rsp_cs
>> 8;
269 cs
[2] = srv
->fdidx
[fd
].rsp_cs
& 0xff;
273 assert(rsp_end
>= rsp
);
275 rcounts
[0] = srv
->fdidx
[fd
].rsp_size
/ 4; /* TotalServiceRecordCount */
276 rcounts
[1] = (rsp_end
- rsp
) / 4; /* CurrentServiceRecordCount */
278 pdu
.pid
= SDP_PDU_SERVICE_SEARCH_RESPONSE
;
279 pdu
.tid
= ((sdp_pdu_p
)(srv
->req
))->tid
;
280 pdu
.len
= htons(sizeof(rcounts
) + rcounts
[1] * 4 + 1 + cs
[0]);
282 rcounts
[0] = htons(rcounts
[0]);
283 rcounts
[1] = htons(rcounts
[1]);
285 iov
[0].iov_base
= &pdu
;
286 iov
[0].iov_len
= sizeof(pdu
);
288 iov
[1].iov_base
= rcounts
;
289 iov
[1].iov_len
= sizeof(rcounts
);
291 iov
[2].iov_base
= rsp
;
292 iov
[2].iov_len
= rsp_end
- rsp
;
294 iov
[3].iov_base
= cs
;
295 iov
[3].iov_len
= 1 + cs
[0];
298 size
= writev(fd
, (struct iovec
const *) &iov
, sizeof(iov
)/sizeof(iov
[0]));
299 } while (size
< 0 && errno
== EINTR
);
301 /* Check if we have sent (or failed to sent) last response chunk */
302 if (srv
->fdidx
[fd
].rsp_cs
== srv
->fdidx
[fd
].rsp_size
) {
303 srv
->fdidx
[fd
].rsp_cs
= 0;
304 srv
->fdidx
[fd
].rsp_size
= 0;
305 srv
->fdidx
[fd
].rsp_limit
= 0;
308 return ((size
< 0)? errno
: 0);