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