1 /******************************************************************************
2 *
3 * Copyright 1999-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 /******************************************************************************
20 *
21 * this file contains SDP interface functions
22 *
23 ******************************************************************************/
24
25 #ifndef LOG_TAG
26 #define LOG_TAG "sdp_api"
27 #endif
28
29
30 #include "stack/include/sdp_api.h"
31
32 #include <string.h>
33
34 #include <cstdint>
35 #include "bt_target.h"
36 #include "osi/include/log.h"
37 #include "osi/include/osi.h" // PTR_TO_UINT
38 #include "stack/include/bt_types.h"
39 #include "stack/include/sdp_api.h"
40 #include "stack/sdp/sdpint.h"
41 #include "types/bluetooth/uuid.h"
42 #include "types/raw_address.h"
43
44 using bluetooth::Uuid;
45
46 /**********************************************************************
47 * C L I E N T F U N C T I O N P R O T O T Y P E S *
48 **********************************************************************/
49
50 /*******************************************************************************
51 *
52 * Function SDP_InitDiscoveryDb
53 *
54 * Description This function is called to initialize a discovery database.
55 *
56 * Parameters: p_db - (input) address of an area of memory where the
57 * discovery database is managed.
58 * len - (input) size (in bytes) of the memory
59 * NOTE: This must be larger than
60 * sizeof(tSDP_DISCOVERY_DB)
61 * num_uuid - (input) number of UUID filters applied
62 * p_uuid_list - (input) list of UUID filters
63 * num_attr - (input) number of attribute filters applied
64 * p_attr_list - (input) list of attribute filters
65 *
66 *
67 * Returns bool
68 * true if successful
69 * false if one or more parameters are bad
70 *
71 ******************************************************************************/
SDP_InitDiscoveryDb(tSDP_DISCOVERY_DB * p_db,uint32_t len,uint16_t num_uuid,const Uuid * p_uuid_list,uint16_t num_attr,const uint16_t * p_attr_list)72 bool SDP_InitDiscoveryDb(tSDP_DISCOVERY_DB* p_db, uint32_t len,
73 uint16_t num_uuid, const Uuid* p_uuid_list,
74 uint16_t num_attr, const uint16_t* p_attr_list) {
75 uint16_t xx;
76
77 /* verify the parameters */
78 if (p_db == NULL || (sizeof(tSDP_DISCOVERY_DB) > len) ||
79 num_attr > SDP_MAX_ATTR_FILTERS || num_uuid > SDP_MAX_UUID_FILTERS) {
80 SDP_TRACE_ERROR(
81 "SDP_InitDiscoveryDb Illegal param: p_db 0x%x, len %d, num_uuid %d, "
82 "num_attr %d",
83 PTR_TO_UINT(p_db), len, num_uuid, num_attr);
84
85 return (false);
86 }
87
88 memset(p_db, 0, (size_t)len);
89
90 p_db->mem_size = len - sizeof(tSDP_DISCOVERY_DB);
91 p_db->mem_free = p_db->mem_size;
92 p_db->p_first_rec = NULL;
93 p_db->p_free_mem = (uint8_t*)(p_db + 1);
94
95 for (xx = 0; xx < num_uuid; xx++) p_db->uuid_filters[xx] = *p_uuid_list++;
96
97 p_db->num_uuid_filters = num_uuid;
98
99 for (xx = 0; xx < num_attr; xx++) p_db->attr_filters[xx] = *p_attr_list++;
100
101 /* sort attributes */
102 sdpu_sort_attr_list(num_attr, p_db);
103
104 p_db->num_attr_filters = num_attr;
105 return (true);
106 }
107
108 /*******************************************************************************
109 *
110 * Function SDP_CancelServiceSearch
111 *
112 * Description This function cancels an active query to an SDP server.
113 *
114 * Returns true if discovery cancelled, false if a matching activity is
115 * not found.
116 *
117 ******************************************************************************/
SDP_CancelServiceSearch(const tSDP_DISCOVERY_DB * p_db)118 bool SDP_CancelServiceSearch(const tSDP_DISCOVERY_DB* p_db) {
119 tCONN_CB* p_ccb = sdpu_find_ccb_by_db(p_db);
120 if (!p_ccb) return (false);
121
122 sdp_disconnect(p_ccb, SDP_CANCEL);
123 p_ccb->disc_state = SDP_DISC_WAIT_CANCEL;
124 return (true);
125 }
126
127 /*******************************************************************************
128 *
129 * Function SDP_ServiceSearchRequest
130 *
131 * Description This function queries an SDP server for information.
132 *
133 * Returns true if discovery started, false if failed.
134 *
135 ******************************************************************************/
SDP_ServiceSearchRequest(const RawAddress & p_bd_addr,tSDP_DISCOVERY_DB * p_db,tSDP_DISC_CMPL_CB * p_cb)136 bool SDP_ServiceSearchRequest(const RawAddress& p_bd_addr,
137 tSDP_DISCOVERY_DB* p_db,
138 tSDP_DISC_CMPL_CB* p_cb) {
139 tCONN_CB* p_ccb;
140
141 /* Specific BD address */
142 p_ccb = sdp_conn_originate(p_bd_addr);
143
144 if (!p_ccb) return (false);
145
146 p_ccb->disc_state = SDP_DISC_WAIT_CONN;
147 p_ccb->p_db = p_db;
148 p_ccb->p_cb = p_cb;
149
150 return (true);
151 }
152
153 /*******************************************************************************
154 *
155 * Function SDP_ServiceSearchAttributeRequest
156 *
157 * Description This function queries an SDP server for information.
158 *
159 * The difference between this API function and the function
160 * SDP_ServiceSearchRequest is that this one does a
161 * combined ServiceSearchAttributeRequest SDP function.
162 * (This is for Unplug Testing)
163 *
164 * Returns true if discovery started, false if failed.
165 *
166 ******************************************************************************/
SDP_ServiceSearchAttributeRequest(const RawAddress & p_bd_addr,tSDP_DISCOVERY_DB * p_db,tSDP_DISC_CMPL_CB * p_cb)167 bool SDP_ServiceSearchAttributeRequest(const RawAddress& p_bd_addr,
168 tSDP_DISCOVERY_DB* p_db,
169 tSDP_DISC_CMPL_CB* p_cb) {
170 tCONN_CB* p_ccb;
171
172 /* Specific BD address */
173 p_ccb = sdp_conn_originate(p_bd_addr);
174
175 if (!p_ccb) return (false);
176
177 p_ccb->disc_state = SDP_DISC_WAIT_CONN;
178 p_ccb->p_db = p_db;
179 p_ccb->p_cb = p_cb;
180
181 p_ccb->is_attr_search = true;
182
183 return (true);
184 }
185 /*******************************************************************************
186 *
187 * Function SDP_ServiceSearchAttributeRequest2
188 *
189 * Description This function queries an SDP server for information.
190 *
191 * The difference between this API function and the function
192 * SDP_ServiceSearchRequest is that this one does a
193 * combined ServiceSearchAttributeRequest SDP function.
194 * (This is for Unplug Testing)
195 *
196 * Returns true if discovery started, false if failed.
197 *
198 ******************************************************************************/
SDP_ServiceSearchAttributeRequest2(const RawAddress & p_bd_addr,tSDP_DISCOVERY_DB * p_db,tSDP_DISC_CMPL_CB2 * p_cb2,const void * user_data)199 bool SDP_ServiceSearchAttributeRequest2(const RawAddress& p_bd_addr,
200 tSDP_DISCOVERY_DB* p_db,
201 tSDP_DISC_CMPL_CB2* p_cb2,
202 const void* user_data) {
203 tCONN_CB* p_ccb;
204
205 /* Specific BD address */
206 p_ccb = sdp_conn_originate(p_bd_addr);
207
208 if (!p_ccb) return (false);
209
210 p_ccb->disc_state = SDP_DISC_WAIT_CONN;
211 p_ccb->p_db = p_db;
212 p_ccb->p_cb2 = p_cb2;
213
214 p_ccb->is_attr_search = true;
215 p_ccb->user_data = user_data;
216
217 return (true);
218 }
219
220 /*******************************************************************************
221 *
222 * Function SDP_FindAttributeInRec
223 *
224 * Description This function searches an SDP discovery record for a
225 * specific attribute.
226 *
227 * Returns Pointer to matching attribute entry, or NULL
228 *
229 ******************************************************************************/
SDP_FindAttributeInRec(const tSDP_DISC_REC * p_rec,uint16_t attr_id)230 tSDP_DISC_ATTR* SDP_FindAttributeInRec(const tSDP_DISC_REC* p_rec,
231 uint16_t attr_id) {
232 tSDP_DISC_ATTR* p_attr;
233
234 p_attr = p_rec->p_first_attr;
235 while (p_attr) {
236 if (p_attr->attr_id == attr_id) return (p_attr);
237
238 p_attr = p_attr->p_next_attr;
239 }
240
241 /* If here, no matching attribute found */
242 return (NULL);
243 }
244
245 /*******************************************************************************
246 *
247 * Function SDP_FindServiceUUIDInRec
248 *
249 * Description This function is called to read the service UUID within a
250 * record if there is any.
251 *
252 * Parameters: p_rec - pointer to a SDP record.
253 * p_uuid - output parameter to save the UUID found.
254 *
255 * Returns true if found, otherwise false.
256 *
257 ******************************************************************************/
SDP_FindServiceUUIDInRec(const tSDP_DISC_REC * p_rec,Uuid * p_uuid)258 bool SDP_FindServiceUUIDInRec(const tSDP_DISC_REC* p_rec, Uuid* p_uuid) {
259 tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr;
260
261 p_attr = p_rec->p_first_attr;
262
263 while (p_attr) {
264 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
265 (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
266 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
267 p_sattr = p_sattr->p_next_attr) {
268 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) {
269 if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == Uuid::kNumBytes16) {
270 *p_uuid = Uuid::From16Bit(p_sattr->attr_value.v.u16);
271 } else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) ==
272 Uuid::kNumBytes128) {
273 *p_uuid = Uuid::From128BitBE(p_sattr->attr_value.v.array);
274 } else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) ==
275 Uuid::kNumBytes32) {
276 *p_uuid = Uuid::From32Bit(p_sattr->attr_value.v.u32);
277 }
278
279 return (true);
280 }
281
282 /* Checking for Toyota G Block Car Kit:
283 ** This car kit puts an extra data element sequence
284 ** where the UUID is suppose to be!!!
285 */
286 else {
287 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) ==
288 DATA_ELE_SEQ_DESC_TYPE) {
289 /* Look through data element sequence until no more UUIDs */
290 for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr;
291 p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr) {
292 /* Increment past this to see if the next attribut is UUID */
293 if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) ==
294 UUID_DESC_TYPE)
295 /* only support 16 bits UUID for now */
296 && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2)) {
297 *p_uuid = Uuid::From16Bit(p_extra_sattr->attr_value.v.u16);
298 return (true);
299 }
300 }
301 }
302 }
303 }
304 break;
305 } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
306 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
307 /* only support 16 bits UUID for now */
308 && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2)) {
309 *p_uuid = Uuid::From16Bit(p_attr->attr_value.v.u16);
310 return (true);
311 }
312 }
313 p_attr = p_attr->p_next_attr;
314 }
315 return false;
316 }
317
318 /*******************************************************************************
319 *
320 * Function SDP_FindServiceUUIDInRec_128bit
321 *
322 * Description This function is called to read the 128-bit service UUID
323 * within a record if there is any.
324 *
325 * Parameters: p_rec - pointer to a SDP record.
326 * p_uuid - output parameter to save the UUID found.
327 *
328 * Returns true if found, otherwise false.
329 *
330 ******************************************************************************/
SDP_FindServiceUUIDInRec_128bit(const tSDP_DISC_REC * p_rec,Uuid * p_uuid)331 bool SDP_FindServiceUUIDInRec_128bit(const tSDP_DISC_REC* p_rec, Uuid* p_uuid) {
332 tSDP_DISC_ATTR* p_attr = p_rec->p_first_attr;
333 while (p_attr) {
334 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
335 (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
336 tSDP_DISC_ATTR* p_sattr = p_attr->attr_value.v.p_sub_attr;
337 while (p_sattr) {
338 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) {
339 /* only support 128 bits UUID for now */
340 if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16) {
341 *p_uuid = Uuid::From128BitBE(p_sattr->attr_value.v.array);
342 }
343 return (true);
344 }
345
346 p_sattr = p_sattr->p_next_attr;
347 }
348 break;
349 } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
350 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
351 /* only support 128 bits UUID for now */
352 && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16)) {
353 *p_uuid = Uuid::From128BitBE(p_attr->attr_value.v.array);
354 return (true);
355 }
356 }
357 p_attr = p_attr->p_next_attr;
358 }
359 return false;
360 }
361
362 /*******************************************************************************
363 *
364 * Function SDP_FindServiceInDb
365 *
366 * Description This function queries an SDP database for a specific
367 * service. If the p_start_rec pointer is NULL, it looks from
368 * the beginning of the database, else it continues from the
369 * next record after p_start_rec.
370 *
371 * Returns Pointer to record containing service class, or NULL
372 *
373 ******************************************************************************/
SDP_FindServiceInDb(const tSDP_DISCOVERY_DB * p_db,uint16_t service_uuid,tSDP_DISC_REC * p_start_rec)374 tSDP_DISC_REC* SDP_FindServiceInDb(const tSDP_DISCOVERY_DB* p_db,
375 uint16_t service_uuid,
376 tSDP_DISC_REC* p_start_rec) {
377 tSDP_DISC_REC* p_rec;
378 tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr;
379
380 /* Must have a valid database */
381 if (p_db == NULL) return (NULL);
382
383 if (!p_start_rec)
384 p_rec = p_db->p_first_rec;
385 else
386 p_rec = p_start_rec->p_next_rec;
387
388 while (p_rec) {
389 p_attr = p_rec->p_first_attr;
390 while (p_attr) {
391 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
392 (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) ==
393 DATA_ELE_SEQ_DESC_TYPE)) {
394 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
395 p_sattr = p_sattr->p_next_attr) {
396 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) &&
397 (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)) {
398 SDP_TRACE_DEBUG(
399 "SDP_FindServiceInDb - p_sattr value = 0x%x serviceuuid = 0x%x",
400 p_sattr->attr_value.v.u16, service_uuid);
401 if (service_uuid == UUID_SERVCLASS_HDP_PROFILE) {
402 if ((p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SOURCE) ||
403 (p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SINK)) {
404 SDP_TRACE_DEBUG(
405 "SDP_FindServiceInDb found HDP source or sink\n");
406 return (p_rec);
407 }
408 }
409 }
410
411 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE &&
412 (service_uuid == 0 ||
413 (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2 &&
414 p_sattr->attr_value.v.u16 == service_uuid)))
415 /* for a specific uuid, or any one */
416 {
417 return (p_rec);
418 }
419
420 /* Checking for Toyota G Block Car Kit:
421 ** This car kit puts an extra data element sequence
422 ** where the UUID is suppose to be!!!
423 */
424 else {
425 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) ==
426 DATA_ELE_SEQ_DESC_TYPE) {
427 /* Look through data element sequence until no more UUIDs */
428 for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr;
429 p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr) {
430 /* Increment past this to see if the next attribut is UUID */
431 if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) ==
432 UUID_DESC_TYPE) &&
433 (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2)
434 /* for a specific uuid, or any one */
435 && ((p_extra_sattr->attr_value.v.u16 == service_uuid) ||
436 (service_uuid == 0))) {
437 return (p_rec);
438 }
439 }
440 }
441 }
442 }
443 break;
444 } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
445 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) &&
446 (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2)
447 /* find a specific UUID or anyone */
448 &&
449 ((p_attr->attr_value.v.u16 == service_uuid) || service_uuid == 0))
450 return (p_rec);
451 }
452
453 p_attr = p_attr->p_next_attr;
454 }
455
456 p_rec = p_rec->p_next_rec;
457 }
458 /* If here, no matching UUID found */
459 return (NULL);
460 }
461
462 /*******************************************************************************
463 *
464 * Function SDP_FindServiceInDb_128bit
465 *
466 * Description Query an SDP database for a specific service. If the
467 * p_start_rec pointer is NULL, it looks from the beginning of
468 * the database, else it continues from the next record after
469 * p_start_rec.
470 *
471 * This function is kept separate from SDP_FindServiceInDb
472 * since that API is expected to return only 16-bit UUIDs
473 *
474 * Returns Pointer to record containing service class, or NULL
475 *
476 ******************************************************************************/
SDP_FindServiceInDb_128bit(const tSDP_DISCOVERY_DB * p_db,tSDP_DISC_REC * p_start_rec)477 tSDP_DISC_REC* SDP_FindServiceInDb_128bit(const tSDP_DISCOVERY_DB* p_db,
478 tSDP_DISC_REC* p_start_rec) {
479 tSDP_DISC_REC* p_rec;
480 tSDP_DISC_ATTR *p_attr, *p_sattr;
481
482 /* Must have a valid database */
483 if (p_db == NULL) return (NULL);
484
485 if (!p_start_rec)
486 p_rec = p_db->p_first_rec;
487 else
488 p_rec = p_start_rec->p_next_rec;
489
490 while (p_rec) {
491 p_attr = p_rec->p_first_attr;
492 while (p_attr) {
493 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
494 (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) ==
495 DATA_ELE_SEQ_DESC_TYPE)) {
496 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
497 p_sattr = p_sattr->p_next_attr) {
498 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) &&
499 (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16)) {
500 return (p_rec);
501 }
502 }
503 break;
504 } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
505 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) &&
506 (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16))
507 return (p_rec);
508 }
509
510 p_attr = p_attr->p_next_attr;
511 }
512
513 p_rec = p_rec->p_next_rec;
514 }
515 /* If here, no matching UUID found */
516 return (NULL);
517 }
518
519 /*******************************************************************************
520 *
521 * Function SDP_FindServiceUUIDInDb
522 *
523 * Description Query an SDP database for a specific service. If the
524 * p_start_rec pointer is NULL, it looks from the beginning of
525 * the database, else it continues from the next record after
526 * p_start_rec.
527 *
528 * NOTE the only difference between this function and the previous
529 * function "SDP_FindServiceInDb()" is that this function takes
530 * a Uuid input
531 *
532 * Returns Pointer to record containing service class, or NULL
533 *
534 ******************************************************************************/
SDP_FindServiceUUIDInDb(const tSDP_DISCOVERY_DB * p_db,const Uuid & uuid,tSDP_DISC_REC * p_start_rec)535 tSDP_DISC_REC* SDP_FindServiceUUIDInDb(const tSDP_DISCOVERY_DB* p_db,
536 const Uuid& uuid,
537 tSDP_DISC_REC* p_start_rec) {
538 tSDP_DISC_REC* p_rec;
539 tSDP_DISC_ATTR *p_attr, *p_sattr;
540
541 /* Must have a valid database */
542 if (p_db == NULL) return (NULL);
543
544 if (!p_start_rec)
545 p_rec = p_db->p_first_rec;
546 else
547 p_rec = p_start_rec->p_next_rec;
548
549 while (p_rec) {
550 p_attr = p_rec->p_first_attr;
551 while (p_attr) {
552 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
553 (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) ==
554 DATA_ELE_SEQ_DESC_TYPE)) {
555 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
556 p_sattr = p_sattr->p_next_attr) {
557 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) {
558 if (sdpu_compare_uuid_with_attr(uuid, p_sattr)) return (p_rec);
559 }
560 }
561 break;
562 } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
563 if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) {
564 if (sdpu_compare_uuid_with_attr(uuid, p_attr)) return (p_rec);
565 }
566 }
567
568 p_attr = p_attr->p_next_attr;
569 }
570
571 p_rec = p_rec->p_next_rec;
572 }
573 /* If here, no matching UUID found */
574 return (NULL);
575 }
576
577 /*******************************************************************************
578 *
579 * Function sdp_fill_proto_elem
580 *
581 * Description This function retrieves the protocol element.
582 *
583 * Returns true if found, false if not
584 * If found, the passed protocol list element is filled in.
585 *
586 ******************************************************************************/
sdp_fill_proto_elem(const tSDP_DISC_ATTR * p_attr,uint16_t layer_uuid,tSDP_PROTOCOL_ELEM * p_elem)587 static bool sdp_fill_proto_elem(const tSDP_DISC_ATTR* p_attr,
588 uint16_t layer_uuid,
589 tSDP_PROTOCOL_ELEM* p_elem) {
590 tSDP_DISC_ATTR* p_sattr;
591
592 /* Walk through the protocol descriptor list */
593 for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr;
594 p_attr = p_attr->p_next_attr) {
595 /* Safety check - each entry should itself be a sequence */
596 if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
597 return (false);
598
599 /* Now, see if the entry contains the layer we are interested in */
600 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
601 p_sattr = p_sattr->p_next_attr) {
602 /* SDP_TRACE_DEBUG ("SDP - p_sattr 0x%x, layer_uuid:0x%x, u16:0x%x####",
603 p_sattr, layer_uuid, p_sattr->attr_value.v.u16); */
604
605 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) &&
606 (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) &&
607 (p_sattr->attr_value.v.u16 == layer_uuid)) {
608 /* Bingo. Now fill in the passed element */
609 p_elem->protocol_uuid = layer_uuid;
610 p_elem->num_params = 0;
611
612 /* Store the parameters, if any */
613 for (p_sattr = p_sattr->p_next_attr; p_sattr;
614 p_sattr = p_sattr->p_next_attr) {
615 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) != UINT_DESC_TYPE)
616 break;
617
618 if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)
619 p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u16;
620 else
621 p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u8;
622
623 if (p_elem->num_params >= SDP_MAX_PROTOCOL_PARAMS) break;
624 }
625 return (true);
626 }
627 }
628 }
629
630 return (false);
631 }
632
633 /*******************************************************************************
634 *
635 * Function SDP_FindProtocolListElemInRec
636 *
637 * Description This function looks at a specific discovery record for a
638 * protocol list element.
639 *
640 * Returns true if found, false if not
641 * If found, the passed protocol list element is filled in.
642 *
643 ******************************************************************************/
SDP_FindProtocolListElemInRec(const tSDP_DISC_REC * p_rec,uint16_t layer_uuid,tSDP_PROTOCOL_ELEM * p_elem)644 bool SDP_FindProtocolListElemInRec(const tSDP_DISC_REC* p_rec,
645 uint16_t layer_uuid,
646 tSDP_PROTOCOL_ELEM* p_elem) {
647 tSDP_DISC_ATTR* p_attr;
648
649 p_attr = p_rec->p_first_attr;
650 while (p_attr) {
651 /* Find the protocol descriptor list */
652 if ((p_attr->attr_id == ATTR_ID_PROTOCOL_DESC_LIST) &&
653 (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
654 return sdp_fill_proto_elem(p_attr, layer_uuid, p_elem);
655 }
656 p_attr = p_attr->p_next_attr;
657 }
658 /* If here, no match found */
659 return (false);
660 }
661
662 /*******************************************************************************
663 *
664 * Function SDP_FindProfileVersionInRec
665 *
666 * Description This function looks at a specific discovery record for the
667 * Profile list descriptor, and pulls out the version number.
668 * The version number consists of an 8-bit major version and
669 * an 8-bit minor version.
670 *
671 * Returns true if found, false if not
672 * If found, the major and minor version numbers that were
673 * passed in are filled in.
674 *
675 ******************************************************************************/
SDP_FindProfileVersionInRec(const tSDP_DISC_REC * p_rec,uint16_t profile_uuid,uint16_t * p_version)676 bool SDP_FindProfileVersionInRec(const tSDP_DISC_REC* p_rec,
677 uint16_t profile_uuid, uint16_t* p_version) {
678 tSDP_DISC_ATTR *p_attr, *p_sattr;
679
680 p_attr = p_rec->p_first_attr;
681 while (p_attr) {
682 /* Find the profile descriptor list */
683 if ((p_attr->attr_id == ATTR_ID_BT_PROFILE_DESC_LIST) &&
684 (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
685 /* Walk through the protocol descriptor list */
686 for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr;
687 p_attr = p_attr->p_next_attr) {
688 /* Safety check - each entry should itself be a sequence */
689 if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
690 return (false);
691
692 /* Now, see if the entry contains the profile UUID we are interested in
693 */
694 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
695 p_sattr = p_sattr->p_next_attr) {
696 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) &&
697 (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) ==
698 2) /* <- This is bytes, not size code! */
699 && (p_sattr->attr_value.v.u16 == profile_uuid)) {
700 /* Now fill in the major and minor numbers */
701 /* if the attribute matches the description for version (type UINT,
702 * size 2 bytes) */
703 p_sattr = p_sattr->p_next_attr;
704
705 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) ==
706 UINT_DESC_TYPE) &&
707 (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)) {
708 /* The high order 8 bits is the major number, low order is the
709 * minor number (big endian) */
710 *p_version = p_sattr->attr_value.v.u16;
711
712 return (true);
713 } else
714 return (false); /* The type and/or size was not valid for the
715 profile list version */
716 }
717 }
718 }
719
720 return (false);
721 }
722 p_attr = p_attr->p_next_attr;
723 }
724
725 /* If here, no match found */
726 return (false);
727 }
728
729 /*******************************************************************************
730 * Device Identification (DI) Client Functions
731 ******************************************************************************/
732
733 /*******************************************************************************
734 *
735 * Function SDP_DiDiscover
736 *
737 * Description This function queries a remote device for DI information.
738 *
739 * Returns SDP_SUCCESS if query started successfully, else error
740 *
741 ******************************************************************************/
SDP_DiDiscover(const RawAddress & remote_device,tSDP_DISCOVERY_DB * p_db,uint32_t len,tSDP_DISC_CMPL_CB * p_cb)742 tSDP_STATUS SDP_DiDiscover(const RawAddress& remote_device,
743 tSDP_DISCOVERY_DB* p_db, uint32_t len,
744 tSDP_DISC_CMPL_CB* p_cb) {
745 tSDP_STATUS result = SDP_DI_DISC_FAILED;
746 uint16_t num_uuids = 1;
747 uint16_t di_uuid = UUID_SERVCLASS_PNP_INFORMATION;
748
749 /* build uuid for db init */
750 Uuid init_uuid = Uuid::From16Bit(di_uuid);
751
752 if (SDP_InitDiscoveryDb(p_db, len, num_uuids, &init_uuid, 0, NULL))
753 if (SDP_ServiceSearchRequest(remote_device, p_db, p_cb))
754 result = SDP_SUCCESS;
755
756 return result;
757 }
758
759 /*******************************************************************************
760 *
761 * Function SDP_GetNumDiRecords
762 *
763 * Description Searches specified database for DI records
764 *
765 * Returns number of DI records found
766 *
767 ******************************************************************************/
SDP_GetNumDiRecords(const tSDP_DISCOVERY_DB * p_db)768 uint8_t SDP_GetNumDiRecords(const tSDP_DISCOVERY_DB* p_db) {
769 uint8_t num_records = 0;
770 tSDP_DISC_REC* p_curr_record = NULL;
771
772 do {
773 p_curr_record = SDP_FindServiceInDb(p_db, UUID_SERVCLASS_PNP_INFORMATION,
774 p_curr_record);
775 if (p_curr_record) num_records++;
776 } while (p_curr_record);
777
778 return num_records;
779 }
780
781 /*******************************************************************************
782 *
783 * Function SDP_AttrStringCopy
784 *
785 * Description This function copy given attribute to specified buffer as a
786 * string
787 *
788 * Returns none
789 *
790 ******************************************************************************/
SDP_AttrStringCopy(char * dst,const tSDP_DISC_ATTR * p_attr,uint16_t dst_size,uint8_t expected_type)791 static void SDP_AttrStringCopy(char* dst, const tSDP_DISC_ATTR* p_attr,
792 uint16_t dst_size,
793 uint8_t expected_type) {
794 if (dst == NULL)
795 return;
796
797 dst[0] = '\0';
798
799 if (p_attr) {
800 uint8_t type = SDP_DISC_ATTR_TYPE(p_attr->attr_len_type);
801
802 if (type == expected_type) {
803 uint16_t len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
804 if (len > dst_size - 1) {
805 len = dst_size - 1;
806 }
807 memcpy(dst, (const void*)p_attr->attr_value.v.array, len);
808 dst[len] = '\0';
809 } else {
810 LOG_ERROR("unexpected attr type=%d, expected=%d",
811 type, expected_type);
812 }
813 } else {
814 LOG_ERROR("p_attr is NULL");
815 }
816 }
817
818 /*******************************************************************************
819 *
820 * Function SDP_GetDiRecord
821 *
822 * Description This function retrieves a remote device's DI record from
823 * the specified database.
824 *
825 * Returns SDP_SUCCESS if record retrieved, else error
826 *
827 ******************************************************************************/
SDP_GetDiRecord(uint8_t get_record_index,tSDP_DI_GET_RECORD * p_device_info,const tSDP_DISCOVERY_DB * p_db)828 uint16_t SDP_GetDiRecord(uint8_t get_record_index,
829 tSDP_DI_GET_RECORD* p_device_info,
830 const tSDP_DISCOVERY_DB* p_db) {
831 uint16_t result = SDP_NO_DI_RECORD_FOUND;
832 uint8_t curr_record_index = 1;
833
834 tSDP_DISC_REC* p_curr_record = NULL;
835
836 /* find the requested SDP record in the discovery database */
837 do {
838 p_curr_record = SDP_FindServiceInDb(p_db, UUID_SERVCLASS_PNP_INFORMATION,
839 p_curr_record);
840 if (p_curr_record) {
841 if (curr_record_index++ == get_record_index) {
842 result = SDP_SUCCESS;
843 break;
844 }
845 }
846 } while (p_curr_record);
847
848 if (result == SDP_SUCCESS) {
849 /* copy the information from the SDP record to the DI record */
850 tSDP_DISC_ATTR* p_curr_attr = NULL;
851
852 /* ClientExecutableURL is optional */
853 p_curr_attr = SDP_FindAttributeInRec(p_curr_record, ATTR_ID_CLIENT_EXE_URL);
854 SDP_AttrStringCopy(p_device_info->rec.client_executable_url, p_curr_attr,
855 SDP_MAX_ATTR_LEN, URL_DESC_TYPE);
856
857 /* Service Description is optional */
858 /* 5.1.16 ServiceDescription attribute */
859 p_curr_attr =
860 SDP_FindAttributeInRec(p_curr_record, ATTR_ID_SERVICE_DESCRIPTION);
861 SDP_AttrStringCopy(p_device_info->rec.service_description, p_curr_attr,
862 SDP_MAX_ATTR_LEN, TEXT_STR_DESC_TYPE);
863
864 /* DocumentationURL is optional */
865 p_curr_attr =
866 SDP_FindAttributeInRec(p_curr_record, ATTR_ID_DOCUMENTATION_URL);
867 SDP_AttrStringCopy(p_device_info->rec.documentation_url, p_curr_attr,
868 SDP_MAX_ATTR_LEN, URL_DESC_TYPE);
869
870 p_curr_attr =
871 SDP_FindAttributeInRec(p_curr_record, ATTR_ID_SPECIFICATION_ID);
872 if (p_curr_attr &&
873 SDP_DISC_ATTR_TYPE(p_curr_attr->attr_len_type) == UINT_DESC_TYPE &&
874 SDP_DISC_ATTR_LEN(p_curr_attr->attr_len_type) >= 2)
875 p_device_info->spec_id = p_curr_attr->attr_value.v.u16;
876 else
877 result = SDP_ERR_ATTR_NOT_PRESENT;
878
879 p_curr_attr = SDP_FindAttributeInRec(p_curr_record, ATTR_ID_VENDOR_ID);
880 if (p_curr_attr &&
881 SDP_DISC_ATTR_TYPE(p_curr_attr->attr_len_type) == UINT_DESC_TYPE &&
882 SDP_DISC_ATTR_LEN(p_curr_attr->attr_len_type) >= 2)
883 p_device_info->rec.vendor = p_curr_attr->attr_value.v.u16;
884 else
885 result = SDP_ERR_ATTR_NOT_PRESENT;
886
887 p_curr_attr =
888 SDP_FindAttributeInRec(p_curr_record, ATTR_ID_VENDOR_ID_SOURCE);
889 if (p_curr_attr &&
890 SDP_DISC_ATTR_TYPE(p_curr_attr->attr_len_type) == UINT_DESC_TYPE &&
891 SDP_DISC_ATTR_LEN(p_curr_attr->attr_len_type) >= 2)
892 p_device_info->rec.vendor_id_source = p_curr_attr->attr_value.v.u16;
893 else
894 result = SDP_ERR_ATTR_NOT_PRESENT;
895
896 p_curr_attr = SDP_FindAttributeInRec(p_curr_record, ATTR_ID_PRODUCT_ID);
897 if (p_curr_attr &&
898 SDP_DISC_ATTR_TYPE(p_curr_attr->attr_len_type) == UINT_DESC_TYPE &&
899 SDP_DISC_ATTR_LEN(p_curr_attr->attr_len_type) >= 2)
900 p_device_info->rec.product = p_curr_attr->attr_value.v.u16;
901 else
902 result = SDP_ERR_ATTR_NOT_PRESENT;
903
904 p_curr_attr =
905 SDP_FindAttributeInRec(p_curr_record, ATTR_ID_PRODUCT_VERSION);
906 if (p_curr_attr &&
907 SDP_DISC_ATTR_TYPE(p_curr_attr->attr_len_type) == UINT_DESC_TYPE &&
908 SDP_DISC_ATTR_LEN(p_curr_attr->attr_len_type) >= 2)
909 p_device_info->rec.version = p_curr_attr->attr_value.v.u16;
910 else
911 result = SDP_ERR_ATTR_NOT_PRESENT;
912
913 p_curr_attr = SDP_FindAttributeInRec(p_curr_record, ATTR_ID_PRIMARY_RECORD);
914 if (p_curr_attr &&
915 SDP_DISC_ATTR_TYPE(p_curr_attr->attr_len_type) == BOOLEAN_DESC_TYPE &&
916 SDP_DISC_ATTR_LEN(p_curr_attr->attr_len_type) >= 1)
917 p_device_info->rec.primary_record = (bool)p_curr_attr->attr_value.v.u8;
918 else
919 result = SDP_ERR_ATTR_NOT_PRESENT;
920 }
921
922 return result;
923 }
924
925 /*******************************************************************************
926 * Device Identification (DI) Server Functions
927 ******************************************************************************/
928
929 /*******************************************************************************
930 *
931 * Function SDP_SetLocalDiRecord
932 *
933 * Description This function adds a DI record to the local SDP database.
934 *
935 *
936 *
937 * Returns Returns SDP_SUCCESS if record added successfully, else error
938 *
939 ******************************************************************************/
SDP_SetLocalDiRecord(const tSDP_DI_RECORD * p_device_info,uint32_t * p_handle)940 uint16_t SDP_SetLocalDiRecord(const tSDP_DI_RECORD* p_device_info,
941 uint32_t* p_handle) {
942 uint16_t result = SDP_SUCCESS;
943 uint32_t handle;
944 uint16_t di_uuid = UUID_SERVCLASS_PNP_INFORMATION;
945 uint16_t di_specid = BLUETOOTH_DI_SPECIFICATION;
946 uint8_t temp_u16[2];
947 uint8_t* p_temp;
948 uint8_t u8;
949
950 *p_handle = 0;
951 if (p_device_info == NULL) return SDP_ILLEGAL_PARAMETER;
952
953 /* if record is to be primary record, get handle to replace old primary */
954 if (p_device_info->primary_record && sdp_cb.server_db.di_primary_handle)
955 handle = sdp_cb.server_db.di_primary_handle;
956 else {
957 handle = SDP_CreateRecord();
958 if (handle == 0) return SDP_NO_RESOURCES;
959 }
960
961 *p_handle = handle;
962
963 /* build the SDP entry */
964 /* Add the UUID to the Service Class ID List */
965 if (!(SDP_AddServiceClassIdList(handle, 1, &di_uuid)))
966 result = SDP_DI_REG_FAILED;
967
968 /* mandatory */
969 if (result == SDP_SUCCESS) {
970 p_temp = temp_u16;
971 UINT16_TO_BE_STREAM(p_temp, di_specid);
972 if (!(SDP_AddAttribute(handle, ATTR_ID_SPECIFICATION_ID, UINT_DESC_TYPE,
973 sizeof(di_specid), temp_u16)))
974 result = SDP_DI_REG_FAILED;
975 }
976
977 /* optional - if string is null, do not add attribute */
978 if (result == SDP_SUCCESS) {
979 if (p_device_info->client_executable_url[0] != '\0') {
980 if (!((strlen(p_device_info->client_executable_url) + 1 <=
981 SDP_MAX_ATTR_LEN) &&
982 SDP_AddAttribute(
983 handle, ATTR_ID_CLIENT_EXE_URL, URL_DESC_TYPE,
984 (uint32_t)(strlen(p_device_info->client_executable_url) + 1),
985 (uint8_t*)p_device_info->client_executable_url)))
986 result = SDP_DI_REG_FAILED;
987 }
988 }
989
990 /* optional - if string is null, do not add attribute */
991 if (result == SDP_SUCCESS) {
992 if (p_device_info->service_description[0] != '\0') {
993 if (!((strlen(p_device_info->service_description) + 1 <=
994 SDP_MAX_ATTR_LEN) &&
995 SDP_AddAttribute(
996 handle, ATTR_ID_SERVICE_DESCRIPTION, TEXT_STR_DESC_TYPE,
997 (uint32_t)(strlen(p_device_info->service_description) + 1),
998 (uint8_t*)p_device_info->service_description)))
999 result = SDP_DI_REG_FAILED;
1000 }
1001 }
1002
1003 /* optional - if string is null, do not add attribute */
1004 if (result == SDP_SUCCESS) {
1005 if (p_device_info->documentation_url[0] != '\0') {
1006 if (!((strlen(p_device_info->documentation_url) + 1 <=
1007 SDP_MAX_ATTR_LEN) &&
1008 SDP_AddAttribute(
1009 handle, ATTR_ID_DOCUMENTATION_URL, URL_DESC_TYPE,
1010 (uint32_t)(strlen(p_device_info->documentation_url) + 1),
1011 (uint8_t*)p_device_info->documentation_url)))
1012 result = SDP_DI_REG_FAILED;
1013 }
1014 }
1015
1016 /* mandatory */
1017 if (result == SDP_SUCCESS) {
1018 p_temp = temp_u16;
1019 UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor);
1020 if (!(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID, UINT_DESC_TYPE,
1021 sizeof(p_device_info->vendor), temp_u16)))
1022 result = SDP_DI_REG_FAILED;
1023 }
1024
1025 /* mandatory */
1026 if (result == SDP_SUCCESS) {
1027 p_temp = temp_u16;
1028 UINT16_TO_BE_STREAM(p_temp, p_device_info->product);
1029 if (!(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_ID, UINT_DESC_TYPE,
1030 sizeof(p_device_info->product), temp_u16)))
1031 result = SDP_DI_REG_FAILED;
1032 }
1033
1034 /* mandatory */
1035 if (result == SDP_SUCCESS) {
1036 p_temp = temp_u16;
1037 UINT16_TO_BE_STREAM(p_temp, p_device_info->version);
1038 if (!(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_VERSION, UINT_DESC_TYPE,
1039 sizeof(p_device_info->version), temp_u16)))
1040 result = SDP_DI_REG_FAILED;
1041 }
1042
1043 /* mandatory */
1044 if (result == SDP_SUCCESS) {
1045 u8 = (uint8_t)p_device_info->primary_record;
1046 if (!(SDP_AddAttribute(handle, ATTR_ID_PRIMARY_RECORD, BOOLEAN_DESC_TYPE, 1,
1047 &u8)))
1048 result = SDP_DI_REG_FAILED;
1049 }
1050
1051 /* mandatory */
1052 if (result == SDP_SUCCESS) {
1053 p_temp = temp_u16;
1054 UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor_id_source);
1055 if (!(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID_SOURCE, UINT_DESC_TYPE,
1056 sizeof(p_device_info->vendor_id_source), temp_u16)))
1057 result = SDP_DI_REG_FAILED;
1058 }
1059
1060 if (result != SDP_SUCCESS)
1061 SDP_DeleteRecord(handle);
1062 else if (p_device_info->primary_record)
1063 sdp_cb.server_db.di_primary_handle = handle;
1064
1065 return result;
1066 }
1067
1068 /*******************************************************************************
1069 *
1070 * Function SDP_SetTraceLevel
1071 *
1072 * Description This function sets the trace level for SDP. If called with
1073 * a value of 0xFF, it simply reads the current trace level.
1074 *
1075 * Returns the new (current) trace level
1076 *
1077 ******************************************************************************/
SDP_SetTraceLevel(uint8_t new_level)1078 uint8_t SDP_SetTraceLevel(uint8_t new_level) {
1079 if (new_level != 0xFF) sdp_cb.trace_level = new_level;
1080
1081 return (sdp_cb.trace_level);
1082 }
1083
1084 namespace {
1085 bluetooth::legacy::stack::sdp::tSdpApi api_ = {
1086 .service =
1087 {
1088 .SDP_InitDiscoveryDb = ::SDP_InitDiscoveryDb,
1089 .SDP_CancelServiceSearch = ::SDP_CancelServiceSearch,
1090 .SDP_ServiceSearchRequest = ::SDP_ServiceSearchRequest,
1091 .SDP_ServiceSearchAttributeRequest =
1092 ::SDP_ServiceSearchAttributeRequest,
1093 .SDP_ServiceSearchAttributeRequest2 =
1094 ::SDP_ServiceSearchAttributeRequest2,
1095 },
1096 .db =
1097 {
1098 .SDP_FindServiceInDb = ::SDP_FindServiceInDb,
1099 .SDP_FindServiceUUIDInDb = ::SDP_FindServiceUUIDInDb,
1100 .SDP_FindServiceInDb_128bit = ::SDP_FindServiceInDb_128bit,
1101 },
1102 .record =
1103 {
1104 .SDP_FindAttributeInRec = ::SDP_FindAttributeInRec,
1105 .SDP_FindServiceUUIDInRec_128bit =
1106 ::SDP_FindServiceUUIDInRec_128bit,
1107 .SDP_FindProtocolListElemInRec = ::SDP_FindProtocolListElemInRec,
1108 .SDP_FindProfileVersionInRec = ::SDP_FindProfileVersionInRec,
1109 .SDP_FindServiceUUIDInRec = ::SDP_FindServiceUUIDInRec,
1110 },
1111 .handle =
1112 {
1113 .SDP_CreateRecord = ::SDP_CreateRecord,
1114 .SDP_DeleteRecord = ::SDP_DeleteRecord,
1115 .SDP_AddAttribute = ::SDP_AddAttribute,
1116 .SDP_AddSequence = ::SDP_AddSequence,
1117 .SDP_AddUuidSequence = ::SDP_AddUuidSequence,
1118 .SDP_AddProtocolList = ::SDP_AddProtocolList,
1119 .SDP_AddAdditionProtoLists = ::SDP_AddAdditionProtoLists,
1120 .SDP_AddProfileDescriptorList = ::SDP_AddProfileDescriptorList,
1121 .SDP_AddLanguageBaseAttrIDList = ::SDP_AddLanguageBaseAttrIDList,
1122 .SDP_AddServiceClassIdList = ::SDP_AddServiceClassIdList,
1123 .SDP_DeleteAttribute = ::SDP_DeleteAttribute,
1124 },
1125 .device_id =
1126 {
1127 .SDP_SetLocalDiRecord = ::SDP_SetLocalDiRecord,
1128 .SDP_DiDiscover = ::SDP_DiDiscover,
1129 .SDP_GetNumDiRecords = ::SDP_GetNumDiRecords,
1130 .SDP_GetDiRecord = ::SDP_GetDiRecord,
1131 },
1132 };
1133 } // namespace
1134
1135 const bluetooth::legacy::stack::sdp::tSdpApi*
get_legacy_stack_sdp_api()1136 bluetooth::legacy::stack::sdp::get_legacy_stack_sdp_api() {
1137 return &api_;
1138 }
1139