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