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