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: stable/10/usr.sbin/bluetooth/sdpd/ssar.c 344146 2019-02-15 09:22:23Z hselasky $
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/*
47344146Shselasky * Scan an attribute for matching UUID.
48344146Shselasky */
49344146Shselaskystatic int
50344146Shselaskyserver_search_uuid_sub(uint8_t *buf, uint8_t const * const eob, const uint128_t *uuid)
51344146Shselasky{
52344146Shselasky        int128_t duuid;
53344146Shselasky        uint32_t value;
54344146Shselasky        uint8_t type;
55344146Shselasky
56344146Shselasky        while (buf < eob) {
57344146Shselasky
58344146Shselasky                SDP_GET8(type, buf);
59344146Shselasky
60344146Shselasky                switch (type) {
61344146Shselasky                case SDP_DATA_UUID16:
62344146Shselasky                        if (buf + 2 > eob)
63344146Shselasky                                continue;
64344146Shselasky                        SDP_GET16(value, buf);
65344146Shselasky
66344146Shselasky                        memcpy(&duuid, &uuid_base, sizeof(duuid));
67344146Shselasky                        duuid.b[2] = value >> 8 & 0xff;
68344146Shselasky                        duuid.b[3] = value & 0xff;
69344146Shselasky
70344146Shselasky                        if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
71344146Shselasky                                return (0);
72344146Shselasky                        break;
73344146Shselasky                case SDP_DATA_UUID32:
74344146Shselasky                        if (buf + 4 > eob)
75344146Shselasky                                continue;
76344146Shselasky                        SDP_GET32(value, buf);
77344146Shselasky                        memcpy(&duuid, &uuid_base, sizeof(duuid));
78344146Shselasky                        duuid.b[0] = value >> 24 & 0xff;
79344146Shselasky                        duuid.b[1] = value >> 16 & 0xff;
80344146Shselasky                        duuid.b[2] = value >> 8 & 0xff;
81344146Shselasky                        duuid.b[3] = value & 0xff;
82344146Shselasky
83344146Shselasky                        if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
84344146Shselasky                                return (0);
85344146Shselasky                        break;
86344146Shselasky                case SDP_DATA_UUID128:
87344146Shselasky                        if (buf + 16 > eob)
88344146Shselasky                                continue;
89344146Shselasky                        SDP_GET_UUID128(&duuid, buf);
90344146Shselasky
91344146Shselasky                        if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
92344146Shselasky                                return (0);
93344146Shselasky                        break;
94344146Shselasky                case SDP_DATA_UINT8:
95344146Shselasky                case SDP_DATA_INT8:
96344146Shselasky                case SDP_DATA_SEQ8:
97344146Shselasky                        buf++;
98344146Shselasky                        break;
99344146Shselasky                case SDP_DATA_UINT16:
100344146Shselasky                case SDP_DATA_INT16:
101344146Shselasky                case SDP_DATA_SEQ16:
102344146Shselasky                        buf += 2;
103344146Shselasky                        break;
104344146Shselasky                case SDP_DATA_UINT32:
105344146Shselasky                case SDP_DATA_INT32:
106344146Shselasky                case SDP_DATA_SEQ32:
107344146Shselasky                        buf += 4;
108344146Shselasky                        break;
109344146Shselasky                case SDP_DATA_UINT64:
110344146Shselasky                case SDP_DATA_INT64:
111344146Shselasky                        buf += 8;
112344146Shselasky                        break;
113344146Shselasky                case SDP_DATA_UINT128:
114344146Shselasky                case SDP_DATA_INT128:
115344146Shselasky                        buf += 16;
116344146Shselasky                        break;
117344146Shselasky                case SDP_DATA_STR8:
118344146Shselasky                        if (buf + 1 > eob)
119344146Shselasky                                continue;
120344146Shselasky                        SDP_GET8(value, buf);
121344146Shselasky                        buf += value;
122344146Shselasky                        break;
123344146Shselasky                case SDP_DATA_STR16:
124344146Shselasky                        if (buf + 2 > eob)
125344146Shselasky                                continue;
126344146Shselasky                        SDP_GET16(value, buf);
127344146Shselasky                        if (value > (eob - buf))
128344146Shselasky                                return (1);
129344146Shselasky                        buf += value;
130344146Shselasky                        break;
131344146Shselasky                case SDP_DATA_STR32:
132344146Shselasky                        if (buf + 4 > eob)
133344146Shselasky                                continue;
134344146Shselasky                        SDP_GET32(value, buf);
135344146Shselasky                        if (value > (eob - buf))
136344146Shselasky                                return (1);
137344146Shselasky                        buf += value;
138344146Shselasky                        break;
139344146Shselasky                case SDP_DATA_BOOL:
140344146Shselasky                        buf += 1;
141344146Shselasky                        break;
142344146Shselasky                default:
143344146Shselasky                        return (1);
144344146Shselasky                }
145344146Shselasky        }
146344146Shselasky        return (1);
147344146Shselasky}
148344146Shselasky
149344146Shselasky/*
150344146Shselasky * Search a provider for matching UUID in its attributes.
151344146Shselasky */
152344146Shselaskystatic int
153344146Shselaskyserver_search_uuid(provider_p const provider, const uint128_t *uuid)
154344146Shselasky{
155344146Shselasky        uint8_t buffer[256];
156344146Shselasky        const attr_t *attr;
157344146Shselasky        int len;
158344146Shselasky
159344146Shselasky        for (attr = provider->profile->attrs; attr->create != NULL; attr++) {
160344146Shselasky
161344146Shselasky                len = attr->create(buffer, buffer + sizeof(buffer),
162344146Shselasky                    (const uint8_t *)provider->profile, sizeof(*provider->profile));
163344146Shselasky                if (len < 0)
164344146Shselasky                        continue;
165344146Shselasky                if (server_search_uuid_sub(buffer, buffer + len, uuid) == 0)
166344146Shselasky                        return (0);
167344146Shselasky        }
168344146Shselasky        return (1);
169344146Shselasky}
170344146Shselasky
171344146Shselasky/*
172124758Semax * Prepare SDP Service Search Attribute Response
173124758Semax */
174124758Semax
175124758Semaxint32_t
176124758Semaxserver_prepare_service_search_attribute_response(server_p srv, int32_t fd)
177124758Semax{
178124758Semax	uint8_t const	*req = srv->req + sizeof(sdp_pdu_t);
179124758Semax	uint8_t const	*req_end = req + ((sdp_pdu_p)(srv->req))->len;
180124758Semax	uint8_t		*rsp = srv->fdidx[fd].rsp;
181124758Semax	uint8_t const	*rsp_end = rsp + NG_L2CAP_MTU_MAXIMUM;
182124758Semax
183124758Semax	uint8_t const	*sspptr = NULL, *aidptr = NULL;
184124758Semax	uint8_t		*ptr = NULL;
185124758Semax
186124758Semax	provider_t	*provider = NULL;
187139721Semax	int32_t		 type, rsp_limit, ssplen, aidlen, cslen, cs;
188139721Semax	uint128_t	 uuid, puuid;
189124758Semax
190124758Semax	/*
191124758Semax	 * Minimal Service Search Attribute Request request
192124758Semax	 *
193124758Semax	 * seq8 len8		- 2 bytes
194124758Semax	 *	uuid16 value16  - 3 bytes ServiceSearchPattern
195124758Semax	 * value16		- 2 bytes MaximumAttributeByteCount
196124758Semax	 * seq8 len8		- 2 bytes
197124758Semax	 *	uint16 value16	- 3 bytes AttributeIDList
198124758Semax	 * value8		- 1 byte  ContinuationState
199124758Semax	 */
200124758Semax
201124758Semax	if (req_end - req < 13)
202124758Semax		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
203124758Semax
204124758Semax	/* Get size of ServiceSearchPattern */
205124758Semax	ssplen = 0;
206124758Semax	SDP_GET8(type, req);
207124758Semax	switch (type) {
208124758Semax	case SDP_DATA_SEQ8:
209124758Semax		SDP_GET8(ssplen, req);
210124758Semax		break;
211124758Semax
212124758Semax	case SDP_DATA_SEQ16:
213124758Semax		SDP_GET16(ssplen, req);
214124758Semax		break;
215124758Semax
216124758Semax	case SDP_DATA_SEQ32:
217124758Semax		SDP_GET32(ssplen, req);
218124758Semax		break;
219124758Semax	}
220124758Semax	if (ssplen <= 0)
221124758Semax		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
222124758Semax
223124758Semax	sspptr = req;
224124758Semax	req += ssplen;
225124758Semax
226124758Semax	/* Get MaximumAttributeByteCount */
227124758Semax	if (req + 2 > req_end)
228124758Semax		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
229124758Semax
230124758Semax	SDP_GET16(rsp_limit, req);
231124758Semax	if (rsp_limit <= 0)
232124758Semax		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
233124758Semax
234124758Semax	/* Get size of AttributeIDList */
235124758Semax	if (req + 1 > req_end)
236124758Semax		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
237124758Semax
238124758Semax	aidlen = 0;
239124758Semax	SDP_GET8(type, req);
240124758Semax	switch (type) {
241124758Semax	case SDP_DATA_SEQ8:
242124758Semax		if (req + 1 > req_end)
243124758Semax			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
244124758Semax
245124758Semax		SDP_GET8(aidlen, req);
246124758Semax		break;
247124758Semax
248124758Semax	case SDP_DATA_SEQ16:
249124758Semax		if (req + 2 > req_end)
250124758Semax			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
251124758Semax
252124758Semax		SDP_GET16(aidlen, req);
253124758Semax		break;
254124758Semax
255124758Semax	case SDP_DATA_SEQ32:
256124758Semax		if (req + 4 > req_end)
257124758Semax			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
258124758Semax
259124758Semax		SDP_GET32(aidlen, req);
260124758Semax		break;
261124758Semax	}
262124758Semax	if (aidlen <= 0)
263124758Semax		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
264124758Semax
265124758Semax	aidptr = req;
266124758Semax	req += aidlen;
267124758Semax
268124758Semax	/* Get ContinuationState */
269124758Semax	if (req + 1 > req_end)
270124758Semax		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
271124758Semax
272124758Semax	SDP_GET8(cslen, req);
273124758Semax	if (cslen != 0) {
274124758Semax		if (cslen != 2 || req_end - req != 2)
275124758Semax			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
276124758Semax
277124758Semax		SDP_GET16(cs, req);
278124758Semax	} else
279124758Semax		cs = 0;
280124758Semax
281124758Semax	/* Process the request. First, check continuation state */
282124758Semax	if (srv->fdidx[fd].rsp_cs != cs)
283124758Semax		return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE);
284124758Semax	if (srv->fdidx[fd].rsp_size > 0)
285124758Semax		return (0);
286124758Semax
287124758Semax	/*
288124758Semax	 * Service Search Attribute Response format
289124758Semax	 *
290124758Semax	 * value16		- 2 bytes  AttributeListByteCount (not incl.)
291124758Semax	 * seq8 len16		- 3 bytes
292124758Semax	 *	attr list	- 3+ bytes AttributeLists
293124758Semax	 *	[ attr list ]
294124758Semax	 */
295124758Semax
296124758Semax	ptr = rsp + 3;
297124758Semax
298124758Semax	while (ssplen > 0) {
299124758Semax		SDP_GET8(type, sspptr);
300124758Semax		ssplen --;
301124758Semax
302124758Semax		switch (type) {
303124758Semax		case SDP_DATA_UUID16:
304124758Semax			if (ssplen < 2)
305124758Semax				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
306124758Semax
307139721Semax			memcpy(&uuid, &uuid_base, sizeof(uuid));
308139721Semax			uuid.b[2] = *sspptr ++;
309139721Semax			uuid.b[3] = *sspptr ++;
310124758Semax			ssplen -= 2;
311124758Semax			break;
312124758Semax
313139721Semax		case SDP_DATA_UUID32:
314139721Semax			if (ssplen < 4)
315139721Semax				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
316139721Semax
317139721Semax			memcpy(&uuid, &uuid_base, sizeof(uuid));
318139721Semax			uuid.b[0] = *sspptr ++;
319139721Semax			uuid.b[1] = *sspptr ++;
320139721Semax			uuid.b[2] = *sspptr ++;
321139721Semax			uuid.b[3] = *sspptr ++;
322139721Semax			ssplen -= 4;
323139721Semax			break;
324139721Semax
325139721Semax		case SDP_DATA_UUID128:
326139721Semax			if (ssplen < 16)
327139721Semax				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
328139721Semax
329139721Semax			memcpy(uuid.b, sspptr, 16);
330139721Semax			sspptr += 16;
331139721Semax			ssplen -= 16;
332139721Semax			break;
333139721Semax
334124758Semax		default:
335124758Semax			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
336124758Semax			/* NOT REACHED */
337124758Semax		}
338124758Semax
339124758Semax		for (provider = provider_get_first();
340124758Semax		     provider != NULL;
341124758Semax		     provider = provider_get_next(provider)) {
342124758Semax			if (!provider_match_bdaddr(provider, &srv->req_sa.l2cap_bdaddr))
343124758Semax				continue;
344124758Semax
345139721Semax			memcpy(&puuid, &uuid_base, sizeof(puuid));
346139721Semax			puuid.b[2] = provider->profile->uuid >> 8;
347139721Semax			puuid.b[3] = provider->profile->uuid;
348139721Semax
349139721Semax			if (memcmp(&uuid, &puuid, sizeof(uuid)) != 0 &&
350344146Shselasky			    memcmp(&uuid, &uuid_public_browse_group, sizeof(uuid)) != 0 &&
351344146Shselasky			    server_search_uuid(provider, &uuid) != 0)
352124758Semax				continue;
353124758Semax
354124758Semax			cs = server_prepare_attr_list(provider,
355124758Semax				aidptr, aidptr + aidlen, ptr, rsp_end);
356124758Semax			if (cs < 0)
357124758Semax				return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
358124758Semax
359124758Semax			ptr += cs;
360124758Semax		}
361124758Semax	}
362124758Semax
363124758Semax	/* Set reply size (not counting PDU header and continuation state) */
364124758Semax	srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t) - 2;
365124758Semax	if (srv->fdidx[fd].rsp_limit > rsp_limit)
366124758Semax		srv->fdidx[fd].rsp_limit = rsp_limit;
367124758Semax
368124758Semax	srv->fdidx[fd].rsp_size = ptr - rsp;
369124758Semax	srv->fdidx[fd].rsp_cs = 0;
370124758Semax
371124758Semax	/* Fix AttributeLists sequence header */
372124758Semax	ptr = rsp;
373124758Semax	SDP_PUT8(SDP_DATA_SEQ16, ptr);
374124758Semax	SDP_PUT16(srv->fdidx[fd].rsp_size - 3, ptr);
375124758Semax
376124758Semax	return (0);
377124758Semax}
378124758Semax
379