search.c revision 121054
1121054Semax/*
2121054Semax * search.c
3121054Semax *
4121054Semax * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5121054Semax * All rights reserved.
6121054Semax *
7121054Semax * Redistribution and use in source and binary forms, with or without
8121054Semax * modification, are permitted provided that the following conditions
9121054Semax * are met:
10121054Semax * 1. Redistributions of source code must retain the above copyright
11121054Semax *    notice, this list of conditions and the following disclaimer.
12121054Semax * 2. Redistributions in binary form must reproduce the above copyright
13121054Semax *    notice, this list of conditions and the following disclaimer in the
14121054Semax *    documentation and/or other materials provided with the distribution.
15121054Semax *
16121054Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17121054Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18121054Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19121054Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20121054Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21121054Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22121054Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23121054Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24121054Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25121054Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26121054Semax * SUCH DAMAGE.
27121054Semax *
28121054Semax * $Id: search.c,v 1.2 2003/09/04 22:12:13 max Exp $
29121054Semax * $FreeBSD: head/lib/libsdp/search.c 121054 2003-10-12 22:04:24Z emax $
30121054Semax */
31121054Semax
32121054Semax#include <sys/uio.h>
33121054Semax#include <netinet/in.h>
34121054Semax#include <arpa/inet.h>
35121054Semax#include <bluetooth.h>
36121054Semax#include <errno.h>
37121054Semax#include <stdio.h>
38121054Semax#include <stdlib.h>
39121054Semax#include <string.h>
40121054Semax#include <unistd.h>
41121054Semax
42121054Semax#include <sdp-int.h>
43121054Semax#include <sdp.h>
44121054Semax
45121054Semaxint32_t
46121054Semaxsdp_search(void *xss,
47121054Semax		u_int32_t plen, u_int16_t const *pp,
48121054Semax		u_int32_t alen, u_int32_t const *ap,
49121054Semax		u_int32_t vlen, sdp_attr_t *vp)
50121054Semax{
51121054Semax	struct sdp_xpdu {
52121054Semax		sdp_pdu_t	pdu;
53121054Semax		u_int16_t	len;
54121054Semax	} __attribute__ ((packed))	 xpdu;
55121054Semax
56121054Semax	sdp_session_p			 ss = (sdp_session_p) xss;
57121054Semax	u_int8_t			*req = NULL, *rsp = NULL, *rsp_tmp = NULL;
58121054Semax	int32_t				 type, len;
59121054Semax
60121054Semax	if (ss == NULL)
61121054Semax		return (-1);
62121054Semax
63121054Semax	if (ss->req == NULL || ss->rsp == NULL ||
64121054Semax	    plen == 0 || pp == NULL || alen == 0 || ap == NULL) {
65121054Semax		ss->error = EINVAL;
66121054Semax		return (-1);
67121054Semax	}
68121054Semax
69121054Semax	/* Calculate length of the request */
70121054Semax	req = ss->req;
71121054Semax	plen = plen * (sizeof(pp[0]) + 1);
72121054Semax	alen = alen * (sizeof(ap[0]) + 1);
73121054Semax
74121054Semax	len =	plen + sizeof(u_int8_t) + sizeof(u_int16_t) +
75121054Semax			/* ServiceSearchPattern */
76121054Semax		sizeof(u_int16_t) +
77121054Semax			/* MaximumAttributeByteCount */
78121054Semax		alen + sizeof(u_int8_t) + sizeof(u_int16_t);
79121054Semax			/* AttributeIDList */
80121054Semax
81121054Semax	if (ss->req_e - req < len) {
82121054Semax		ss->error = ENOBUFS;
83121054Semax		return (-1);
84121054Semax	}
85121054Semax
86121054Semax	/* Put ServiceSearchPattern */
87121054Semax	SDP_PUT8(SDP_DATA_SEQ16, req);
88121054Semax	SDP_PUT16(plen, req);
89121054Semax	for (; plen > 0; pp ++, plen -= (sizeof(pp[0]) + 1)) {
90121054Semax		SDP_PUT8(SDP_DATA_UUID16, req);
91121054Semax		SDP_PUT16(*pp, req);
92121054Semax	}
93121054Semax
94121054Semax	/* Put MaximumAttributeByteCount */
95121054Semax	SDP_PUT16(0xffff, req);
96121054Semax
97121054Semax	/* Put AttributeIDList */
98121054Semax	SDP_PUT8(SDP_DATA_SEQ16, req);
99121054Semax	SDP_PUT16(alen, req);
100121054Semax	for (; alen > 0; ap ++, alen -= (sizeof(ap[0]) + 1)) {
101121054Semax		SDP_PUT8(SDP_DATA_UINT32, req);
102121054Semax		SDP_PUT32(*ap, req);
103121054Semax	}
104121054Semax
105121054Semax	/* Submit ServiceSearchAttributeRequest and wait for response */
106121054Semax	ss->cslen = 0;
107121054Semax	rsp = ss->rsp;
108121054Semax
109121054Semax	do {
110121054Semax		struct iovec	 iov[2];
111121054Semax		u_int8_t	*req_cs = req;
112121054Semax
113121054Semax		/* Add continuation state (if any) */
114121054Semax		if (ss->req_e - req_cs < ss->cslen + 1) {
115121054Semax			ss->error = ENOBUFS;
116121054Semax			return (-1);
117121054Semax		}
118121054Semax
119121054Semax		SDP_PUT8(ss->cslen, req_cs);
120121054Semax		if (ss->cslen > 0) {
121121054Semax			memcpy(req_cs, ss->cs, ss->cslen);
122121054Semax			req_cs += ss->cslen;
123121054Semax		}
124121054Semax
125121054Semax		/* Prepare SDP PDU header */
126121054Semax		xpdu.pdu.pid = SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST;
127121054Semax		xpdu.pdu.tid = htons(ss->tid);
128121054Semax		xpdu.pdu.len = htons(req_cs - ss->req);
129121054Semax
130121054Semax		/* Submit request */
131121054Semax		iov[0].iov_base = (void *) &xpdu;
132121054Semax		iov[0].iov_len = sizeof(xpdu.pdu);
133121054Semax		iov[1].iov_base = (void *) ss->req;
134121054Semax		iov[1].iov_len = req_cs - ss->req;
135121054Semax
136121054Semax		len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
137121054Semax		if (len < 0) {
138121054Semax			ss->error = errno;
139121054Semax			return (-1);
140121054Semax		}
141121054Semax
142121054Semax		/* Read response */
143121054Semax		iov[0].iov_base = (void *) &xpdu;
144121054Semax		iov[0].iov_len = sizeof(xpdu);
145121054Semax		iov[1].iov_base = (void *) rsp;
146121054Semax		iov[1].iov_len = ss->imtu;
147121054Semax
148121054Semax		len = readv(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
149121054Semax		if (len < 0) {
150121054Semax			ss->error = errno;
151121054Semax			return (-1);
152121054Semax		}
153121054Semax		if (len < sizeof(xpdu)) {
154121054Semax			ss->error = ENOMSG;
155121054Semax			return (-1);
156121054Semax		}
157121054Semax
158121054Semax		xpdu.pdu.tid = ntohs(xpdu.pdu.tid);
159121054Semax		xpdu.pdu.len = ntohs(xpdu.pdu.len);
160121054Semax		xpdu.len = ntohs(xpdu.len);
161121054Semax
162121054Semax		if (xpdu.pdu.pid == SDP_PDU_ERROR_RESPONSE ||
163121054Semax		    xpdu.pdu.tid != ss->tid ||
164121054Semax		    xpdu.len > xpdu.pdu.len) {
165121054Semax			ss->error = EIO;
166121054Semax			return (-1);
167121054Semax		}
168121054Semax
169121054Semax		/* Save continuation state (if any) */
170121054Semax		ss->cslen = rsp[xpdu.len];
171121054Semax		if (ss->cslen > 0) {
172121054Semax			if (ss->cslen > sizeof(ss->cs)) {
173121054Semax				ss->error = ENOBUFS;
174121054Semax				return (-1);
175121054Semax			}
176121054Semax
177121054Semax			memcpy(ss->cs, rsp + xpdu.len + 1, ss->cslen);
178121054Semax
179121054Semax			/*
180121054Semax			 * Ensure that we always have ss->imtu bytes
181121054Semax			 * available in the ss->rsp buffer
182121054Semax			 */
183121054Semax
184121054Semax			if (ss->rsp_e - rsp <= ss->imtu) {
185121054Semax				u_int32_t	 size, offset;
186121054Semax
187121054Semax				size = ss->rsp_e - ss->rsp + ss->imtu;
188121054Semax				offset = rsp - ss->rsp;
189121054Semax
190121054Semax				rsp_tmp = realloc(ss->rsp, size);
191121054Semax				if (rsp_tmp == NULL) {
192121054Semax					ss->error = ENOMEM;
193121054Semax					return (-1);
194121054Semax				}
195121054Semax
196121054Semax				ss->rsp = rsp_tmp;
197121054Semax				ss->rsp_e = ss->rsp + size;
198121054Semax				rsp = ss->rsp + offset;
199121054Semax			}
200121054Semax		}
201121054Semax
202121054Semax		rsp += xpdu.len;
203121054Semax		ss->tid ++;
204121054Semax	} while (ss->cslen > 0);
205121054Semax
206121054Semax	/*
207121054Semax	 * If we got here then we have completed SDP transaction and now
208121054Semax	 * we must populate attribute values into vp array. At this point
209121054Semax	 * ss->rsp points to the beginning of the response and rsp points
210121054Semax	 * to the end of the response.
211121054Semax	 *
212121054Semax	 * From Bluetooth v1.1 spec page 364
213121054Semax	 *
214121054Semax	 * The AttributeLists is a data element sequence where each element
215121054Semax	 * in turn is a data element sequence representing an attribute list.
216121054Semax	 * Each attribute list contains attribute IDs and attribute values
217121054Semax	 * from one service record. The first element in each attribute list
218121054Semax	 * contains the attribute ID of the first attribute to be returned for
219121054Semax	 * that service record. The second element in each attribute list
220121054Semax	 * contains the corresponding attribute value. Successive pairs of
221121054Semax	 * elements in each attribute list contain additional attribute ID
222121054Semax	 * and value pairs. Only attributes that have non-null values within
223121054Semax	 * the service record and whose attribute IDs were specified in the
224121054Semax	 * SDP_ServiceSearchAttributeRequest are contained in the AttributeLists
225121054Semax	 * Neither an attribute ID nor attribute value is placed in
226121054Semax	 * AttributeLists for attributes in the service record that have no
227121054Semax	 * value. Within each attribute list, the attributes are listed in
228121054Semax	 * ascending order of attribute ID value.
229121054Semax	 */
230121054Semax
231121054Semax	if (vp == NULL)
232121054Semax		goto done;
233121054Semax
234121054Semax	rsp_tmp = ss->rsp;
235121054Semax
236121054Semax	/* Skip the first SEQ */
237121054Semax	SDP_GET8(type, rsp_tmp);
238121054Semax	switch (type) {
239121054Semax	case SDP_DATA_SEQ8:
240121054Semax		SDP_GET8(len, rsp_tmp);
241121054Semax		break;
242121054Semax
243121054Semax	case SDP_DATA_SEQ16:
244121054Semax		SDP_GET16(len, rsp_tmp);
245121054Semax		break;
246121054Semax
247121054Semax	case SDP_DATA_SEQ32:
248121054Semax		SDP_GET32(len, rsp_tmp);
249121054Semax		break;
250121054Semax
251121054Semax	default:
252121054Semax		ss->error = ENOATTR;
253121054Semax		return (-1);
254121054Semax		/* NOT REACHED */
255121054Semax	}
256121054Semax
257121054Semax	for (; rsp_tmp < rsp && vlen > 0; ) {
258121054Semax		/* Get set of attributes for the next record */
259121054Semax		SDP_GET8(type, rsp_tmp);
260121054Semax		switch (type) {
261121054Semax		case SDP_DATA_SEQ8:
262121054Semax			SDP_GET8(len, rsp_tmp);
263121054Semax			break;
264121054Semax
265121054Semax		case SDP_DATA_SEQ16:
266121054Semax			SDP_GET16(len, rsp_tmp);
267121054Semax			break;
268121054Semax
269121054Semax		case SDP_DATA_SEQ32:
270121054Semax			SDP_GET32(len, rsp_tmp);
271121054Semax			break;
272121054Semax
273121054Semax		default:
274121054Semax			ss->error = ENOATTR;
275121054Semax			return (-1);
276121054Semax			/* NOT REACHED */
277121054Semax		}
278121054Semax
279121054Semax		/* Now rsp_tmp points to list of (attr,value) pairs */
280121054Semax		for (; len > 0 && vlen > 0; vp ++, vlen --) {
281121054Semax			/* Attribute */
282121054Semax			SDP_GET8(type, rsp_tmp);
283121054Semax			if (type != SDP_DATA_UINT16) {
284121054Semax				ss->error = ENOATTR;
285121054Semax				return (-1);
286121054Semax			}
287121054Semax			SDP_GET16(vp->attr, rsp_tmp);
288121054Semax
289121054Semax			/* Attribute value */
290121054Semax			switch (rsp_tmp[0]) {
291121054Semax			case SDP_DATA_NIL:
292121054Semax				alen = 0;
293121054Semax				break;
294121054Semax
295121054Semax			case SDP_DATA_UINT8:
296121054Semax			case SDP_DATA_INT8:
297121054Semax			case SDP_DATA_BOOL:
298121054Semax				alen = sizeof(u_int8_t);
299121054Semax				break;
300121054Semax
301121054Semax			case SDP_DATA_UINT16:
302121054Semax			case SDP_DATA_INT16:
303121054Semax			case SDP_DATA_UUID16:
304121054Semax				alen = sizeof(u_int16_t);
305121054Semax				break;
306121054Semax
307121054Semax			case SDP_DATA_UINT32:
308121054Semax			case SDP_DATA_INT32:
309121054Semax			case SDP_DATA_UUID32:
310121054Semax				alen = sizeof(u_int32_t);
311121054Semax				break;
312121054Semax
313121054Semax			case SDP_DATA_UINT64:
314121054Semax			case SDP_DATA_INT64:
315121054Semax				alen = sizeof(u_int64_t);
316121054Semax				break;
317121054Semax
318121054Semax			case SDP_DATA_UINT128:
319121054Semax			case SDP_DATA_INT128:
320121054Semax			case SDP_DATA_UUID128:
321121054Semax				alen = sizeof(u_int128_t);
322121054Semax				break;
323121054Semax
324121054Semax			case SDP_DATA_STR8:
325121054Semax			case SDP_DATA_URL8:
326121054Semax			case SDP_DATA_SEQ8:
327121054Semax			case SDP_DATA_ALT8:
328121054Semax				alen = rsp_tmp[1] + sizeof(u_int8_t);
329121054Semax				break;
330121054Semax
331121054Semax			case SDP_DATA_STR16:
332121054Semax			case SDP_DATA_URL16:
333121054Semax			case SDP_DATA_SEQ16:
334121054Semax			case SDP_DATA_ALT16:
335121054Semax				alen =	  ((u_int16_t)rsp_tmp[1] << 8)
336121054Semax					| ((u_int16_t)rsp_tmp[2]);
337121054Semax				alen += sizeof(u_int16_t);
338121054Semax				break;
339121054Semax
340121054Semax			case SDP_DATA_STR32:
341121054Semax			case SDP_DATA_URL32:
342121054Semax			case SDP_DATA_SEQ32:
343121054Semax			case SDP_DATA_ALT32:
344121054Semax				alen =    ((u_int32_t)rsp_tmp[1] << 24)
345121054Semax					| ((u_int32_t)rsp_tmp[2] << 16)
346121054Semax					| ((u_int32_t)rsp_tmp[3] <<  8)
347121054Semax					| ((u_int32_t)rsp_tmp[4]);
348121054Semax				alen += sizeof(u_int32_t);
349121054Semax				break;
350121054Semax
351121054Semax			default:
352121054Semax				ss->error = ENOATTR;
353121054Semax				return (-1);
354121054Semax				/* NOT REACHED */
355121054Semax			}
356121054Semax
357121054Semax			alen += sizeof(u_int8_t);
358121054Semax
359121054Semax			if (vp->value != NULL) {
360121054Semax				if (alen <= vp->vlen) {
361121054Semax					vp->flags = SDP_ATTR_OK;
362121054Semax					vp->vlen = alen;
363121054Semax				} else
364121054Semax					vp->flags = SDP_ATTR_TRUNCATED;
365121054Semax
366121054Semax				memcpy(vp->value, rsp_tmp, vp->vlen);
367121054Semax			} else
368121054Semax				vp->flags = SDP_ATTR_INVALID;
369121054Semax
370121054Semax			len -=	(
371121054Semax				sizeof(u_int8_t) + sizeof(u_int16_t) +
372121054Semax				alen
373121054Semax				);
374121054Semax
375121054Semax			rsp_tmp += alen;
376121054Semax		}
377121054Semax	}
378121054Semaxdone:
379121054Semax	ss->error = 0;
380121054Semax
381121054Semax	return (0);
382121054Semax}
383121054Semax
384