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