1124758Semax/*
2124758Semax * ssar.c
3124758Semax *
4124758Semax * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5124758Semax * All rights reserved.
6124758Semax *
7124758Semax * Redistribution and use in source and binary forms, with or without
8124758Semax * modification, are permitted provided that the following conditions
9124758Semax * are met:
10124758Semax * 1. Redistributions of source code must retain the above copyright
11124758Semax *    notice, this list of conditions and the following disclaimer.
12124758Semax * 2. Redistributions in binary form must reproduce the above copyright
13124758Semax *    notice, this list of conditions and the following disclaimer in the
14124758Semax *    documentation and/or other materials provided with the distribution.
15124758Semax *
16124758Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17124758Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18124758Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19124758Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20124758Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21124758Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22124758Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23124758Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24124758Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25124758Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26124758Semax * SUCH DAMAGE.
27124758Semax *
28124758Semax * $Id: ssar.c,v 1.4 2004/01/12 22:54:31 max Exp $
29124758Semax * $FreeBSD$
30124758Semax */
31124758Semax
32124758Semax#include <sys/queue.h>
33124758Semax#include <bluetooth.h>
34124758Semax#include <sdp.h>
35124758Semax#include <string.h>
36124758Semax#include "profile.h"
37124758Semax#include "provider.h"
38124758Semax#include "server.h"
39139721Semax#include "uuid-private.h"
40124758Semax
41124758Semax/* from sar.c */
42124758Semaxint32_t server_prepare_attr_list(provider_p const provider,
43124758Semax		uint8_t const *req, uint8_t const * const req_end,
44124758Semax		uint8_t *rsp, uint8_t const * const rsp_end);
45124758Semax
46124758Semax/*
47124758Semax * Prepare SDP Service Search Attribute Response
48124758Semax */
49124758Semax
50124758Semaxint32_t
51124758Semaxserver_prepare_service_search_attribute_response(server_p srv, int32_t fd)
52124758Semax{
53124758Semax	uint8_t const	*req = srv->req + sizeof(sdp_pdu_t);
54124758Semax	uint8_t const	*req_end = req + ((sdp_pdu_p)(srv->req))->len;
55124758Semax	uint8_t		*rsp = srv->fdidx[fd].rsp;
56124758Semax	uint8_t const	*rsp_end = rsp + NG_L2CAP_MTU_MAXIMUM;
57124758Semax
58124758Semax	uint8_t const	*sspptr = NULL, *aidptr = NULL;
59124758Semax	uint8_t		*ptr = NULL;
60124758Semax
61124758Semax	provider_t	*provider = NULL;
62139721Semax	int32_t		 type, rsp_limit, ssplen, aidlen, cslen, cs;
63139721Semax	uint128_t	 uuid, puuid;
64124758Semax
65124758Semax	/*
66124758Semax	 * Minimal Service Search Attribute Request request
67124758Semax	 *
68124758Semax	 * seq8 len8		- 2 bytes
69124758Semax	 *	uuid16 value16  - 3 bytes ServiceSearchPattern
70124758Semax	 * value16		- 2 bytes MaximumAttributeByteCount
71124758Semax	 * seq8 len8		- 2 bytes
72124758Semax	 *	uint16 value16	- 3 bytes AttributeIDList
73124758Semax	 * value8		- 1 byte  ContinuationState
74124758Semax	 */
75124758Semax
76124758Semax	if (req_end - req < 13)
77124758Semax		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
78124758Semax
79124758Semax	/* Get size of ServiceSearchPattern */
80124758Semax	ssplen = 0;
81124758Semax	SDP_GET8(type, req);
82124758Semax	switch (type) {
83124758Semax	case SDP_DATA_SEQ8:
84124758Semax		SDP_GET8(ssplen, req);
85124758Semax		break;
86124758Semax
87124758Semax	case SDP_DATA_SEQ16:
88124758Semax		SDP_GET16(ssplen, req);
89124758Semax		break;
90124758Semax
91124758Semax	case SDP_DATA_SEQ32:
92124758Semax		SDP_GET32(ssplen, req);
93124758Semax		break;
94124758Semax	}
95124758Semax	if (ssplen <= 0)
96124758Semax		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
97124758Semax
98124758Semax	sspptr = req;
99124758Semax	req += ssplen;
100124758Semax
101124758Semax	/* Get MaximumAttributeByteCount */
102124758Semax	if (req + 2 > req_end)
103124758Semax		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
104124758Semax
105124758Semax	SDP_GET16(rsp_limit, req);
106124758Semax	if (rsp_limit <= 0)
107124758Semax		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
108124758Semax
109124758Semax	/* Get size of AttributeIDList */
110124758Semax	if (req + 1 > req_end)
111124758Semax		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
112124758Semax
113124758Semax	aidlen = 0;
114124758Semax	SDP_GET8(type, req);
115124758Semax	switch (type) {
116124758Semax	case SDP_DATA_SEQ8:
117124758Semax		if (req + 1 > req_end)
118124758Semax			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
119124758Semax
120124758Semax		SDP_GET8(aidlen, req);
121124758Semax		break;
122124758Semax
123124758Semax	case SDP_DATA_SEQ16:
124124758Semax		if (req + 2 > req_end)
125124758Semax			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
126124758Semax
127124758Semax		SDP_GET16(aidlen, req);
128124758Semax		break;
129124758Semax
130124758Semax	case SDP_DATA_SEQ32:
131124758Semax		if (req + 4 > req_end)
132124758Semax			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
133124758Semax
134124758Semax		SDP_GET32(aidlen, req);
135124758Semax		break;
136124758Semax	}
137124758Semax	if (aidlen <= 0)
138124758Semax		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
139124758Semax
140124758Semax	aidptr = req;
141124758Semax	req += aidlen;
142124758Semax
143124758Semax	/* Get ContinuationState */
144124758Semax	if (req + 1 > req_end)
145124758Semax		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
146124758Semax
147124758Semax	SDP_GET8(cslen, req);
148124758Semax	if (cslen != 0) {
149124758Semax		if (cslen != 2 || req_end - req != 2)
150124758Semax			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
151124758Semax
152124758Semax		SDP_GET16(cs, req);
153124758Semax	} else
154124758Semax		cs = 0;
155124758Semax
156124758Semax	/* Process the request. First, check continuation state */
157124758Semax	if (srv->fdidx[fd].rsp_cs != cs)
158124758Semax		return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE);
159124758Semax	if (srv->fdidx[fd].rsp_size > 0)
160124758Semax		return (0);
161124758Semax
162124758Semax	/*
163124758Semax	 * Service Search Attribute Response format
164124758Semax	 *
165124758Semax	 * value16		- 2 bytes  AttributeListByteCount (not incl.)
166124758Semax	 * seq8 len16		- 3 bytes
167124758Semax	 *	attr list	- 3+ bytes AttributeLists
168124758Semax	 *	[ attr list ]
169124758Semax	 */
170124758Semax
171124758Semax	ptr = rsp + 3;
172124758Semax
173124758Semax	while (ssplen > 0) {
174124758Semax		SDP_GET8(type, sspptr);
175124758Semax		ssplen --;
176124758Semax
177124758Semax		switch (type) {
178124758Semax		case SDP_DATA_UUID16:
179124758Semax			if (ssplen < 2)
180124758Semax				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
181124758Semax
182139721Semax			memcpy(&uuid, &uuid_base, sizeof(uuid));
183139721Semax			uuid.b[2] = *sspptr ++;
184139721Semax			uuid.b[3] = *sspptr ++;
185124758Semax			ssplen -= 2;
186124758Semax			break;
187124758Semax
188139721Semax		case SDP_DATA_UUID32:
189139721Semax			if (ssplen < 4)
190139721Semax				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
191139721Semax
192139721Semax			memcpy(&uuid, &uuid_base, sizeof(uuid));
193139721Semax			uuid.b[0] = *sspptr ++;
194139721Semax			uuid.b[1] = *sspptr ++;
195139721Semax			uuid.b[2] = *sspptr ++;
196139721Semax			uuid.b[3] = *sspptr ++;
197139721Semax			ssplen -= 4;
198139721Semax			break;
199139721Semax
200139721Semax		case SDP_DATA_UUID128:
201139721Semax			if (ssplen < 16)
202139721Semax				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
203139721Semax
204139721Semax			memcpy(uuid.b, sspptr, 16);
205139721Semax			sspptr += 16;
206139721Semax			ssplen -= 16;
207139721Semax			break;
208139721Semax
209124758Semax		default:
210124758Semax			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
211124758Semax			/* NOT REACHED */
212124758Semax		}
213124758Semax
214124758Semax		for (provider = provider_get_first();
215124758Semax		     provider != NULL;
216124758Semax		     provider = provider_get_next(provider)) {
217124758Semax			if (!provider_match_bdaddr(provider, &srv->req_sa.l2cap_bdaddr))
218124758Semax				continue;
219124758Semax
220139721Semax			memcpy(&puuid, &uuid_base, sizeof(puuid));
221139721Semax			puuid.b[2] = provider->profile->uuid >> 8;
222139721Semax			puuid.b[3] = provider->profile->uuid;
223139721Semax
224139721Semax			if (memcmp(&uuid, &puuid, sizeof(uuid)) != 0 &&
225139721Semax			    memcmp(&uuid, &uuid_public_browse_group, sizeof(uuid)) != 0)
226124758Semax				continue;
227124758Semax
228124758Semax			cs = server_prepare_attr_list(provider,
229124758Semax				aidptr, aidptr + aidlen, ptr, rsp_end);
230124758Semax			if (cs < 0)
231124758Semax				return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
232124758Semax
233124758Semax			ptr += cs;
234124758Semax		}
235124758Semax	}
236124758Semax
237124758Semax	/* Set reply size (not counting PDU header and continuation state) */
238124758Semax	srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t) - 2;
239124758Semax	if (srv->fdidx[fd].rsp_limit > rsp_limit)
240124758Semax		srv->fdidx[fd].rsp_limit = rsp_limit;
241124758Semax
242124758Semax	srv->fdidx[fd].rsp_size = ptr - rsp;
243124758Semax	srv->fdidx[fd].rsp_cs = 0;
244124758Semax
245124758Semax	/* Fix AttributeLists sequence header */
246124758Semax	ptr = rsp;
247124758Semax	SDP_PUT8(SDP_DATA_SEQ16, ptr);
248124758Semax	SDP_PUT16(srv->fdidx[fd].rsp_size - 3, ptr);
249124758Semax
250124758Semax	return (0);
251124758Semax}
252124758Semax
253