• 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-2009  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 "logging.h"
49 #include "manager.h"
50 
51 static sdp_record_t *server = NULL;
52 
53 static uint8_t service_classes = 0x00;
54 
55 static uint16_t did_vendor = 0x0000;
56 static uint16_t did_product = 0x0000;
57 static uint16_t did_version = 0x0000;
58 
59 /*
60  * List of version numbers supported by the SDP server.
61  * Add to this list when newer versions are supported.
62  */
63 static sdp_version_t sdpVnumArray[1] = {
64 	{ 1, 0 }
65 };
66 static const int sdpServerVnumEntries = 1;
67 
68 /*
69  * A simple function which returns the time of day in
70  * seconds. Used for updating the service db state
71  * attribute of the service record of the SDP server
72  */
sdp_get_time()73 uint32_t sdp_get_time()
74 {
75 	/*
76 	 * To handle failure in gettimeofday, so an old
77 	 * value is returned and service does not fail
78 	 */
79 	static struct timeval tm;
80 
81 	gettimeofday(&tm, NULL);
82 	return (uint32_t) tm.tv_sec;
83 }
84 
85 /*
86  * The service database state is an attribute of the service record
87  * of the SDP server itself. This attribute is guaranteed to
88  * change if any of the contents of the service repository
89  * changes. This function updates the timestamp of value of
90  * the svcDBState attribute
91  * Set the SDP server DB. Simply a timestamp which is the marker
92  * when the DB was modified.
93  */
update_db_timestamp(void)94 static void update_db_timestamp(void)
95 {
96 	uint32_t dbts = sdp_get_time();
97 	sdp_data_t *d = sdp_data_alloc(SDP_UINT32, &dbts);
98 	sdp_attr_replace(server, SDP_ATTR_SVCDB_STATE, d);
99 }
100 
update_svclass_list(const bdaddr_t * src)101 static void update_svclass_list(const bdaddr_t *src)
102 {
103 	sdp_list_t *list = sdp_get_record_list();
104 	uint8_t val = 0;
105 
106 	for (; list; list = list->next) {
107 		sdp_record_t *rec = (sdp_record_t *) list->data;
108 
109 		if (rec->svclass.type != SDP_UUID16)
110 			continue;
111 
112 		switch (rec->svclass.value.uuid16) {
113 		case DIALUP_NET_SVCLASS_ID:
114 		case CIP_SVCLASS_ID:
115 			val |= 0x42;	/* Telephony & Networking */
116 			break;
117 		case IRMC_SYNC_SVCLASS_ID:
118 		case OBEX_OBJPUSH_SVCLASS_ID:
119 		case OBEX_FILETRANS_SVCLASS_ID:
120 		case IRMC_SYNC_CMD_SVCLASS_ID:
121 		case PBAP_PSE_SVCLASS_ID:
122 			val |= 0x10;	/* Object Transfer */
123 			break;
124 		case HEADSET_SVCLASS_ID:
125 		case HANDSFREE_SVCLASS_ID:
126 			val |= 0x20;	/* Audio */
127 			break;
128 		case CORDLESS_TELEPHONY_SVCLASS_ID:
129 		case INTERCOM_SVCLASS_ID:
130 		case FAX_SVCLASS_ID:
131 		case SAP_SVCLASS_ID:
132 		/*
133 		 * Setting the telephony bit for the handsfree audio gateway
134 		 * role is not required by the HFP specification, but the
135 		 * Nokia 616 carkit is just plain broken! It will refuse
136 		 * pairing without this bit set.
137 		 */
138 		case HANDSFREE_AGW_SVCLASS_ID:
139 			val |= 0x40;	/* Telephony */
140 			break;
141 		case AUDIO_SOURCE_SVCLASS_ID:
142 		case VIDEO_SOURCE_SVCLASS_ID:
143 			val |= 0x08;	/* Capturing */
144 			break;
145 		case AUDIO_SINK_SVCLASS_ID:
146 		case VIDEO_SINK_SVCLASS_ID:
147 			val |= 0x04;	/* Rendering */
148 			break;
149 		case PANU_SVCLASS_ID:
150 		case NAP_SVCLASS_ID:
151 		case GN_SVCLASS_ID:
152 			val |= 0x02;	/* Networking */
153 			break;
154 		}
155 	}
156 
157 	SDPDBG("Service classes 0x%02x", val);
158 
159 	service_classes = val;
160 
161 	manager_update_svc(src, val);
162 }
163 
get_service_classes(const bdaddr_t * bdaddr)164 uint8_t get_service_classes(const bdaddr_t *bdaddr)
165 {
166 	return service_classes;
167 }
168 
create_ext_inquiry_response(const char * name,uint8_t * data)169 void create_ext_inquiry_response(const char *name, uint8_t *data)
170 {
171 	sdp_list_t *list = sdp_get_record_list();
172 	uint8_t *ptr = data;
173 	uint16_t uuid[24];
174 	int i, index = 0;
175 
176 	if (name) {
177 		int len = strlen(name);
178 
179 		if (len > 48) {
180 			len = 48;
181 			ptr[1] = 0x08;
182 		} else
183 			ptr[1] = 0x09;
184 
185 		ptr[0] = len + 1;
186 
187 		memcpy(ptr + 2, name, len);
188 
189 		ptr += len + 2;
190 	}
191 
192 	if (did_vendor != 0x0000) {
193 		uint16_t source = 0x0002;
194 		*ptr++ = 9;
195 		*ptr++ = 11;
196 		*ptr++ = (source & 0x00ff);
197 		*ptr++ = (source & 0xff00) >> 8;
198 		*ptr++ = (did_vendor & 0x00ff);
199 		*ptr++ = (did_vendor & 0xff00) >> 8;
200 		*ptr++ = (did_product & 0x00ff);
201 		*ptr++ = (did_product & 0xff00) >> 8;
202 		*ptr++ = (did_version & 0x00ff);
203 		*ptr++ = (did_version & 0xff00) >> 8;
204 	}
205 
206 	ptr[1] = 0x03;
207 
208 	for (; list; list = list->next) {
209 		sdp_record_t *rec = (sdp_record_t *) list->data;
210 
211 		if (rec->svclass.type != SDP_UUID16)
212 			continue;
213 
214 		if (rec->svclass.value.uuid16 < 0x1100)
215 			continue;
216 
217 		if (index > 23) {
218 			ptr[1] = 0x02;
219 			break;
220 		}
221 
222 		for (i = 0; i < index; i++)
223 			if (uuid[i] == rec->svclass.value.uuid16)
224 				break;
225 
226 		if (i == index - 1)
227 			continue;
228 
229 		uuid[index++] = rec->svclass.value.uuid16;
230 	}
231 
232 	if (index > 0) {
233 		ptr[0] = (index * 2) + 1;
234 		ptr += 2;
235 
236 		for (i = 0; i < index; i++) {
237 			*ptr++ = (uuid[i] & 0x00ff);
238 			*ptr++ = (uuid[i] & 0xff00) >> 8;
239 		}
240 	}
241 }
242 
register_public_browse_group(void)243 void register_public_browse_group(void)
244 {
245 	sdp_list_t *browselist;
246 	uuid_t bgscid, pbgid;
247 	sdp_data_t *sdpdata;
248 	sdp_record_t *browse = sdp_record_alloc();
249 
250 	browse->handle = SDP_SERVER_RECORD_HANDLE + 1;
251 
252 	sdp_record_add(BDADDR_ANY, browse);
253 	sdpdata = sdp_data_alloc(SDP_UINT32, &browse->handle);
254 	sdp_attr_add(browse, SDP_ATTR_RECORD_HANDLE, sdpdata);
255 
256 	sdp_uuid16_create(&bgscid, BROWSE_GRP_DESC_SVCLASS_ID);
257 	browselist = sdp_list_append(0, &bgscid);
258 	sdp_set_service_classes(browse, browselist);
259 	sdp_list_free(browselist, 0);
260 
261 	sdp_uuid16_create(&pbgid, PUBLIC_BROWSE_GROUP);
262 	sdp_attr_add_new(browse, SDP_ATTR_GROUP_ID,
263 				SDP_UUID16, &pbgid.value.uuid16);
264 }
265 
266 /*
267  * The SDP server must present its own service record to
268  * the service repository. This can be accessed by service
269  * discovery clients. This method constructs a service record
270  * and stores it in the repository
271  */
register_server_service(void)272 void register_server_service(void)
273 {
274 	sdp_list_t *classIDList;
275 	uuid_t classID;
276 	void **versions, **versionDTDs;
277 	uint8_t dtd;
278 	sdp_data_t *pData;
279 	int i;
280 
281 	server = sdp_record_alloc();
282 	server->pattern = NULL;
283 
284 	/* Force the record to be SDP_SERVER_RECORD_HANDLE */
285 	server->handle = SDP_SERVER_RECORD_HANDLE;
286 
287 	sdp_record_add(BDADDR_ANY, server);
288 	sdp_attr_add(server, SDP_ATTR_RECORD_HANDLE,
289 				sdp_data_alloc(SDP_UINT32, &server->handle));
290 
291 	sdp_uuid16_create(&classID, SDP_SERVER_SVCLASS_ID);
292 	classIDList = sdp_list_append(0, &classID);
293 	sdp_set_service_classes(server, classIDList);
294 	sdp_list_free(classIDList, 0);
295 
296 	/*
297 	 * Set the version numbers supported, these are passed as arguments
298 	 * to the server on command line. Now defaults to 1.0
299 	 * Build the version number sequence first
300 	 */
301 	versions = (void **)malloc(sdpServerVnumEntries * sizeof(void *));
302 	versionDTDs = (void **)malloc(sdpServerVnumEntries * sizeof(void *));
303 	dtd = SDP_UINT16;
304 	for (i = 0; i < sdpServerVnumEntries; i++) {
305 		uint16_t *version = malloc(sizeof(uint16_t));
306 		*version = sdpVnumArray[i].major;
307 		*version = (*version << 8);
308 		*version |= sdpVnumArray[i].minor;
309 		versions[i] = version;
310 		versionDTDs[i] = &dtd;
311 	}
312 	pData = sdp_seq_alloc(versionDTDs, versions, sdpServerVnumEntries);
313 	for (i = 0; i < sdpServerVnumEntries; i++)
314 		free(versions[i]);
315 	free(versions);
316 	free(versionDTDs);
317 	sdp_attr_add(server, SDP_ATTR_VERSION_NUM_LIST, pData);
318 
319 	update_db_timestamp();
320 	update_svclass_list(BDADDR_ANY);
321 }
322 
register_device_id(const uint16_t vendor,const uint16_t product,const uint16_t version)323 void register_device_id(const uint16_t vendor, const uint16_t product,
324 						const uint16_t version)
325 {
326 	const uint16_t spec = 0x0102, source = 0x0002;
327 	const uint8_t primary = 1;
328 	sdp_list_t *class_list, *group_list, *profile_list;
329 	uuid_t class_uuid, group_uuid;
330 	sdp_data_t *sdp_data, *primary_data, *source_data;
331 	sdp_data_t *spec_data, *vendor_data, *product_data, *version_data;
332 	sdp_profile_desc_t profile;
333 	sdp_record_t *record = sdp_record_alloc();
334 
335 	info("Adding device id record for %04x:%04x", vendor, product);
336 
337 	did_vendor = vendor;
338 	did_product = product;
339 	did_version = version;
340 
341 	record->handle = sdp_next_handle();
342 
343 	sdp_record_add(BDADDR_ANY, record);
344 	sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle);
345 	sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data);
346 
347 	sdp_uuid16_create(&class_uuid, PNP_INFO_SVCLASS_ID);
348 	class_list = sdp_list_append(0, &class_uuid);
349 	sdp_set_service_classes(record, class_list);
350 	sdp_list_free(class_list, NULL);
351 
352 	sdp_uuid16_create(&group_uuid, PUBLIC_BROWSE_GROUP);
353 	group_list = sdp_list_append(NULL, &group_uuid);
354 	sdp_set_browse_groups(record, group_list);
355 	sdp_list_free(group_list, NULL);
356 
357 	sdp_uuid16_create(&profile.uuid, PNP_INFO_PROFILE_ID);
358 	profile.version = spec;
359 	profile_list = sdp_list_append(NULL, &profile);
360 	sdp_set_profile_descs(record, profile_list);
361 	sdp_list_free(profile_list, NULL);
362 
363 	spec_data = sdp_data_alloc(SDP_UINT16, &spec);
364 	sdp_attr_add(record, 0x0200, spec_data);
365 
366 	vendor_data = sdp_data_alloc(SDP_UINT16, &vendor);
367 	sdp_attr_add(record, 0x0201, vendor_data);
368 
369 	product_data = sdp_data_alloc(SDP_UINT16, &product);
370 	sdp_attr_add(record, 0x0202, product_data);
371 
372 	version_data = sdp_data_alloc(SDP_UINT16, &version);
373 	sdp_attr_add(record, 0x0203, version_data);
374 
375 	primary_data = sdp_data_alloc(SDP_BOOL, &primary);
376 	sdp_attr_add(record, 0x0204, primary_data);
377 
378 	source_data = sdp_data_alloc(SDP_UINT16, &source);
379 	sdp_attr_add(record, 0x0205, source_data);
380 
381 	update_db_timestamp();
382 	update_svclass_list(BDADDR_ANY);
383 }
384 
add_record_to_server(const bdaddr_t * src,sdp_record_t * rec)385 int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec)
386 {
387 	sdp_data_t *data;
388 	sdp_list_t *pattern;
389 
390 	if (rec->handle == 0xffffffff) {
391 		rec->handle = sdp_next_handle();
392 		if (rec->handle < 0x10000)
393 			return -1;
394 	} else {
395 		if (sdp_record_find(rec->handle))
396 			return -1;
397 	}
398 
399 	debug("Adding record with handle 0x%05x", rec->handle);
400 
401 	sdp_record_add(src, rec);
402 
403 	data = sdp_data_alloc(SDP_UINT32, &rec->handle);
404 	sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, data);
405 
406 	if (sdp_data_get(rec, SDP_ATTR_BROWSE_GRP_LIST) == NULL) {
407 		uuid_t uuid;
408 		sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
409 		sdp_pattern_add_uuid(rec, &uuid);
410 	}
411 
412 	for (pattern = rec->pattern; pattern; pattern = pattern->next) {
413 		char uuid[32];
414 
415 		if (pattern->data == NULL)
416 			continue;
417 
418 		sdp_uuid2strn((uuid_t *) pattern->data, uuid, sizeof(uuid));
419 		debug("Record pattern UUID %s", uuid);
420 	}
421 
422 	update_db_timestamp();
423 	update_svclass_list(src);
424 
425 	return 0;
426 }
427 
remove_record_from_server(uint32_t handle)428 int remove_record_from_server(uint32_t handle)
429 {
430 	sdp_record_t *rec;
431 
432 	debug("Removing record with handle 0x%05x", handle);
433 
434 	rec = sdp_record_find(handle);
435 	if (!rec)
436 		return -ENOENT;
437 
438 	if (sdp_record_remove(handle) == 0) {
439 		update_db_timestamp();
440 		update_svclass_list(BDADDR_ANY);
441 	}
442 
443 	sdp_record_free(rec);
444 
445 	return 0;
446 }
447 
448 /* FIXME: refactor for server-side */
extract_pdu_server(bdaddr_t * device,uint8_t * p,unsigned int bufsize,uint32_t handleExpected,int * scanned)449 static sdp_record_t *extract_pdu_server(bdaddr_t *device, uint8_t *p,
450 					unsigned int bufsize,
451 					uint32_t handleExpected, int *scanned)
452 {
453 	int extractStatus = -1, localExtractedLength = 0;
454 	uint8_t dtd;
455 	int seqlen = 0;
456 	sdp_record_t *rec = NULL;
457 	uint16_t attrId, lookAheadAttrId;
458 	sdp_data_t *pAttr = NULL;
459 	uint32_t handle = 0xffffffff;
460 
461 	*scanned = sdp_extract_seqtype(p, bufsize, &dtd, &seqlen);
462 	p += *scanned;
463 	bufsize -= *scanned;
464 
465 	if (bufsize < sizeof(uint8_t) + sizeof(uint8_t)) {
466 		SDPDBG("Unexpected end of packet");
467 		return NULL;
468 	}
469 
470 	lookAheadAttrId = ntohs(bt_get_unaligned((uint16_t *) (p + sizeof(uint8_t))));
471 
472 	SDPDBG("Look ahead attr id : %d", lookAheadAttrId);
473 
474 	if (lookAheadAttrId == SDP_ATTR_RECORD_HANDLE) {
475 		if (bufsize < (sizeof(uint8_t) * 2) +
476 					sizeof(uint16_t) + sizeof(uint32_t)) {
477 			SDPDBG("Unexpected end of packet");
478 			return NULL;
479 		}
480 		handle = ntohl(bt_get_unaligned((uint32_t *) (p +
481 				sizeof(uint8_t) + sizeof(uint16_t) +
482 				sizeof(uint8_t))));
483 		SDPDBG("SvcRecHandle : 0x%x", handle);
484 		rec = sdp_record_find(handle);
485 	} else if (handleExpected != 0xffffffff)
486 		rec = sdp_record_find(handleExpected);
487 
488 	if (!rec) {
489 		rec = sdp_record_alloc();
490 		rec->attrlist = NULL;
491 		if (lookAheadAttrId == SDP_ATTR_RECORD_HANDLE) {
492 			rec->handle = handle;
493 			sdp_record_add(device, rec);
494 		} else if (handleExpected != 0xffffffff) {
495 			rec->handle = handleExpected;
496 			sdp_record_add(device, rec);
497 		}
498 	} else {
499 		sdp_list_free(rec->attrlist, (sdp_free_func_t) sdp_data_free);
500 		rec->attrlist = NULL;
501 	}
502 
503 	while (localExtractedLength < seqlen) {
504 		int attrSize = sizeof(uint8_t);
505 		int attrValueLength = 0;
506 
507 		if (bufsize < attrSize + sizeof(uint16_t)) {
508 			SDPDBG("Unexpected end of packet: Terminating extraction of attributes");
509 			break;
510 		}
511 
512 		SDPDBG("Extract PDU, sequenceLength: %d localExtractedLength: %d",
513 							seqlen, localExtractedLength);
514 		dtd = *(uint8_t *) p;
515 
516 		attrId = ntohs(bt_get_unaligned((uint16_t *) (p + attrSize)));
517 		attrSize += sizeof(uint16_t);
518 
519 		SDPDBG("DTD of attrId : %d Attr id : 0x%x", dtd, attrId);
520 
521 		pAttr = sdp_extract_attr(p + attrSize, bufsize - attrSize,
522 							&attrValueLength, rec);
523 
524 		SDPDBG("Attr id : 0x%x attrValueLength : %d", attrId, attrValueLength);
525 
526 		attrSize += attrValueLength;
527 		if (pAttr == NULL) {
528 			SDPDBG("Terminating extraction of attributes");
529 			break;
530 		}
531 		localExtractedLength += attrSize;
532 		p += attrSize;
533 		bufsize -= attrSize;
534 		sdp_attr_replace(rec, attrId, pAttr);
535 		extractStatus = 0;
536 		SDPDBG("Extract PDU, seqLength: %d localExtractedLength: %d",
537 					seqlen, localExtractedLength);
538 	}
539 
540 	if (extractStatus == 0) {
541 		SDPDBG("Successful extracting of Svc Rec attributes");
542 #ifdef SDP_DEBUG
543 		sdp_print_service_attr(rec->attrlist);
544 #endif
545 		*scanned += seqlen;
546 	}
547 	return rec;
548 }
549 
550 /*
551  * Add the newly created service record to the service repository
552  */
service_register_req(sdp_req_t * req,sdp_buf_t * rsp)553 int service_register_req(sdp_req_t *req, sdp_buf_t *rsp)
554 {
555 	int scanned = 0;
556 	sdp_data_t *handle;
557 	uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t);
558 	int bufsize = req->len - sizeof(sdp_pdu_hdr_t);
559 	sdp_record_t *rec;
560 
561 	req->flags = *p++;
562 	if (req->flags & SDP_DEVICE_RECORD) {
563 		bacpy(&req->device, (bdaddr_t *) p);
564 		p += sizeof(bdaddr_t);
565 		bufsize -= sizeof(bdaddr_t);
566 	}
567 
568 	// save image of PDU: we need it when clients request this attribute
569 	rec = extract_pdu_server(&req->device, p, bufsize, 0xffffffff, &scanned);
570 	if (!rec)
571 		goto invalid;
572 
573 	if (rec->handle == 0xffffffff) {
574 		rec->handle = sdp_next_handle();
575 		if (rec->handle < 0x10000) {
576 			sdp_record_free(rec);
577 			goto invalid;
578 		}
579 	} else {
580 		if (sdp_record_find(rec->handle)) {
581 			/* extract_pdu_server will add the record handle
582 			 * if it is missing. So instead of failing, skip
583 			 * the record adding to avoid duplication. */
584 			goto success;
585 		}
586 	}
587 
588 	sdp_record_add(&req->device, rec);
589 	if (!(req->flags & SDP_RECORD_PERSIST))
590 		sdp_svcdb_set_collectable(rec, req->sock);
591 
592 	handle = sdp_data_alloc(SDP_UINT32, &rec->handle);
593 	sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, handle);
594 
595 success:
596 	/* if the browse group descriptor is NULL,
597 	 * ensure that the record belongs to the ROOT group */
598 	if (sdp_data_get(rec, SDP_ATTR_BROWSE_GRP_LIST) == NULL) {
599 		uuid_t uuid;
600 		sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
601 		sdp_pattern_add_uuid(rec, &uuid);
602 	}
603 
604 	update_db_timestamp();
605 	update_svclass_list(BDADDR_ANY);
606 
607 	/* Build a rsp buffer */
608 	bt_put_unaligned(htonl(rec->handle), (uint32_t *) rsp->data);
609 	rsp->data_size = sizeof(uint32_t);
610 
611 	return 0;
612 
613 invalid:
614 	bt_put_unaligned(htons(SDP_INVALID_SYNTAX), (uint16_t *) rsp->data);
615 	rsp->data_size = sizeof(uint16_t);
616 
617 	return -1;
618 }
619 
620 /*
621  * Update a service record
622  */
service_update_req(sdp_req_t * req,sdp_buf_t * rsp)623 int service_update_req(sdp_req_t *req, sdp_buf_t *rsp)
624 {
625 	sdp_record_t *orec, *nrec;
626 	int status = 0, scanned = 0;
627 	uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t);
628 	int bufsize = req->len - sizeof(sdp_pdu_hdr_t);
629 	uint32_t handle = ntohl(bt_get_unaligned((uint32_t *) p));
630 
631 	SDPDBG("Svc Rec Handle: 0x%x", handle);
632 
633 	p += sizeof(uint32_t);
634 	bufsize -= sizeof(uint32_t);
635 
636 	orec = sdp_record_find(handle);
637 
638 	SDPDBG("SvcRecOld: %p", orec);
639 
640 	if (!orec) {
641 		status = SDP_INVALID_RECORD_HANDLE;
642 		goto done;
643 	}
644 
645 	nrec = extract_pdu_server(BDADDR_ANY, p, bufsize, handle, &scanned);
646 	if (!nrec) {
647 		status = SDP_INVALID_SYNTAX;
648 		goto done;
649 	}
650 
651 	assert(nrec == orec);
652 
653 	update_db_timestamp();
654 	update_svclass_list(BDADDR_ANY);
655 
656 done:
657 	p = rsp->data;
658 	bt_put_unaligned(htons(status), (uint16_t *) p);
659 	rsp->data_size = sizeof(uint16_t);
660 	return status;
661 }
662 
663 /*
664  * Remove a registered service record
665  */
service_remove_req(sdp_req_t * req,sdp_buf_t * rsp)666 int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp)
667 {
668 	uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t);
669 	uint32_t handle = ntohl(bt_get_unaligned((uint32_t *) p));
670 	sdp_record_t *rec;
671 	int status = 0;
672 
673 	/* extract service record handle */
674 	p += sizeof(uint32_t);
675 
676 	rec = sdp_record_find(handle);
677 	if (rec) {
678 		sdp_svcdb_collect(rec);
679 		status = sdp_record_remove(handle);
680 		sdp_record_free(rec);
681 		if (status == 0) {
682 			update_db_timestamp();
683 			update_svclass_list(BDADDR_ANY);
684 		}
685 	} else {
686 		status = SDP_INVALID_RECORD_HANDLE;
687 		SDPDBG("Could not find record : 0x%x", handle);
688 	}
689 
690 	p = rsp->data;
691 	bt_put_unaligned(htons(status), (uint16_t *) p);
692 	rsp->data_size = sizeof(uint16_t);
693 
694 	return status;
695 }
696