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