xref: /netbsd/usr.sbin/sdpd/db.c (revision d3fd925f)
1 /*	$NetBSD: db.c,v 1.2 2015/11/24 21:11:39 plunky Exp $	*/
2 
3 /*-
4  * Copyright (c) 2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Iain Hibbert.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: db.c,v 1.2 2015/11/24 21:11:39 plunky Exp $");
34 
35 #include <bluetooth.h>
36 #include <sdp.h>
37 #include <stdbool.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <uuid.h>
41 
42 #include "sdpd.h"
43 
44 /*
45  * Using a prebuilt service record means that providing ServerState
46  * and a non-hardcoded ProviderName are difficult. Look into that later.
47  */
48 
49 /* ServiceDiscoveryServer service record */
50 static uint8_t sds_data[] = {
51 	0x09, 0x00, 0x00,	//  uint16	ServiceRecordHandle
52 	0x0a, 0x00, 0x00, 0x00,	//  uint32	0x00000000
53 	0x00,
54 
55 	0x09, 0x00, 0x01,	//  uint16	ServiceClassIDList
56 	0x35, 0x03,		//  seq8(3)
57 	0x19, 0x10, 0x00,	//   uuid16	ServiceDiscoveryServer
58 
59 	0x09, 0x00, 0x04,	//  uint16	ProtocolDescriptorList
60 	0x35, 0x0d,		//  seq8(13)
61 	0x35, 0x06,		//   seq8(6)
62 	0x19, 0x01, 0x00,	//    uuid16	L2CAP
63 	0x09, 0x00, 0x01,	//    uint16	L2CAP_PSM_SDP
64 	0x35, 0x03,		//   seq8(3)
65 	0x19, 0x00, 0x01,	//    uuid16	SDP
66 
67 	0x09, 0x00, 0x05,	//  uint16	BrowseGroupList
68 	0x35, 0x03,		//  seq8(3)
69 	0x19, 0x10, 0x02,	//   uuid16	PublicBrowseGroup
70 
71 	0x09, 0x00, 0x06,	//  uint16	LanguageBaseAttributeIDList
72 	0x35, 0x09,		//  seq8(9)
73 	0x09, 0x65, 0x6e,	//   uint16	0x656e	("en")
74 	0x09, 0x00, 0x6a,	//   uint16	106	(UTF-8)
75 	0x09, 0x01, 0x00,	//   uint16	PrimaryLanguageBaseID
76 
77 	0x09, 0x01, 0x00,	//  uint16	PrimaryLanguageBaseID + ServiceNameOffset
78 	0x25, 0x1b, 0x42, 0x6c,	//  str8(27)	"Bluetooth service discovery"
79 	0x75, 0x65, 0x74, 0x6f,
80 	0x6f, 0x74, 0x68, 0x20,
81 	0x73, 0x65, 0x72, 0x76,
82 	0x69, 0x63, 0x65, 0x20,
83 	0x64, 0x69, 0x73, 0x63,
84 	0x6f, 0x76, 0x65, 0x72,
85 	0x79,
86 
87 	0x09, 0x01, 0x02,	//  uint16	PrimaryLanguageBaseID + ProviderNameOffset
88 	0x25, 0x06, 0x4e, 0x65,	//  str8(6)	"NetBSD"
89 	0x74, 0x42, 0x53, 0x44,
90 
91 	0x09, 0x02, 0x00,	//  uint16	VersionNumberList
92 	0x35, 0x03,		//  seq8(3)
93 	0x09, 0x01, 0x00,	//   uint16	v1.0
94 };
95 
96 /* BrowseGroupDescriptor service record */
97 static uint8_t bgd_data[] = {
98 	0x09, 0x00, 0x00,	//  uint16	ServiceRecordHandle
99 	0x0a, 0x00, 0x01, 0x00,	//  uint32	0x00010000
100 	0x00,
101 
102 	0x09, 0x00, 0x01,	//  uint16	ServiceClassIDList
103 	0x35, 0x03,		//  seq8(3)
104 	0x19, 0x10, 0x01,	//   uuid16	BrowseGroupDescriptor
105 
106 	0x09, 0x00, 0x06,	//  uint16	LanguageBaseAttributeIDList
107 	0x35, 0x09,		//  seq8(9)
108 	0x09, 0x65, 0x6e,	//   uint16	0x656e	("en")
109 	0x09, 0x00, 0x6a,	//   uint16	106	(UTF-8)
110 	0x09, 0x01, 0x00,	//   uint16	PrimaryLanguageBaseID
111 
112 	0x09, 0x01, 0x00,	//  uint16	PrimaryLanguageBaseID + ServiceNameOffset
113 	0x25, 0x12, 0x50, 0x75,	//  str8(18)	"Public Browse Root"
114 	0x62, 0x6c, 0x69, 0x63,
115 	0x20, 0x42, 0x72, 0x6f,
116 	0x77, 0x73, 0x65, 0x20,
117 	0x52, 0x6f, 0x6f, 0x74,
118 
119 	0x09, 0x02, 0x00,	//  uint16	GroupID
120 	0x19, 0x10, 0x02,	//  uuid16	PublicBrowseRoot
121 };
122 
123 /*
124  * Initialise the record database with the ServiceDiscoveryServer
125  * and BrowseGroupDescriptor records
126  */
127 bool
db_init(server_t * srv)128 db_init(server_t *srv)
129 {
130 	sdp_data_t d;
131 
132 	LIST_INIT(&srv->rlist);
133 	srv->handle = 0x00010000; /* values 0x00000001->0x0000FFFF are reserved */
134 
135 	d.next = sds_data;
136 	d.end = sds_data + sizeof(sds_data);
137 	if (!db_create(srv, -1, BDADDR_ANY, 0x00000000, &d))
138 		return false;
139 
140 	d.next = bgd_data;
141 	d.end = bgd_data + sizeof(bgd_data);
142 	if (!db_create(srv, -1, BDADDR_ANY, srv->handle++, &d))
143 		return false;
144 
145 	return true;
146 }
147 
148 /*
149  * Iterate through records selected by fd.  rec should point to a NULL
150  * value to start the iteration, and false will be returned when there
151  * are no more records to return.
152  */
153 bool
db_next(server_t * srv,int fd,record_t ** rec)154 db_next(server_t *srv, int fd, record_t **rec)
155 {
156 	record_t *r;
157 
158 	if (*rec == NULL)
159 		r = LIST_FIRST(&srv->rlist);
160 	else
161 		r = LIST_NEXT(*rec, next);
162 
163 	while (r != NULL && !FD_ISSET(fd, &r->refset))
164 		r = LIST_NEXT(r, next);
165 
166 	*rec = r;
167 	return (r == NULL) ? false : true;
168 }
169 
170 /*
171  * Match a ServiceRecord against a UUID. Note that because we already
172  * know that the record data is valid, we don't need to recurse here
173  * and can just skip over SEQ and ALT headers. Return true if equivalent
174  * UUID is found.
175  */
176 static bool
db_match_uuid(record_t * rec,uuid_t * uuid)177 db_match_uuid(record_t *rec, uuid_t *uuid)
178 {
179 	uint8_t *p = rec->data.next;
180 	uuid_t u;
181 
182 	while (p < rec->data.end) {
183 		switch(*p++) {
184 		case SDP_DATA_NIL:
185 			break;
186 
187 		case SDP_DATA_BOOL:
188 		case SDP_DATA_INT8:
189 		case SDP_DATA_UINT8:
190 		case SDP_DATA_SEQ8:
191 		case SDP_DATA_ALT8:
192 			p += 1;
193 			break;
194 
195 		case SDP_DATA_INT16:
196 		case SDP_DATA_UINT16:
197 		case SDP_DATA_SEQ16:
198 		case SDP_DATA_ALT16:
199 			p += 2;
200 			break;
201 
202 		case SDP_DATA_INT32:
203 		case SDP_DATA_UINT32:
204 		case SDP_DATA_SEQ32:
205 		case SDP_DATA_ALT32:
206 			p += 4;
207 			break;
208 
209 		case SDP_DATA_INT64:
210 		case SDP_DATA_UINT64:
211 			p += 8;
212 			break;
213 
214 		case SDP_DATA_INT128:
215 		case SDP_DATA_UINT128:
216 			p += 16;
217 			break;
218 
219 		case SDP_DATA_STR8:
220 		case SDP_DATA_URL8:
221 			p += 1 + *p;
222 			break;
223 
224 		case SDP_DATA_STR16:
225 		case SDP_DATA_URL16:
226 			p += 2 + be16dec(p);
227 			break;
228 
229 		case SDP_DATA_STR32:
230 		case SDP_DATA_URL32:
231 			p += 4 + be32dec(p);
232 			break;
233 
234 		case SDP_DATA_UUID16:
235 			u = BLUETOOTH_BASE_UUID;
236 			u.time_low = be16dec(p);
237 
238 			if (uuid_equal(&u, uuid, NULL))
239 				return true;
240 
241 			p += 2;
242 			break;
243 
244 		case SDP_DATA_UUID32:
245 			u = BLUETOOTH_BASE_UUID;
246 			u.time_low = be32dec(p);
247 
248 			if (uuid_equal(&u, uuid, NULL))
249 				return true;
250 
251 			p += 4;
252 			break;
253 
254 		case SDP_DATA_UUID128:
255 			uuid_dec_be(p, &u);
256 
257 			if (uuid_equal(&u, uuid, NULL))
258 				return true;
259 
260 			p += 16;
261 			break;
262 
263 		default:
264 			return false;
265 		}
266 	}
267 
268 	return false;
269 }
270 
271 /*
272  * Select ServiceRecords matching ServiceSearchPattern
273  *
274  * A record is selected when it is visible to the client and
275  * contains each and every UUID from the ServiceSearchPattern
276  */
277 void
db_select_ssp(server_t * srv,int fd,sdp_data_t * ssp)278 db_select_ssp(server_t *srv, int fd, sdp_data_t *ssp)
279 {
280 	record_t *r;
281 	sdp_data_t s;
282 	uuid_t u;
283 
284 	LIST_FOREACH(r, &srv->rlist, next) {
285 		if (!r->valid)
286 			continue;
287 
288 		if (!srv->fdidx[fd].control
289 		    && !bdaddr_any(&r->bdaddr)
290 		    && !bdaddr_same(&r->bdaddr, &srv->fdidx[fd].bdaddr))
291 			continue;
292 
293 		s = *ssp;
294 		for (;;) {
295 			if (!sdp_get_uuid(&s, &u)) {
296 				/* matched all UUIDs */
297 				FD_SET(fd, &r->refset);
298 				r->refcnt++;
299 				break;
300 			}
301 
302 			if (!db_match_uuid(r, &u)) {
303 				/* does not match UUID */
304 				break;
305 			}
306 		}
307 	}
308 }
309 
310 /*
311  * Select a ServiceRecord given the RecordHandle.
312  */
313 void
db_select_handle(server_t * srv,int fd,uint32_t handle)314 db_select_handle(server_t *srv, int fd, uint32_t handle)
315 {
316 	record_t *r;
317 
318 	LIST_FOREACH(r, &srv->rlist, next) {
319 		if (!r->valid)
320 			continue;
321 
322 		if (!srv->fdidx[fd].control
323 		    && !bdaddr_any(&r->bdaddr)
324 		    && !bdaddr_same(&r->bdaddr, &srv->fdidx[fd].bdaddr))
325 			continue;
326 
327 		if (handle == r->handle) {
328 			FD_SET(fd, &r->refset);
329 			r->refcnt++;
330 			break;
331 		}
332 	}
333 }
334 
335 /*
336  * Create a record and insert in server record list in ascending handle
337  * order. Where a selectable record exists with the same handle number,
338  * it will be expired.
339  */
340 bool
db_create(server_t * srv,int fd,const bdaddr_t * bdaddr,uint32_t handle,sdp_data_t * data)341 db_create(server_t *srv, int fd, const bdaddr_t *bdaddr, uint32_t handle, sdp_data_t *data)
342 {
343 	record_t *n, *r, *rec;
344 	sdp_data_t d, v;
345 	uint16_t a;
346 	size_t len;
347 
348 	d = *data;
349 	if (!sdp_get_attr(&d, &a, &v)
350 	    || a != SDP_ATTR_SERVICE_RECORD_HANDLE
351 	    || sdp_data_type(&v) != SDP_DATA_UINT32)
352 		return false;
353 
354 	sdp_set_uint(&v, handle);
355 
356 	len = data->end - data->next;
357 	rec = malloc(sizeof(record_t) + len);
358 	if (rec == NULL)
359 		return false;
360 
361 	memset(rec, 0, sizeof(record_t));
362 	FD_ZERO(&rec->refset);
363 	rec->handle = handle;
364 	rec->valid = true;
365 	rec->fd = fd;
366 	bdaddr_copy(&rec->bdaddr, bdaddr);
367 	rec->data.next = rec->ext;
368 	rec->data.end = rec->ext + len;
369 	memcpy(rec->ext, data->next, len);
370 
371 	/*
372 	 * Note, this does not handle the case where we expire
373 	 * the first record on the list, as that won't happen.
374 	 */
375 	n = LIST_FIRST(&srv->rlist);
376 	if (n != NULL) {
377 		do {
378 			r = n;
379 			n = LIST_NEXT(r, next);
380 		} while (n != NULL && n->handle < handle);
381 
382 		if (n != NULL && n->valid && n->handle == handle) {
383 			if (n->refcnt-- == 0) {
384 				LIST_REMOVE(n, next);
385 				free(n);
386 			} else {
387 				n->valid = false;
388 				n->fd = -1;
389 			}
390 		}
391 
392 		LIST_INSERT_AFTER(r, rec, next);
393 	} else {
394 		LIST_INSERT_HEAD(&srv->rlist, rec, next);
395 	}
396 
397 	return true;
398 }
399 
400 /*
401  * Unselect any ServiceRecords selected by fd
402  */
403 void
db_unselect(server_t * srv,int fd)404 db_unselect(server_t *srv, int fd)
405 {
406 	record_t *n, *r;
407 
408 	n = LIST_FIRST(&srv->rlist);
409 	while (n != NULL) {
410 		r = n;
411 		n = LIST_NEXT(r, next);
412 
413 		if (FD_ISSET(fd, &r->refset)) {
414 			if (r->refcnt-- == 0) {
415 				LIST_REMOVE(r, next);
416 				free(r);
417 			} else {
418 				FD_CLR(fd, &r->refset);
419 			}
420 		}
421 	}
422 }
423 
424 /*
425  * Invalidate or release all records owned by fd
426  */
427 void
db_release(server_t * srv,int fd)428 db_release(server_t *srv, int fd)
429 {
430 	record_t *n, *r;
431 
432 	n = LIST_FIRST(&srv->rlist);
433 	while (n != NULL) {
434 		r = n;
435 		n = LIST_NEXT(r, next);
436 
437 		if (r->fd == fd) {
438 			if (r->refcnt-- == 0) {
439 				LIST_REMOVE(r, next);
440 				free(r);
441 			} else {
442 				r->valid = false;
443 				r->fd = -1;
444 			}
445 		}
446 	}
447 }
448