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