Home | History | Annotate | Download | only in src
      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 (at) qualcomm.com>
      7  *  Copyright (C) 2002-2009  Marcel Holtmann <marcel (at) holtmann.org>
      8  *  Copyright (C) 2002-2003  Stephen Crane <steve.crane (at) 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  */
     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  */
     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 
    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 
    164 uint8_t get_service_classes(const bdaddr_t *bdaddr)
    165 {
    166 	return service_classes;
    167 }
    168 
    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 
    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  */
    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 
    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 
    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 
    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 */
    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  */
    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  */
    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  */
    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