• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2001-2002  Nokia Corporation
6  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
7  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
8  *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com>
9  *
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24  *
25  */
26 
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 
31 #include <stdio.h>
32 #include <errno.h>
33 #include <stdlib.h>
34 #include <assert.h>
35 #include <sys/time.h>
36 #include <sys/socket.h>
37 
38 #include <bluetooth/bluetooth.h>
39 #include <bluetooth/sdp.h>
40 #include <bluetooth/sdp_lib.h>
41 
42 #include <netinet/in.h>
43 
44 #include <glib.h>
45 #include <dbus/dbus.h>
46 
47 #include "sdpd.h"
48 #include "log.h"
49 #include "adapter.h"
50 #include "manager.h"
51 
52 static sdp_record_t *server = NULL;
53 
54 /*
55  * List of version numbers supported by the SDP server.
56  * Add to this list when newer versions are supported.
57  */
58 static sdp_version_t sdpVnumArray[1] = {
59 	{ 1, 0 }
60 };
61 static const int sdpServerVnumEntries = 1;
62 
63 /*
64  * A simple function which returns the time of day in
65  * seconds. Used for updating the service db state
66  * attribute of the service record of the SDP server
67  */
sdp_get_time(void)68 uint32_t sdp_get_time(void)
69 {
70 	/*
71 	 * To handle failure in gettimeofday, so an old
72 	 * value is returned and service does not fail
73 	 */
74 	static struct timeval tm;
75 
76 	gettimeofday(&tm, NULL);
77 	return (uint32_t) tm.tv_sec;
78 }
79 
80 /*
81  * The service database state is an attribute of the service record
82  * of the SDP server itself. This attribute is guaranteed to
83  * change if any of the contents of the service repository
84  * changes. This function updates the timestamp of value of
85  * the svcDBState attribute
86  * Set the SDP server DB. Simply a timestamp which is the marker
87  * when the DB was modified.
88  */
update_db_timestamp(void)89 static void update_db_timestamp(void)
90 {
91 	uint32_t dbts = sdp_get_time();
92 	sdp_data_t *d = sdp_data_alloc(SDP_UINT32, &dbts);
93 	sdp_attr_replace(server, SDP_ATTR_SVCDB_STATE, d);
94 }
95 
register_public_browse_group(void)96 void register_public_browse_group(void)
97 {
98 	sdp_list_t *browselist;
99 	uuid_t bgscid, pbgid;
100 	sdp_data_t *sdpdata;
101 	sdp_record_t *browse = sdp_record_alloc();
102 
103 	browse->handle = SDP_SERVER_RECORD_HANDLE + 1;
104 
105 	sdp_record_add(BDADDR_ANY, browse);
106 	sdpdata = sdp_data_alloc(SDP_UINT32, &browse->handle);
107 	sdp_attr_add(browse, SDP_ATTR_RECORD_HANDLE, sdpdata);
108 
109 	sdp_uuid16_create(&bgscid, BROWSE_GRP_DESC_SVCLASS_ID);
110 	browselist = sdp_list_append(0, &bgscid);
111 	sdp_set_service_classes(browse, browselist);
112 	sdp_list_free(browselist, 0);
113 
114 	sdp_uuid16_create(&pbgid, PUBLIC_BROWSE_GROUP);
115 	sdp_attr_add_new(browse, SDP_ATTR_GROUP_ID,
116 				SDP_UUID16, &pbgid.value.uuid16);
117 }
118 
119 /*
120  * The SDP server must present its own service record to
121  * the service repository. This can be accessed by service
122  * discovery clients. This method constructs a service record
123  * and stores it in the repository
124  */
register_server_service(void)125 void register_server_service(void)
126 {
127 	sdp_list_t *classIDList;
128 	uuid_t classID;
129 	void **versions, **versionDTDs;
130 	uint8_t dtd;
131 	sdp_data_t *pData;
132 	int i;
133 
134 	server = sdp_record_alloc();
135 	server->pattern = NULL;
136 
137 	/* Force the record to be SDP_SERVER_RECORD_HANDLE */
138 	server->handle = SDP_SERVER_RECORD_HANDLE;
139 
140 	sdp_record_add(BDADDR_ANY, server);
141 	sdp_attr_add(server, SDP_ATTR_RECORD_HANDLE,
142 				sdp_data_alloc(SDP_UINT32, &server->handle));
143 
144 	sdp_uuid16_create(&classID, SDP_SERVER_SVCLASS_ID);
145 	classIDList = sdp_list_append(0, &classID);
146 	sdp_set_service_classes(server, classIDList);
147 	sdp_list_free(classIDList, 0);
148 
149 	/*
150 	 * Set the version numbers supported, these are passed as arguments
151 	 * to the server on command line. Now defaults to 1.0
152 	 * Build the version number sequence first
153 	 */
154 	versions = malloc(sdpServerVnumEntries * sizeof(void *));
155 	versionDTDs = malloc(sdpServerVnumEntries * sizeof(void *));
156 	dtd = SDP_UINT16;
157 	for (i = 0; i < sdpServerVnumEntries; i++) {
158 		uint16_t *version = malloc(sizeof(uint16_t));
159 		*version = sdpVnumArray[i].major;
160 		*version = (*version << 8);
161 		*version |= sdpVnumArray[i].minor;
162 		versions[i] = version;
163 		versionDTDs[i] = &dtd;
164 	}
165 	pData = sdp_seq_alloc(versionDTDs, versions, sdpServerVnumEntries);
166 	for (i = 0; i < sdpServerVnumEntries; i++)
167 		free(versions[i]);
168 	free(versions);
169 	free(versionDTDs);
170 	sdp_attr_add(server, SDP_ATTR_VERSION_NUM_LIST, pData);
171 
172 	update_db_timestamp();
173 }
174 
register_device_id(const uint16_t vendor,const uint16_t product,const uint16_t version)175 void register_device_id(const uint16_t vendor, const uint16_t product,
176 						const uint16_t version)
177 {
178 	const uint16_t spec = 0x0102, source = 0x0002;
179 	const uint8_t primary = 1;
180 	sdp_list_t *class_list, *group_list, *profile_list;
181 	uuid_t class_uuid, group_uuid;
182 	sdp_data_t *sdp_data, *primary_data, *source_data;
183 	sdp_data_t *spec_data, *vendor_data, *product_data, *version_data;
184 	sdp_profile_desc_t profile;
185 	sdp_record_t *record = sdp_record_alloc();
186 
187 	info("Adding device id record for %04x:%04x", vendor, product);
188 
189 	btd_manager_set_did(vendor, product, version);
190 
191 	record->handle = sdp_next_handle();
192 
193 	sdp_record_add(BDADDR_ANY, record);
194 	sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle);
195 	sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data);
196 
197 	sdp_uuid16_create(&class_uuid, PNP_INFO_SVCLASS_ID);
198 	class_list = sdp_list_append(0, &class_uuid);
199 	sdp_set_service_classes(record, class_list);
200 	sdp_list_free(class_list, NULL);
201 
202 	sdp_uuid16_create(&group_uuid, PUBLIC_BROWSE_GROUP);
203 	group_list = sdp_list_append(NULL, &group_uuid);
204 	sdp_set_browse_groups(record, group_list);
205 	sdp_list_free(group_list, NULL);
206 
207 	sdp_uuid16_create(&profile.uuid, PNP_INFO_PROFILE_ID);
208 	profile.version = spec;
209 	profile_list = sdp_list_append(NULL, &profile);
210 	sdp_set_profile_descs(record, profile_list);
211 	sdp_list_free(profile_list, NULL);
212 
213 	spec_data = sdp_data_alloc(SDP_UINT16, &spec);
214 	sdp_attr_add(record, 0x0200, spec_data);
215 
216 	vendor_data = sdp_data_alloc(SDP_UINT16, &vendor);
217 	sdp_attr_add(record, 0x0201, vendor_data);
218 
219 	product_data = sdp_data_alloc(SDP_UINT16, &product);
220 	sdp_attr_add(record, 0x0202, product_data);
221 
222 	version_data = sdp_data_alloc(SDP_UINT16, &version);
223 	sdp_attr_add(record, 0x0203, version_data);
224 
225 	primary_data = sdp_data_alloc(SDP_BOOL, &primary);
226 	sdp_attr_add(record, 0x0204, primary_data);
227 
228 	source_data = sdp_data_alloc(SDP_UINT16, &source);
229 	sdp_attr_add(record, 0x0205, source_data);
230 
231 	update_db_timestamp();
232 }
233 
add_record_to_server(const bdaddr_t * src,sdp_record_t * rec)234 int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec)
235 {
236 	sdp_data_t *data;
237 	sdp_list_t *pattern;
238 
239 	if (rec->handle == 0xffffffff) {
240 		rec->handle = sdp_next_handle();
241 		if (rec->handle < 0x10000)
242 			return -ENOSPC;
243 	} else {
244 		if (sdp_record_find(rec->handle))
245 			return -EEXIST;
246 	}
247 
248 	DBG("Adding record with handle 0x%05x", rec->handle);
249 
250 	sdp_record_add(src, rec);
251 
252 	data = sdp_data_alloc(SDP_UINT32, &rec->handle);
253 	sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, data);
254 
255 	if (sdp_data_get(rec, SDP_ATTR_BROWSE_GRP_LIST) == NULL) {
256 		uuid_t uuid;
257 		sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
258 		sdp_pattern_add_uuid(rec, &uuid);
259 	}
260 
261 	for (pattern = rec->pattern; pattern; pattern = pattern->next) {
262 		char uuid[32];
263 
264 		if (pattern->data == NULL)
265 			continue;
266 
267 		sdp_uuid2strn((uuid_t *) pattern->data, uuid, sizeof(uuid));
268 		DBG("Record pattern UUID %s", uuid);
269 	}
270 
271 	update_db_timestamp();
272 
273 	return 0;
274 }
275 
remove_record_from_server(uint32_t handle)276 int remove_record_from_server(uint32_t handle)
277 {
278 	sdp_record_t *rec;
279 
280 	DBG("Removing record with handle 0x%05x", handle);
281 
282 	rec = sdp_record_find(handle);
283 	if (!rec)
284 		return -ENOENT;
285 
286 	if (sdp_record_remove(handle) == 0)
287 		update_db_timestamp();
288 
289 	sdp_record_free(rec);
290 
291 	return 0;
292 }
293 
294 /* FIXME: refactor for server-side */
extract_pdu_server(bdaddr_t * device,uint8_t * p,unsigned int bufsize,uint32_t handleExpected,int * scanned)295 static sdp_record_t *extract_pdu_server(bdaddr_t *device, uint8_t *p,
296 					unsigned int bufsize,
297 					uint32_t handleExpected, int *scanned)
298 {
299 	int extractStatus = -1, localExtractedLength = 0;
300 	uint8_t dtd;
301 	int seqlen = 0;
302 	sdp_record_t *rec = NULL;
303 	uint16_t attrId, lookAheadAttrId;
304 	sdp_data_t *pAttr = NULL;
305 	uint32_t handle = 0xffffffff;
306 
307 	*scanned = sdp_extract_seqtype(p, bufsize, &dtd, &seqlen);
308 	p += *scanned;
309 	bufsize -= *scanned;
310 
311 	if (bufsize < sizeof(uint8_t) + sizeof(uint8_t)) {
312 		SDPDBG("Unexpected end of packet");
313 		return NULL;
314 	}
315 
316 	lookAheadAttrId = ntohs(bt_get_unaligned((uint16_t *) (p + sizeof(uint8_t))));
317 
318 	SDPDBG("Look ahead attr id : %d", lookAheadAttrId);
319 
320 	if (lookAheadAttrId == SDP_ATTR_RECORD_HANDLE) {
321 		if (bufsize < (sizeof(uint8_t) * 2) +
322 					sizeof(uint16_t) + sizeof(uint32_t)) {
323 			SDPDBG("Unexpected end of packet");
324 			return NULL;
325 		}
326 		handle = ntohl(bt_get_unaligned((uint32_t *) (p +
327 				sizeof(uint8_t) + sizeof(uint16_t) +
328 				sizeof(uint8_t))));
329 		SDPDBG("SvcRecHandle : 0x%x", handle);
330 		rec = sdp_record_find(handle);
331 	} else if (handleExpected != 0xffffffff)
332 		rec = sdp_record_find(handleExpected);
333 
334 	if (!rec) {
335 		rec = sdp_record_alloc();
336 		rec->attrlist = NULL;
337 		if (lookAheadAttrId == SDP_ATTR_RECORD_HANDLE) {
338 			rec->handle = handle;
339 			sdp_record_add(device, rec);
340 		} else if (handleExpected != 0xffffffff) {
341 			rec->handle = handleExpected;
342 			sdp_record_add(device, rec);
343 		}
344 	} else {
345 		sdp_list_free(rec->attrlist, (sdp_free_func_t) sdp_data_free);
346 		rec->attrlist = NULL;
347 	}
348 
349 	while (localExtractedLength < seqlen) {
350 		int attrSize = sizeof(uint8_t);
351 		int attrValueLength = 0;
352 
353 		if (bufsize < attrSize + sizeof(uint16_t)) {
354 			SDPDBG("Unexpected end of packet: Terminating extraction of attributes");
355 			break;
356 		}
357 
358 		SDPDBG("Extract PDU, sequenceLength: %d localExtractedLength: %d",
359 							seqlen, localExtractedLength);
360 		dtd = *(uint8_t *) p;
361 
362 		attrId = ntohs(bt_get_unaligned((uint16_t *) (p + attrSize)));
363 		attrSize += sizeof(uint16_t);
364 
365 		SDPDBG("DTD of attrId : %d Attr id : 0x%x", dtd, attrId);
366 
367 		pAttr = sdp_extract_attr(p + attrSize, bufsize - attrSize,
368 							&attrValueLength, rec);
369 
370 		SDPDBG("Attr id : 0x%x attrValueLength : %d", attrId, attrValueLength);
371 
372 		attrSize += attrValueLength;
373 		if (pAttr == NULL) {
374 			SDPDBG("Terminating extraction of attributes");
375 			break;
376 		}
377 		localExtractedLength += attrSize;
378 		p += attrSize;
379 		bufsize -= attrSize;
380 		sdp_attr_replace(rec, attrId, pAttr);
381 		extractStatus = 0;
382 		SDPDBG("Extract PDU, seqLength: %d localExtractedLength: %d",
383 					seqlen, localExtractedLength);
384 	}
385 
386 	if (extractStatus == 0) {
387 		SDPDBG("Successful extracting of Svc Rec attributes");
388 #ifdef SDP_DEBUG
389 		sdp_print_service_attr(rec->attrlist);
390 #endif
391 		*scanned += seqlen;
392 	}
393 	return rec;
394 }
395 
396 /*
397  * Add the newly created service record to the service repository
398  */
service_register_req(sdp_req_t * req,sdp_buf_t * rsp)399 int service_register_req(sdp_req_t *req, sdp_buf_t *rsp)
400 {
401 	int scanned = 0;
402 	sdp_data_t *handle;
403 	uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t);
404 	int bufsize = req->len - sizeof(sdp_pdu_hdr_t);
405 	sdp_record_t *rec;
406 
407 	req->flags = *p++;
408 	if (req->flags & SDP_DEVICE_RECORD) {
409 		bacpy(&req->device, (bdaddr_t *) p);
410 		p += sizeof(bdaddr_t);
411 		bufsize -= sizeof(bdaddr_t);
412 	}
413 
414 	/* save image of PDU: we need it when clients request this attribute */
415 	rec = extract_pdu_server(&req->device, p, bufsize, 0xffffffff, &scanned);
416 	if (!rec)
417 		goto invalid;
418 
419 	if (rec->handle == 0xffffffff) {
420 		rec->handle = sdp_next_handle();
421 		if (rec->handle < 0x10000) {
422 			sdp_record_free(rec);
423 			goto invalid;
424 		}
425 	} else {
426 		if (sdp_record_find(rec->handle)) {
427 			/* extract_pdu_server will add the record handle
428 			 * if it is missing. So instead of failing, skip
429 			 * the record adding to avoid duplication. */
430 			goto success;
431 		}
432 	}
433 
434 	sdp_record_add(&req->device, rec);
435 	if (!(req->flags & SDP_RECORD_PERSIST))
436 		sdp_svcdb_set_collectable(rec, req->sock);
437 
438 	handle = sdp_data_alloc(SDP_UINT32, &rec->handle);
439 	sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, handle);
440 
441 success:
442 	/* if the browse group descriptor is NULL,
443 	 * ensure that the record belongs to the ROOT group */
444 	if (sdp_data_get(rec, SDP_ATTR_BROWSE_GRP_LIST) == NULL) {
445 		uuid_t uuid;
446 		sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
447 		sdp_pattern_add_uuid(rec, &uuid);
448 	}
449 
450 	update_db_timestamp();
451 
452 	/* Build a rsp buffer */
453 	bt_put_unaligned(htonl(rec->handle), (uint32_t *) rsp->data);
454 	rsp->data_size = sizeof(uint32_t);
455 
456 	return 0;
457 
458 invalid:
459 	bt_put_unaligned(htons(SDP_INVALID_SYNTAX), (uint16_t *) rsp->data);
460 	rsp->data_size = sizeof(uint16_t);
461 
462 	return -1;
463 }
464 
465 /*
466  * Update a service record
467  */
service_update_req(sdp_req_t * req,sdp_buf_t * rsp)468 int service_update_req(sdp_req_t *req, sdp_buf_t *rsp)
469 {
470 	sdp_record_t *orec, *nrec;
471 	int status = 0, scanned = 0;
472 	uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t);
473 	int bufsize = req->len - sizeof(sdp_pdu_hdr_t);
474 	uint32_t handle = ntohl(bt_get_unaligned((uint32_t *) p));
475 
476 	SDPDBG("Svc Rec Handle: 0x%x", handle);
477 
478 	p += sizeof(uint32_t);
479 	bufsize -= sizeof(uint32_t);
480 
481 	orec = sdp_record_find(handle);
482 
483 	SDPDBG("SvcRecOld: %p", orec);
484 
485 	if (!orec) {
486 		status = SDP_INVALID_RECORD_HANDLE;
487 		goto done;
488 	}
489 
490 	nrec = extract_pdu_server(BDADDR_ANY, p, bufsize, handle, &scanned);
491 	if (!nrec) {
492 		status = SDP_INVALID_SYNTAX;
493 		goto done;
494 	}
495 
496 	assert(nrec == orec);
497 
498 	update_db_timestamp();
499 
500 done:
501 	p = rsp->data;
502 	bt_put_unaligned(htons(status), (uint16_t *) p);
503 	rsp->data_size = sizeof(uint16_t);
504 	return status;
505 }
506 
507 /*
508  * Remove a registered service record
509  */
service_remove_req(sdp_req_t * req,sdp_buf_t * rsp)510 int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp)
511 {
512 	uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t);
513 	uint32_t handle = ntohl(bt_get_unaligned((uint32_t *) p));
514 	sdp_record_t *rec;
515 	int status = 0;
516 
517 	/* extract service record handle */
518 
519 	rec = sdp_record_find(handle);
520 	if (rec) {
521 		sdp_svcdb_collect(rec);
522 		status = sdp_record_remove(handle);
523 		sdp_record_free(rec);
524 		if (status == 0)
525 			update_db_timestamp();
526 	} else {
527 		status = SDP_INVALID_RECORD_HANDLE;
528 		SDPDBG("Could not find record : 0x%x", handle);
529 	}
530 
531 	p = rsp->data;
532 	bt_put_unaligned(htons(status), (uint16_t *) p);
533 	rsp->data_size = sizeof(uint16_t);
534 
535 	return status;
536 }
537