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