search.c revision 121472
1/*
2 * search.c
3 *
4 * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
15 *
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
26 * SUCH DAMAGE.
27 *
28 * $Id: search.c,v 1.2 2003/09/04 22:12:13 max Exp $
29 * $FreeBSD: head/lib/libsdp/search.c 121472 2003-10-24 18:26:30Z ume $
30 */
31
32#include <sys/types.h>
33#include <sys/uio.h>
34#include <netinet/in.h>
35#include <arpa/inet.h>
36#include <bluetooth.h>
37#include <errno.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <unistd.h>
42
43#include <sdp-int.h>
44#include <sdp.h>
45
46int32_t
47sdp_search(void *xss,
48		u_int32_t plen, u_int16_t const *pp,
49		u_int32_t alen, u_int32_t const *ap,
50		u_int32_t vlen, sdp_attr_t *vp)
51{
52	struct sdp_xpdu {
53		sdp_pdu_t	pdu;
54		u_int16_t	len;
55	} __attribute__ ((packed))	 xpdu;
56
57	sdp_session_p			 ss = (sdp_session_p) xss;
58	u_int8_t			*req = NULL, *rsp = NULL, *rsp_tmp = NULL;
59	int32_t				 type, len;
60
61	if (ss == NULL)
62		return (-1);
63
64	if (ss->req == NULL || ss->rsp == NULL ||
65	    plen == 0 || pp == NULL || alen == 0 || ap == NULL) {
66		ss->error = EINVAL;
67		return (-1);
68	}
69
70	/* Calculate length of the request */
71	req = ss->req;
72	plen = plen * (sizeof(pp[0]) + 1);
73	alen = alen * (sizeof(ap[0]) + 1);
74
75	len =	plen + sizeof(u_int8_t) + sizeof(u_int16_t) +
76			/* ServiceSearchPattern */
77		sizeof(u_int16_t) +
78			/* MaximumAttributeByteCount */
79		alen + sizeof(u_int8_t) + sizeof(u_int16_t);
80			/* AttributeIDList */
81
82	if (ss->req_e - req < len) {
83		ss->error = ENOBUFS;
84		return (-1);
85	}
86
87	/* Put ServiceSearchPattern */
88	SDP_PUT8(SDP_DATA_SEQ16, req);
89	SDP_PUT16(plen, req);
90	for (; plen > 0; pp ++, plen -= (sizeof(pp[0]) + 1)) {
91		SDP_PUT8(SDP_DATA_UUID16, req);
92		SDP_PUT16(*pp, req);
93	}
94
95	/* Put MaximumAttributeByteCount */
96	SDP_PUT16(0xffff, req);
97
98	/* Put AttributeIDList */
99	SDP_PUT8(SDP_DATA_SEQ16, req);
100	SDP_PUT16(alen, req);
101	for (; alen > 0; ap ++, alen -= (sizeof(ap[0]) + 1)) {
102		SDP_PUT8(SDP_DATA_UINT32, req);
103		SDP_PUT32(*ap, req);
104	}
105
106	/* Submit ServiceSearchAttributeRequest and wait for response */
107	ss->cslen = 0;
108	rsp = ss->rsp;
109
110	do {
111		struct iovec	 iov[2];
112		u_int8_t	*req_cs = req;
113
114		/* Add continuation state (if any) */
115		if (ss->req_e - req_cs < ss->cslen + 1) {
116			ss->error = ENOBUFS;
117			return (-1);
118		}
119
120		SDP_PUT8(ss->cslen, req_cs);
121		if (ss->cslen > 0) {
122			memcpy(req_cs, ss->cs, ss->cslen);
123			req_cs += ss->cslen;
124		}
125
126		/* Prepare SDP PDU header */
127		xpdu.pdu.pid = SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST;
128		xpdu.pdu.tid = htons(ss->tid);
129		xpdu.pdu.len = htons(req_cs - ss->req);
130
131		/* Submit request */
132		iov[0].iov_base = (void *) &xpdu;
133		iov[0].iov_len = sizeof(xpdu.pdu);
134		iov[1].iov_base = (void *) ss->req;
135		iov[1].iov_len = req_cs - ss->req;
136
137		len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
138		if (len < 0) {
139			ss->error = errno;
140			return (-1);
141		}
142
143		/* Read response */
144		iov[0].iov_base = (void *) &xpdu;
145		iov[0].iov_len = sizeof(xpdu);
146		iov[1].iov_base = (void *) rsp;
147		iov[1].iov_len = ss->imtu;
148
149		len = readv(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
150		if (len < 0) {
151			ss->error = errno;
152			return (-1);
153		}
154		if (len < sizeof(xpdu)) {
155			ss->error = ENOMSG;
156			return (-1);
157		}
158
159		xpdu.pdu.tid = ntohs(xpdu.pdu.tid);
160		xpdu.pdu.len = ntohs(xpdu.pdu.len);
161		xpdu.len = ntohs(xpdu.len);
162
163		if (xpdu.pdu.pid == SDP_PDU_ERROR_RESPONSE ||
164		    xpdu.pdu.tid != ss->tid ||
165		    xpdu.len > xpdu.pdu.len) {
166			ss->error = EIO;
167			return (-1);
168		}
169
170		/* Save continuation state (if any) */
171		ss->cslen = rsp[xpdu.len];
172		if (ss->cslen > 0) {
173			if (ss->cslen > sizeof(ss->cs)) {
174				ss->error = ENOBUFS;
175				return (-1);
176			}
177
178			memcpy(ss->cs, rsp + xpdu.len + 1, ss->cslen);
179
180			/*
181			 * Ensure that we always have ss->imtu bytes
182			 * available in the ss->rsp buffer
183			 */
184
185			if (ss->rsp_e - rsp <= ss->imtu) {
186				u_int32_t	 size, offset;
187
188				size = ss->rsp_e - ss->rsp + ss->imtu;
189				offset = rsp - ss->rsp;
190
191				rsp_tmp = realloc(ss->rsp, size);
192				if (rsp_tmp == NULL) {
193					ss->error = ENOMEM;
194					return (-1);
195				}
196
197				ss->rsp = rsp_tmp;
198				ss->rsp_e = ss->rsp + size;
199				rsp = ss->rsp + offset;
200			}
201		}
202
203		rsp += xpdu.len;
204		ss->tid ++;
205	} while (ss->cslen > 0);
206
207	/*
208	 * If we got here then we have completed SDP transaction and now
209	 * we must populate attribute values into vp array. At this point
210	 * ss->rsp points to the beginning of the response and rsp points
211	 * to the end of the response.
212	 *
213	 * From Bluetooth v1.1 spec page 364
214	 *
215	 * The AttributeLists is a data element sequence where each element
216	 * in turn is a data element sequence representing an attribute list.
217	 * Each attribute list contains attribute IDs and attribute values
218	 * from one service record. The first element in each attribute list
219	 * contains the attribute ID of the first attribute to be returned for
220	 * that service record. The second element in each attribute list
221	 * contains the corresponding attribute value. Successive pairs of
222	 * elements in each attribute list contain additional attribute ID
223	 * and value pairs. Only attributes that have non-null values within
224	 * the service record and whose attribute IDs were specified in the
225	 * SDP_ServiceSearchAttributeRequest are contained in the AttributeLists
226	 * Neither an attribute ID nor attribute value is placed in
227	 * AttributeLists for attributes in the service record that have no
228	 * value. Within each attribute list, the attributes are listed in
229	 * ascending order of attribute ID value.
230	 */
231
232	if (vp == NULL)
233		goto done;
234
235	rsp_tmp = ss->rsp;
236
237	/* Skip the first SEQ */
238	SDP_GET8(type, rsp_tmp);
239	switch (type) {
240	case SDP_DATA_SEQ8:
241		SDP_GET8(len, rsp_tmp);
242		break;
243
244	case SDP_DATA_SEQ16:
245		SDP_GET16(len, rsp_tmp);
246		break;
247
248	case SDP_DATA_SEQ32:
249		SDP_GET32(len, rsp_tmp);
250		break;
251
252	default:
253		ss->error = ENOATTR;
254		return (-1);
255		/* NOT REACHED */
256	}
257
258	for (; rsp_tmp < rsp && vlen > 0; ) {
259		/* Get set of attributes for the next record */
260		SDP_GET8(type, rsp_tmp);
261		switch (type) {
262		case SDP_DATA_SEQ8:
263			SDP_GET8(len, rsp_tmp);
264			break;
265
266		case SDP_DATA_SEQ16:
267			SDP_GET16(len, rsp_tmp);
268			break;
269
270		case SDP_DATA_SEQ32:
271			SDP_GET32(len, rsp_tmp);
272			break;
273
274		default:
275			ss->error = ENOATTR;
276			return (-1);
277			/* NOT REACHED */
278		}
279
280		/* Now rsp_tmp points to list of (attr,value) pairs */
281		for (; len > 0 && vlen > 0; vp ++, vlen --) {
282			/* Attribute */
283			SDP_GET8(type, rsp_tmp);
284			if (type != SDP_DATA_UINT16) {
285				ss->error = ENOATTR;
286				return (-1);
287			}
288			SDP_GET16(vp->attr, rsp_tmp);
289
290			/* Attribute value */
291			switch (rsp_tmp[0]) {
292			case SDP_DATA_NIL:
293				alen = 0;
294				break;
295
296			case SDP_DATA_UINT8:
297			case SDP_DATA_INT8:
298			case SDP_DATA_BOOL:
299				alen = sizeof(u_int8_t);
300				break;
301
302			case SDP_DATA_UINT16:
303			case SDP_DATA_INT16:
304			case SDP_DATA_UUID16:
305				alen = sizeof(u_int16_t);
306				break;
307
308			case SDP_DATA_UINT32:
309			case SDP_DATA_INT32:
310			case SDP_DATA_UUID32:
311				alen = sizeof(u_int32_t);
312				break;
313
314			case SDP_DATA_UINT64:
315			case SDP_DATA_INT64:
316				alen = sizeof(u_int64_t);
317				break;
318
319			case SDP_DATA_UINT128:
320			case SDP_DATA_INT128:
321			case SDP_DATA_UUID128:
322				alen = sizeof(u_int128_t);
323				break;
324
325			case SDP_DATA_STR8:
326			case SDP_DATA_URL8:
327			case SDP_DATA_SEQ8:
328			case SDP_DATA_ALT8:
329				alen = rsp_tmp[1] + sizeof(u_int8_t);
330				break;
331
332			case SDP_DATA_STR16:
333			case SDP_DATA_URL16:
334			case SDP_DATA_SEQ16:
335			case SDP_DATA_ALT16:
336				alen =	  ((u_int16_t)rsp_tmp[1] << 8)
337					| ((u_int16_t)rsp_tmp[2]);
338				alen += sizeof(u_int16_t);
339				break;
340
341			case SDP_DATA_STR32:
342			case SDP_DATA_URL32:
343			case SDP_DATA_SEQ32:
344			case SDP_DATA_ALT32:
345				alen =    ((u_int32_t)rsp_tmp[1] << 24)
346					| ((u_int32_t)rsp_tmp[2] << 16)
347					| ((u_int32_t)rsp_tmp[3] <<  8)
348					| ((u_int32_t)rsp_tmp[4]);
349				alen += sizeof(u_int32_t);
350				break;
351
352			default:
353				ss->error = ENOATTR;
354				return (-1);
355				/* NOT REACHED */
356			}
357
358			alen += sizeof(u_int8_t);
359
360			if (vp->value != NULL) {
361				if (alen <= vp->vlen) {
362					vp->flags = SDP_ATTR_OK;
363					vp->vlen = alen;
364				} else
365					vp->flags = SDP_ATTR_TRUNCATED;
366
367				memcpy(vp->value, rsp_tmp, vp->vlen);
368			} else
369				vp->flags = SDP_ATTR_INVALID;
370
371			len -=	(
372				sizeof(u_int8_t) + sizeof(u_int16_t) +
373				alen
374				);
375
376			rsp_tmp += alen;
377		}
378	}
379done:
380	ss->error = 0;
381
382	return (0);
383}
384
385