xref: /freebsd/usr.sbin/bluetooth/sdpd/ssar.c (revision 42249ef2)
1 /*-
2  * ssar.c
3  *
4  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5  *
6  * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $Id: ssar.c,v 1.4 2004/01/12 22:54:31 max Exp $
31  * $FreeBSD$
32  */
33 
34 #include <sys/queue.h>
35 #define L2CAP_SOCKET_CHECKED
36 #include <bluetooth.h>
37 #include <sdp.h>
38 #include <string.h>
39 #include "profile.h"
40 #include "provider.h"
41 #include "server.h"
42 #include "uuid-private.h"
43 
44 /* from sar.c */
45 int32_t server_prepare_attr_list(provider_p const provider,
46 		uint8_t const *req, uint8_t const * const req_end,
47 		uint8_t *rsp, uint8_t const * const rsp_end);
48 
49 /*
50  * Scan an attribute for matching UUID.
51  */
52 static int
53 server_search_uuid_sub(uint8_t *buf, uint8_t const * const eob, const uint128_t *uuid)
54 {
55         int128_t duuid;
56         uint32_t value;
57         uint8_t type;
58 
59         while (buf < eob) {
60 
61                 SDP_GET8(type, buf);
62 
63                 switch (type) {
64                 case SDP_DATA_UUID16:
65                         if (buf + 2 > eob)
66                                 continue;
67                         SDP_GET16(value, buf);
68 
69                         memcpy(&duuid, &uuid_base, sizeof(duuid));
70                         duuid.b[2] = value >> 8 & 0xff;
71                         duuid.b[3] = value & 0xff;
72 
73                         if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
74                                 return (0);
75                         break;
76                 case SDP_DATA_UUID32:
77                         if (buf + 4 > eob)
78                                 continue;
79                         SDP_GET32(value, buf);
80                         memcpy(&duuid, &uuid_base, sizeof(duuid));
81                         duuid.b[0] = value >> 24 & 0xff;
82                         duuid.b[1] = value >> 16 & 0xff;
83                         duuid.b[2] = value >> 8 & 0xff;
84                         duuid.b[3] = value & 0xff;
85 
86                         if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
87                                 return (0);
88                         break;
89                 case SDP_DATA_UUID128:
90                         if (buf + 16 > eob)
91                                 continue;
92                         SDP_GET_UUID128(&duuid, buf);
93 
94                         if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
95                                 return (0);
96                         break;
97                 case SDP_DATA_UINT8:
98                 case SDP_DATA_INT8:
99                 case SDP_DATA_SEQ8:
100                         buf++;
101                         break;
102                 case SDP_DATA_UINT16:
103                 case SDP_DATA_INT16:
104                 case SDP_DATA_SEQ16:
105                         buf += 2;
106                         break;
107                 case SDP_DATA_UINT32:
108                 case SDP_DATA_INT32:
109                 case SDP_DATA_SEQ32:
110                         buf += 4;
111                         break;
112                 case SDP_DATA_UINT64:
113                 case SDP_DATA_INT64:
114                         buf += 8;
115                         break;
116                 case SDP_DATA_UINT128:
117                 case SDP_DATA_INT128:
118                         buf += 16;
119                         break;
120                 case SDP_DATA_STR8:
121                         if (buf + 1 > eob)
122                                 continue;
123                         SDP_GET8(value, buf);
124                         buf += value;
125                         break;
126                 case SDP_DATA_STR16:
127                         if (buf + 2 > eob)
128                                 continue;
129                         SDP_GET16(value, buf);
130                         if (value > (eob - buf))
131                                 return (1);
132                         buf += value;
133                         break;
134                 case SDP_DATA_STR32:
135                         if (buf + 4 > eob)
136                                 continue;
137                         SDP_GET32(value, buf);
138                         if (value > (eob - buf))
139                                 return (1);
140                         buf += value;
141                         break;
142                 case SDP_DATA_BOOL:
143                         buf += 1;
144                         break;
145                 default:
146                         return (1);
147                 }
148         }
149         return (1);
150 }
151 
152 /*
153  * Search a provider for matching UUID in its attributes.
154  */
155 static int
156 server_search_uuid(provider_p const provider, const uint128_t *uuid)
157 {
158         uint8_t buffer[256];
159         const attr_t *attr;
160         int len;
161 
162         for (attr = provider->profile->attrs; attr->create != NULL; attr++) {
163 
164                 len = attr->create(buffer, buffer + sizeof(buffer),
165                     (const uint8_t *)provider->profile, sizeof(*provider->profile));
166                 if (len < 0)
167                         continue;
168                 if (server_search_uuid_sub(buffer, buffer + len, uuid) == 0)
169                         return (0);
170         }
171         return (1);
172 }
173 
174 /*
175  * Prepare SDP Service Search Attribute Response
176  */
177 
178 int32_t
179 server_prepare_service_search_attribute_response(server_p srv, int32_t fd)
180 {
181 	uint8_t const	*req = srv->req + sizeof(sdp_pdu_t);
182 	uint8_t const	*req_end = req + ((sdp_pdu_p)(srv->req))->len;
183 	uint8_t		*rsp = srv->fdidx[fd].rsp;
184 	uint8_t const	*rsp_end = rsp + NG_L2CAP_MTU_MAXIMUM;
185 
186 	uint8_t const	*sspptr = NULL, *aidptr = NULL;
187 	uint8_t		*ptr = NULL;
188 
189 	provider_t	*provider = NULL;
190 	int32_t		 type, rsp_limit, ssplen, aidlen, cslen, cs;
191 	uint128_t	 uuid, puuid;
192 
193 	/*
194 	 * Minimal Service Search Attribute Request request
195 	 *
196 	 * seq8 len8		- 2 bytes
197 	 *	uuid16 value16  - 3 bytes ServiceSearchPattern
198 	 * value16		- 2 bytes MaximumAttributeByteCount
199 	 * seq8 len8		- 2 bytes
200 	 *	uint16 value16	- 3 bytes AttributeIDList
201 	 * value8		- 1 byte  ContinuationState
202 	 */
203 
204 	if (req_end - req < 13)
205 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
206 
207 	/* Get size of ServiceSearchPattern */
208 	ssplen = 0;
209 	SDP_GET8(type, req);
210 	switch (type) {
211 	case SDP_DATA_SEQ8:
212 		SDP_GET8(ssplen, req);
213 		break;
214 
215 	case SDP_DATA_SEQ16:
216 		SDP_GET16(ssplen, req);
217 		break;
218 
219 	case SDP_DATA_SEQ32:
220 		SDP_GET32(ssplen, req);
221 		break;
222 	}
223 	if (ssplen <= 0)
224 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
225 
226 	sspptr = req;
227 	req += ssplen;
228 
229 	/* Get MaximumAttributeByteCount */
230 	if (req + 2 > req_end)
231 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
232 
233 	SDP_GET16(rsp_limit, req);
234 	if (rsp_limit <= 0)
235 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
236 
237 	/* Get size of AttributeIDList */
238 	if (req + 1 > req_end)
239 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
240 
241 	aidlen = 0;
242 	SDP_GET8(type, req);
243 	switch (type) {
244 	case SDP_DATA_SEQ8:
245 		if (req + 1 > req_end)
246 			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
247 
248 		SDP_GET8(aidlen, req);
249 		break;
250 
251 	case SDP_DATA_SEQ16:
252 		if (req + 2 > req_end)
253 			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
254 
255 		SDP_GET16(aidlen, req);
256 		break;
257 
258 	case SDP_DATA_SEQ32:
259 		if (req + 4 > req_end)
260 			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
261 
262 		SDP_GET32(aidlen, req);
263 		break;
264 	}
265 	if (aidlen <= 0)
266 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
267 
268 	aidptr = req;
269 	req += aidlen;
270 
271 	/* Get ContinuationState */
272 	if (req + 1 > req_end)
273 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
274 
275 	SDP_GET8(cslen, req);
276 	if (cslen != 0) {
277 		if (cslen != 2 || req_end - req != 2)
278 			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
279 
280 		SDP_GET16(cs, req);
281 	} else
282 		cs = 0;
283 
284 	/* Process the request. First, check continuation state */
285 	if (srv->fdidx[fd].rsp_cs != cs)
286 		return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE);
287 	if (srv->fdidx[fd].rsp_size > 0)
288 		return (0);
289 
290 	/*
291 	 * Service Search Attribute Response format
292 	 *
293 	 * value16		- 2 bytes  AttributeListByteCount (not incl.)
294 	 * seq8 len16		- 3 bytes
295 	 *	attr list	- 3+ bytes AttributeLists
296 	 *	[ attr list ]
297 	 */
298 
299 	ptr = rsp + 3;
300 
301 	while (ssplen > 0) {
302 		SDP_GET8(type, sspptr);
303 		ssplen --;
304 
305 		switch (type) {
306 		case SDP_DATA_UUID16:
307 			if (ssplen < 2)
308 				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
309 
310 			memcpy(&uuid, &uuid_base, sizeof(uuid));
311 			uuid.b[2] = *sspptr ++;
312 			uuid.b[3] = *sspptr ++;
313 			ssplen -= 2;
314 			break;
315 
316 		case SDP_DATA_UUID32:
317 			if (ssplen < 4)
318 				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
319 
320 			memcpy(&uuid, &uuid_base, sizeof(uuid));
321 			uuid.b[0] = *sspptr ++;
322 			uuid.b[1] = *sspptr ++;
323 			uuid.b[2] = *sspptr ++;
324 			uuid.b[3] = *sspptr ++;
325 			ssplen -= 4;
326 			break;
327 
328 		case SDP_DATA_UUID128:
329 			if (ssplen < 16)
330 				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
331 
332 			memcpy(uuid.b, sspptr, 16);
333 			sspptr += 16;
334 			ssplen -= 16;
335 			break;
336 
337 		default:
338 			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
339 			/* NOT REACHED */
340 		}
341 
342 		for (provider = provider_get_first();
343 		     provider != NULL;
344 		     provider = provider_get_next(provider)) {
345 			if (!provider_match_bdaddr(provider, &srv->req_sa.l2cap_bdaddr))
346 				continue;
347 
348 			memcpy(&puuid, &uuid_base, sizeof(puuid));
349 			puuid.b[2] = provider->profile->uuid >> 8;
350 			puuid.b[3] = provider->profile->uuid;
351 
352 			if (memcmp(&uuid, &puuid, sizeof(uuid)) != 0 &&
353 			    memcmp(&uuid, &uuid_public_browse_group, sizeof(uuid)) != 0 &&
354 			    server_search_uuid(provider, &uuid) != 0)
355 				continue;
356 
357 			cs = server_prepare_attr_list(provider,
358 				aidptr, aidptr + aidlen, ptr, rsp_end);
359 			if (cs < 0)
360 				return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
361 
362 			ptr += cs;
363 		}
364 	}
365 
366 	/* Set reply size (not counting PDU header and continuation state) */
367 	srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t) - 2;
368 	if (srv->fdidx[fd].rsp_limit > rsp_limit)
369 		srv->fdidx[fd].rsp_limit = rsp_limit;
370 
371 	srv->fdidx[fd].rsp_size = ptr - rsp;
372 	srv->fdidx[fd].rsp_cs = 0;
373 
374 	/* Fix AttributeLists sequence header */
375 	ptr = rsp;
376 	SDP_PUT8(SDP_DATA_SEQ16, ptr);
377 	SDP_PUT16(srv->fdidx[fd].rsp_size - 3, ptr);
378 
379 	return (0);
380 }
381 
382