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 functions that handle the database
     22  *
     23  ******************************************************************************/
     24 
     25 #include <stdio.h>
     26 #include <stdlib.h>
     27 #include <string.h>
     28 
     29 #include "bt_target.h"
     30 
     31 #include "bt_common.h"
     32 
     33 #include "hcidefs.h"
     34 #include "hcimsgs.h"
     35 #include "l2cdefs.h"
     36 
     37 #include "sdp_api.h"
     38 #include "sdpint.h"
     39 
     40 #if (SDP_SERVER_ENABLED == TRUE)
     41 /******************************************************************************/
     42 /*            L O C A L    F U N C T I O N     P R O T O T Y P E S            */
     43 /******************************************************************************/
     44 static bool find_uuid_in_seq(uint8_t* p, uint32_t seq_len, uint8_t* p_his_uuid,
     45                              uint16_t his_len, int nest_level);
     46 
     47 /*******************************************************************************
     48  *
     49  * Function         sdp_db_service_search
     50  *
     51  * Description      This function searches for a record that contains the
     52  *                  specified UIDs. It is passed either NULL to start at the
     53  *                  beginning, or the previous record found.
     54  *
     55  * Returns          Pointer to the record, or NULL if not found.
     56  *
     57  ******************************************************************************/
     58 tSDP_RECORD* sdp_db_service_search(tSDP_RECORD* p_rec, tSDP_UUID_SEQ* p_seq) {
     59   uint16_t xx, yy;
     60   tSDP_ATTRIBUTE* p_attr;
     61   tSDP_RECORD* p_end = &sdp_cb.server_db.record[sdp_cb.server_db.num_records];
     62 
     63   /* If NULL, start at the beginning, else start at the first specified record
     64    */
     65   if (!p_rec)
     66     p_rec = &sdp_cb.server_db.record[0];
     67   else
     68     p_rec++;
     69 
     70   /* Look through the records. The spec says that a match occurs if */
     71   /* the record contains all the passed UUIDs in it.                */
     72   for (; p_rec < p_end; p_rec++) {
     73     for (yy = 0; yy < p_seq->num_uids; yy++) {
     74       p_attr = &p_rec->attribute[0];
     75       for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++) {
     76         if (p_attr->type == UUID_DESC_TYPE) {
     77           if (sdpu_compare_uuid_arrays(p_attr->value_ptr, p_attr->len,
     78                                        &p_seq->uuid_entry[yy].value[0],
     79                                        p_seq->uuid_entry[yy].len))
     80             break;
     81         } else if (p_attr->type == DATA_ELE_SEQ_DESC_TYPE) {
     82           if (find_uuid_in_seq(p_attr->value_ptr, p_attr->len,
     83                                &p_seq->uuid_entry[yy].value[0],
     84                                p_seq->uuid_entry[yy].len, 0))
     85             break;
     86         }
     87       }
     88       /* If any UUID was not found,  on to the next record */
     89       if (xx == p_rec->num_attributes) break;
     90     }
     91 
     92     /* If every UUID was found in the record, return the record */
     93     if (yy == p_seq->num_uids) return (p_rec);
     94   }
     95 
     96   /* If here, no more records found */
     97   return (NULL);
     98 }
     99 
    100 /*******************************************************************************
    101  *
    102  * Function         find_uuid_in_seq
    103  *
    104  * Description      This function searches a data element sequenct for a UUID.
    105  *
    106  * Returns          true if found, else false
    107  *
    108  ******************************************************************************/
    109 static bool find_uuid_in_seq(uint8_t* p, uint32_t seq_len, uint8_t* p_uuid,
    110                              uint16_t uuid_len, int nest_level) {
    111   uint8_t* p_end = p + seq_len;
    112   uint8_t type;
    113   uint32_t len;
    114 
    115   /* A little safety check to avoid excessive recursion */
    116   if (nest_level > 3) return (false);
    117 
    118   while (p < p_end) {
    119     type = *p++;
    120     p = sdpu_get_len_from_type(p, type, &len);
    121     type = type >> 3;
    122     if (type == UUID_DESC_TYPE) {
    123       if (sdpu_compare_uuid_arrays(p, len, p_uuid, uuid_len)) return (true);
    124     } else if (type == DATA_ELE_SEQ_DESC_TYPE) {
    125       if (find_uuid_in_seq(p, len, p_uuid, uuid_len, nest_level + 1))
    126         return (true);
    127     }
    128     p = p + len;
    129   }
    130 
    131   /* If here, failed to match */
    132   return (false);
    133 }
    134 
    135 /*******************************************************************************
    136  *
    137  * Function         sdp_db_find_record
    138  *
    139  * Description      This function searches for a record with a specific handle
    140  *                  It is passed the handle of the record.
    141  *
    142  * Returns          Pointer to the record, or NULL if not found.
    143  *
    144  ******************************************************************************/
    145 tSDP_RECORD* sdp_db_find_record(uint32_t handle) {
    146   tSDP_RECORD* p_rec;
    147   tSDP_RECORD* p_end = &sdp_cb.server_db.record[sdp_cb.server_db.num_records];
    148 
    149   /* Look through the records for the caller's handle */
    150   for (p_rec = &sdp_cb.server_db.record[0]; p_rec < p_end; p_rec++) {
    151     if (p_rec->record_handle == handle) return (p_rec);
    152   }
    153 
    154   /* Record with that handle not found. */
    155   return (NULL);
    156 }
    157 
    158 /*******************************************************************************
    159  *
    160  * Function         sdp_db_find_attr_in_rec
    161  *
    162  * Description      This function searches a record for specific attributes.
    163  *                  It is passed a pointer to the record. If the record contains
    164  *                  the specified attribute, (the caller may specify be a range
    165  *                  of attributes), the attribute is returned.
    166  *
    167  * Returns          Pointer to the attribute, or NULL if not found.
    168  *
    169  ******************************************************************************/
    170 tSDP_ATTRIBUTE* sdp_db_find_attr_in_rec(tSDP_RECORD* p_rec, uint16_t start_attr,
    171                                         uint16_t end_attr) {
    172   tSDP_ATTRIBUTE* p_at;
    173   uint16_t xx;
    174 
    175   /* Note that the attributes in a record are assumed to be in sorted order */
    176   for (xx = 0, p_at = &p_rec->attribute[0]; xx < p_rec->num_attributes;
    177        xx++, p_at++) {
    178     if ((p_at->id >= start_attr) && (p_at->id <= end_attr)) return (p_at);
    179   }
    180 
    181   /* No matching attribute found */
    182   return (NULL);
    183 }
    184 
    185 /*******************************************************************************
    186  *
    187  * Function         sdp_compose_proto_list
    188  *
    189  * Description      This function is called to compose a data sequence from
    190  *                  protocol element list struct pointer
    191  *
    192  * Returns          the length of the data sequence
    193  *
    194  ******************************************************************************/
    195 static int sdp_compose_proto_list(uint8_t* p, uint16_t num_elem,
    196                                   tSDP_PROTOCOL_ELEM* p_elem_list) {
    197   uint16_t xx, yy, len;
    198   bool is_rfcomm_scn;
    199   uint8_t* p_head = p;
    200   uint8_t* p_len;
    201 
    202   /* First, build the protocol list. This consists of a set of data element
    203   ** sequences, one for each layer. Each layer sequence consists of layer's
    204   ** UUID and optional parameters
    205   */
    206   for (xx = 0; xx < num_elem; xx++, p_elem_list++) {
    207     len = 3 + (p_elem_list->num_params * 3);
    208     UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
    209 
    210     p_len = p;
    211     *p++ = (uint8_t)len;
    212 
    213     UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
    214     UINT16_TO_BE_STREAM(p, p_elem_list->protocol_uuid);
    215 
    216     if (p_elem_list->protocol_uuid == UUID_PROTOCOL_RFCOMM)
    217       is_rfcomm_scn = true;
    218     else
    219       is_rfcomm_scn = false;
    220 
    221     for (yy = 0; yy < p_elem_list->num_params; yy++) {
    222       if (is_rfcomm_scn) {
    223         UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
    224         UINT8_TO_BE_STREAM(p, p_elem_list->params[yy]);
    225 
    226         *p_len -= 1;
    227       } else {
    228         UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
    229         UINT16_TO_BE_STREAM(p, p_elem_list->params[yy]);
    230       }
    231     }
    232   }
    233   return (p - p_head);
    234 }
    235 
    236 #endif /* SDP_SERVER_ENABLED == TRUE */
    237 
    238 /*******************************************************************************
    239  *
    240  * Function         SDP_CreateRecord
    241  *
    242  * Description      This function is called to create a record in the database.
    243  *                  This would be through the SDP database maintenance API. The
    244  *                  record is created empty, teh application should then call
    245  *                  "add_attribute" to add the record's attributes.
    246  *
    247  * Returns          Record handle if OK, else 0.
    248  *
    249  ******************************************************************************/
    250 uint32_t SDP_CreateRecord(void) {
    251 #if (SDP_SERVER_ENABLED == TRUE)
    252   uint32_t handle;
    253   uint8_t buf[4];
    254   tSDP_DB* p_db = &sdp_cb.server_db;
    255 
    256   /* First, check if there is a free record */
    257   if (p_db->num_records < SDP_MAX_RECORDS) {
    258     memset(&p_db->record[p_db->num_records], 0, sizeof(tSDP_RECORD));
    259 
    260     /* We will use a handle of the first unreserved handle plus last record
    261     ** number + 1 */
    262     if (p_db->num_records)
    263       handle = p_db->record[p_db->num_records - 1].record_handle + 1;
    264     else
    265       handle = 0x10000;
    266 
    267     p_db->record[p_db->num_records].record_handle = handle;
    268 
    269     p_db->num_records++;
    270     SDP_TRACE_DEBUG("SDP_CreateRecord ok, num_records:%d", p_db->num_records);
    271     /* Add the first attribute (the handle) automatically */
    272     UINT32_TO_BE_FIELD(buf, handle);
    273     SDP_AddAttribute(handle, ATTR_ID_SERVICE_RECORD_HDL, UINT_DESC_TYPE, 4,
    274                      buf);
    275 
    276     return (p_db->record[p_db->num_records - 1].record_handle);
    277   } else
    278     SDP_TRACE_ERROR("SDP_CreateRecord fail, exceed maximum records:%d",
    279                     SDP_MAX_RECORDS);
    280 #endif
    281   return (0);
    282 }
    283 
    284 /*******************************************************************************
    285  *
    286  * Function         SDP_DeleteRecord
    287  *
    288  * Description      This function is called to add a record (or all records)
    289  *                  from the database. This would be through the SDP database
    290  *                  maintenance API.
    291  *
    292  *                  If a record handle of 0 is passed, all records are deleted.
    293  *
    294  * Returns          true if succeeded, else false
    295  *
    296  ******************************************************************************/
    297 bool SDP_DeleteRecord(uint32_t handle) {
    298 #if (SDP_SERVER_ENABLED == TRUE)
    299   uint16_t xx, yy, zz;
    300   tSDP_RECORD* p_rec = &sdp_cb.server_db.record[0];
    301 
    302   if (handle == 0 || sdp_cb.server_db.num_records == 0) {
    303     /* Delete all records in the database */
    304     sdp_cb.server_db.num_records = 0;
    305 
    306     /* require new DI record to be created in SDP_SetLocalDiRecord */
    307     sdp_cb.server_db.di_primary_handle = 0;
    308 
    309     return (true);
    310   } else {
    311     /* Find the record in the database */
    312     for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++) {
    313       if (p_rec->record_handle == handle) {
    314         /* Found it. Shift everything up one */
    315         for (yy = xx; yy < sdp_cb.server_db.num_records - 1; yy++, p_rec++) {
    316           *p_rec = *(p_rec + 1);
    317 
    318           /* Adjust the attribute value pointer for each attribute */
    319           for (zz = 0; zz < p_rec->num_attributes; zz++)
    320             p_rec->attribute[zz].value_ptr -= sizeof(tSDP_RECORD);
    321         }
    322 
    323         sdp_cb.server_db.num_records--;
    324 
    325         SDP_TRACE_DEBUG("SDP_DeleteRecord ok, num_records:%d",
    326                         sdp_cb.server_db.num_records);
    327         /* if we're deleting the primary DI record, clear the */
    328         /* value in the control block */
    329         if (sdp_cb.server_db.di_primary_handle == handle) {
    330           sdp_cb.server_db.di_primary_handle = 0;
    331         }
    332 
    333         return (true);
    334       }
    335     }
    336   }
    337 #endif
    338   return (false);
    339 }
    340 
    341 /*******************************************************************************
    342  *
    343  * Function         SDP_AddAttribute
    344  *
    345  * Description      This function is called to add an attribute to a record.
    346  *                  This would be through the SDP database maintenance API.
    347  *                  If the attribute already exists in the record, it is
    348  *                  replaced with the new value.
    349  *
    350  * NOTE             Attribute values must be passed as a Big Endian stream.
    351  *
    352  * Returns          true if added OK, else false
    353  *
    354  ******************************************************************************/
    355 bool SDP_AddAttribute(uint32_t handle, uint16_t attr_id, uint8_t attr_type,
    356                       uint32_t attr_len, uint8_t* p_val) {
    357 #if (SDP_SERVER_ENABLED == TRUE)
    358   uint16_t xx, yy, zz;
    359   tSDP_RECORD* p_rec = &sdp_cb.server_db.record[0];
    360 
    361   if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) {
    362     if ((attr_type == UINT_DESC_TYPE) ||
    363         (attr_type == TWO_COMP_INT_DESC_TYPE) ||
    364         (attr_type == UUID_DESC_TYPE) ||
    365         (attr_type == DATA_ELE_SEQ_DESC_TYPE) ||
    366         (attr_type == DATA_ELE_ALT_DESC_TYPE)) {
    367       uint8_t num_array[400];
    368       uint32_t len = (attr_len > 200) ? 200 : attr_len;
    369 
    370       num_array[0] = '\0';
    371       for (uint32_t i = 0; i < len; i++) {
    372         snprintf((char*)&num_array[i * 2], sizeof(num_array) - i * 2, "%02X",
    373                  (uint8_t)(p_val[i]));
    374       }
    375       SDP_TRACE_DEBUG(
    376           "SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, "
    377           "*p_val:%s",
    378           handle, attr_id, attr_type, attr_len, p_val, num_array);
    379     } else if (attr_type == BOOLEAN_DESC_TYPE) {
    380       SDP_TRACE_DEBUG(
    381           "SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, "
    382           "*p_val:%d",
    383           handle, attr_id, attr_type, attr_len, p_val, *p_val);
    384     } else {
    385       SDP_TRACE_DEBUG(
    386           "SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, "
    387           "*p_val:%s",
    388           handle, attr_id, attr_type, attr_len, p_val, p_val);
    389     }
    390   }
    391 
    392   /* Find the record in the database */
    393   for (zz = 0; zz < sdp_cb.server_db.num_records; zz++, p_rec++) {
    394     if (p_rec->record_handle == handle) {
    395       tSDP_ATTRIBUTE* p_attr = &p_rec->attribute[0];
    396 
    397       /* Found the record. Now, see if the attribute already exists */
    398       for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++) {
    399         /* The attribute exists. replace it */
    400         if (p_attr->id == attr_id) {
    401           SDP_DeleteAttribute(handle, attr_id);
    402           break;
    403         }
    404         if (p_attr->id > attr_id) break;
    405       }
    406 
    407       if (p_rec->num_attributes == SDP_MAX_REC_ATTR) return (false);
    408 
    409       /* If not found, see if we can allocate a new entry */
    410       if (xx == p_rec->num_attributes)
    411         p_attr = &p_rec->attribute[p_rec->num_attributes];
    412       else {
    413         /* Since the attributes are kept in sorted order, insert ours here */
    414         for (yy = p_rec->num_attributes; yy > xx; yy--)
    415           p_rec->attribute[yy] = p_rec->attribute[yy - 1];
    416       }
    417 
    418       p_attr->id = attr_id;
    419       p_attr->type = attr_type;
    420       p_attr->len = attr_len;
    421 
    422       if (p_rec->free_pad_ptr + attr_len >= SDP_MAX_PAD_LEN) {
    423         /* do truncate only for text string type descriptor */
    424         if (attr_type == TEXT_STR_DESC_TYPE) {
    425           SDP_TRACE_WARNING(
    426               "SDP_AddAttribute: attr_len:%d too long. truncate to (%d)",
    427               attr_len, SDP_MAX_PAD_LEN - p_rec->free_pad_ptr);
    428 
    429           attr_len = SDP_MAX_PAD_LEN - p_rec->free_pad_ptr;
    430           p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr] = '\0';
    431           p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr + 1] = '\0';
    432         } else
    433           attr_len = 0;
    434       }
    435 
    436       if ((attr_len > 0) && (p_val != 0)) {
    437         p_attr->len = attr_len;
    438         memcpy(&p_rec->attr_pad[p_rec->free_pad_ptr], p_val, (size_t)attr_len);
    439         p_attr->value_ptr = &p_rec->attr_pad[p_rec->free_pad_ptr];
    440         p_rec->free_pad_ptr += attr_len;
    441       } else if ((attr_len == 0 &&
    442                   p_attr->len !=
    443                       0) || /* if truncate to 0 length, simply don't add */
    444                  p_val == 0) {
    445         SDP_TRACE_ERROR(
    446             "SDP_AddAttribute fail, length exceed maximum: ID %d: attr_len:%d ",
    447             attr_id, attr_len);
    448         p_attr->id = p_attr->type = p_attr->len = 0;
    449         return (false);
    450       }
    451       p_rec->num_attributes++;
    452       return (true);
    453     }
    454   }
    455 #endif
    456   return (false);
    457 }
    458 
    459 /*******************************************************************************
    460  *
    461  * Function         SDP_AddSequence
    462  *
    463  * Description      This function is called to add a sequence to a record.
    464  *                  This would be through the SDP database maintenance API.
    465  *                  If the sequence already exists in the record, it is replaced
    466  *                  with the new sequence.
    467  *
    468  * NOTE             Element values must be passed as a Big Endian stream.
    469  *
    470  * Returns          true if added OK, else false
    471  *
    472  ******************************************************************************/
    473 bool SDP_AddSequence(uint32_t handle, uint16_t attr_id, uint16_t num_elem,
    474                      uint8_t type[], uint8_t len[], uint8_t* p_val[]) {
    475 #if (SDP_SERVER_ENABLED == TRUE)
    476   uint16_t xx;
    477   uint8_t* p;
    478   uint8_t* p_head;
    479   bool result;
    480   uint8_t* p_buff =
    481       (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
    482 
    483   p = p_buff;
    484 
    485   /* First, build the sequence */
    486   for (xx = 0; xx < num_elem; xx++) {
    487     p_head = p;
    488     switch (len[xx]) {
    489       case 1:
    490         UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_ONE_BYTE);
    491         break;
    492       case 2:
    493         UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_TWO_BYTES);
    494         break;
    495       case 4:
    496         UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_FOUR_BYTES);
    497         break;
    498       case 8:
    499         UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_EIGHT_BYTES);
    500         break;
    501       case 16:
    502         UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_SIXTEEN_BYTES);
    503         break;
    504       default:
    505         UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_IN_NEXT_BYTE);
    506         UINT8_TO_BE_STREAM(p, len[xx]);
    507         break;
    508     }
    509 
    510     ARRAY_TO_BE_STREAM(p, p_val[xx], len[xx]);
    511 
    512     if (p - p_buff > SDP_MAX_ATTR_LEN) {
    513       /* go back to before we add this element */
    514       p = p_head;
    515       if (p_head == p_buff) {
    516         /* the first element exceed the max length */
    517         SDP_TRACE_ERROR("SDP_AddSequence - too long(attribute is not added)!!");
    518         osi_free(p_buff);
    519         return false;
    520       } else
    521         SDP_TRACE_ERROR("SDP_AddSequence - too long, add %d elements of %d", xx,
    522                         num_elem);
    523       break;
    524     }
    525   }
    526   result = SDP_AddAttribute(handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,
    527                             (uint32_t)(p - p_buff), p_buff);
    528   osi_free(p_buff);
    529   return result;
    530 #else /* SDP_SERVER_ENABLED == FALSE */
    531   return (false);
    532 #endif
    533 }
    534 
    535 /*******************************************************************************
    536  *
    537  * Function         SDP_AddUuidSequence
    538  *
    539  * Description      This function is called to add a UUID sequence to a record.
    540  *                  This would be through the SDP database maintenance API.
    541  *                  If the sequence already exists in the record, it is replaced
    542  *                  with the new sequence.
    543  *
    544  * Returns          true if added OK, else false
    545  *
    546  ******************************************************************************/
    547 bool SDP_AddUuidSequence(uint32_t handle, uint16_t attr_id, uint16_t num_uuids,
    548                          uint16_t* p_uuids) {
    549 #if (SDP_SERVER_ENABLED == TRUE)
    550   uint16_t xx;
    551   uint8_t* p;
    552   int32_t max_len = SDP_MAX_ATTR_LEN - 3;
    553   bool result;
    554   uint8_t* p_buff =
    555       (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
    556 
    557   p = p_buff;
    558 
    559   /* First, build the sequence */
    560   for (xx = 0; xx < num_uuids; xx++, p_uuids++) {
    561     UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
    562     UINT16_TO_BE_STREAM(p, *p_uuids);
    563 
    564     if ((p - p_buff) > max_len) {
    565       SDP_TRACE_WARNING("SDP_AddUuidSequence - too long, add %d uuids of %d",
    566                         xx, num_uuids);
    567       break;
    568     }
    569   }
    570 
    571   result = SDP_AddAttribute(handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,
    572                             (uint32_t)(p - p_buff), p_buff);
    573   osi_free(p_buff);
    574   return result;
    575 #else /* SDP_SERVER_ENABLED == FALSE */
    576   return (false);
    577 #endif
    578 }
    579 
    580 /*******************************************************************************
    581  *
    582  * Function         SDP_AddProtocolList
    583  *
    584  * Description      This function is called to add a protocol descriptor list to
    585  *                  a record. This would be through the SDP database
    586  *                  maintenance API. If the protocol list already exists in the
    587  *                  record, it is replaced with the new list.
    588  *
    589  * Returns          true if added OK, else false
    590  *
    591  ******************************************************************************/
    592 bool SDP_AddProtocolList(uint32_t handle, uint16_t num_elem,
    593                          tSDP_PROTOCOL_ELEM* p_elem_list) {
    594 #if (SDP_SERVER_ENABLED == TRUE)
    595   int offset;
    596   bool result;
    597   uint8_t* p_buff =
    598       (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
    599 
    600   offset = sdp_compose_proto_list(p_buff, num_elem, p_elem_list);
    601   result = SDP_AddAttribute(handle, ATTR_ID_PROTOCOL_DESC_LIST,
    602                             DATA_ELE_SEQ_DESC_TYPE, (uint32_t)offset, p_buff);
    603   osi_free(p_buff);
    604   return result;
    605 #else /* SDP_SERVER_ENABLED == FALSE */
    606   return (false);
    607 #endif
    608 }
    609 
    610 /*******************************************************************************
    611  *
    612  * Function         SDP_AddAdditionProtoLists
    613  *
    614  * Description      This function is called to add a protocol descriptor list to
    615  *                  a record. This would be through the SDP database maintenance
    616  *                  API. If the protocol list already exists in the record, it
    617  *                  is replaced with the new list.
    618  *
    619  * Returns          true if added OK, else false
    620  *
    621  ******************************************************************************/
    622 bool SDP_AddAdditionProtoLists(uint32_t handle, uint16_t num_elem,
    623                                tSDP_PROTO_LIST_ELEM* p_proto_list) {
    624 #if (SDP_SERVER_ENABLED == TRUE)
    625   uint16_t xx;
    626   uint8_t* p;
    627   uint8_t* p_len;
    628   int offset;
    629   bool result;
    630   uint8_t* p_buff =
    631       (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
    632 
    633   p = p_buff;
    634 
    635   /* for each ProtocolDescriptorList */
    636   for (xx = 0; xx < num_elem; xx++, p_proto_list++) {
    637     UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
    638     p_len = p++;
    639 
    640     offset = sdp_compose_proto_list(p, p_proto_list->num_elems,
    641                                     p_proto_list->list_elem);
    642     p += offset;
    643 
    644     *p_len = (uint8_t)(p - p_len - 1);
    645   }
    646   result =
    647       SDP_AddAttribute(handle, ATTR_ID_ADDITION_PROTO_DESC_LISTS,
    648                        DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - p_buff), p_buff);
    649   osi_free(p_buff);
    650   return result;
    651 
    652 #else /* SDP_SERVER_ENABLED == FALSE */
    653   return (false);
    654 #endif
    655 }
    656 
    657 /*******************************************************************************
    658  *
    659  * Function         SDP_AddProfileDescriptorList
    660  *
    661  * Description      This function is called to add a profile descriptor list to
    662  *                  a record. This would be through the SDP database maintenance
    663  *                  API. If the version already exists in the record, it is
    664  *                  replaced with the new one.
    665  *
    666  * Returns          true if added OK, else false
    667  *
    668  ******************************************************************************/
    669 bool SDP_AddProfileDescriptorList(uint32_t handle, uint16_t profile_uuid,
    670                                   uint16_t version) {
    671 #if (SDP_SERVER_ENABLED == TRUE)
    672   uint8_t* p;
    673   bool result;
    674   uint8_t* p_buff = (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN);
    675 
    676   p = p_buff + 2;
    677 
    678   /* First, build the profile descriptor list. This consists of a data element
    679    * sequence. */
    680   /* The sequence consists of profile's UUID and version number  */
    681   UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
    682   UINT16_TO_BE_STREAM(p, profile_uuid);
    683 
    684   UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
    685   UINT16_TO_BE_STREAM(p, version);
    686 
    687   /* Add in type and length fields */
    688   *p_buff = (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
    689   *(p_buff + 1) = (uint8_t)(p - (p_buff + 2));
    690 
    691   result =
    692       SDP_AddAttribute(handle, ATTR_ID_BT_PROFILE_DESC_LIST,
    693                        DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - p_buff), p_buff);
    694   osi_free(p_buff);
    695   return result;
    696 
    697 #else /* SDP_SERVER_ENABLED == FALSE */
    698   return (false);
    699 #endif
    700 }
    701 
    702 /*******************************************************************************
    703  *
    704  * Function         SDP_AddLanguageBaseAttrIDList
    705  *
    706  * Description      This function is called to add a language base attr list to
    707  *                  a record. This would be through the SDP database maintenance
    708  *                  API. If the version already exists in the record, it is
    709  *                  replaced with the new one.
    710  *
    711  * Returns          true if added OK, else false
    712  *
    713  ******************************************************************************/
    714 bool SDP_AddLanguageBaseAttrIDList(uint32_t handle, uint16_t lang,
    715                                    uint16_t char_enc, uint16_t base_id) {
    716 #if (SDP_SERVER_ENABLED == TRUE)
    717   uint8_t* p;
    718   bool result;
    719   uint8_t* p_buff = (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN);
    720 
    721   p = p_buff;
    722 
    723   /* First, build the language base descriptor list. This consists of a data */
    724   /* element sequence. The sequence consists of 9 bytes (3 UINt16 fields)    */
    725   UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
    726   UINT16_TO_BE_STREAM(p, lang);
    727 
    728   UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
    729   UINT16_TO_BE_STREAM(p, char_enc);
    730 
    731   UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
    732   UINT16_TO_BE_STREAM(p, base_id);
    733 
    734   result =
    735       SDP_AddAttribute(handle, ATTR_ID_LANGUAGE_BASE_ATTR_ID_LIST,
    736                        DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - p_buff), p_buff);
    737   osi_free(p_buff);
    738   return result;
    739 #else /* SDP_SERVER_ENABLED == FALSE */
    740   return (false);
    741 #endif
    742 }
    743 
    744 /*******************************************************************************
    745  *
    746  * Function         SDP_AddServiceClassIdList
    747  *
    748  * Description      This function is called to add a service list to a record.
    749  *                  This would be through the SDP database maintenance API.
    750  *                  If the service list already exists in the record, it is
    751  *                  replaced with the new list.
    752  *
    753  * Returns          true if added OK, else false
    754  *
    755  ******************************************************************************/
    756 bool SDP_AddServiceClassIdList(uint32_t handle, uint16_t num_services,
    757                                uint16_t* p_service_uuids) {
    758 #if (SDP_SERVER_ENABLED == TRUE)
    759   uint16_t xx;
    760   uint8_t* p;
    761   bool result;
    762   uint8_t* p_buff =
    763       (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
    764 
    765   p = p_buff;
    766 
    767   for (xx = 0; xx < num_services; xx++, p_service_uuids++) {
    768     UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
    769     UINT16_TO_BE_STREAM(p, *p_service_uuids);
    770   }
    771 
    772   result =
    773       SDP_AddAttribute(handle, ATTR_ID_SERVICE_CLASS_ID_LIST,
    774                        DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - p_buff), p_buff);
    775   osi_free(p_buff);
    776   return result;
    777 #else /* SDP_SERVER_ENABLED == FALSE */
    778   return (false);
    779 #endif
    780 }
    781 
    782 /*******************************************************************************
    783  *
    784  * Function         SDP_DeleteAttribute
    785  *
    786  * Description      This function is called to delete an attribute from a
    787  *                  record. This would be through the SDP database maintenance
    788  *                  API.
    789  *
    790  * Returns          true if deleted OK, else false if not found
    791  *
    792  ******************************************************************************/
    793 bool SDP_DeleteAttribute(uint32_t handle, uint16_t attr_id) {
    794 #if (SDP_SERVER_ENABLED == TRUE)
    795   uint16_t xx, yy;
    796   tSDP_RECORD* p_rec = &sdp_cb.server_db.record[0];
    797   uint8_t* pad_ptr;
    798   uint32_t len; /* Number of bytes in the entry */
    799 
    800   /* Find the record in the database */
    801   for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++) {
    802     if (p_rec->record_handle == handle) {
    803       tSDP_ATTRIBUTE* p_attr = &p_rec->attribute[0];
    804 
    805       SDP_TRACE_API("Deleting attr_id 0x%04x for handle 0x%x", attr_id, handle);
    806       /* Found it. Now, find the attribute */
    807       for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++) {
    808         if (p_attr->id == attr_id) {
    809           pad_ptr = p_attr->value_ptr;
    810           len = p_attr->len;
    811 
    812           if (len) {
    813             for (yy = 0; yy < p_rec->num_attributes; yy++) {
    814               if (p_rec->attribute[yy].value_ptr > pad_ptr)
    815                 p_rec->attribute[yy].value_ptr -= len;
    816             }
    817           }
    818 
    819           /* Found it. Shift everything up one */
    820           p_rec->num_attributes--;
    821 
    822           for (yy = xx; yy < p_rec->num_attributes; yy++, p_attr++) {
    823             *p_attr = *(p_attr + 1);
    824           }
    825 
    826           /* adjust attribute values if needed */
    827           if (len) {
    828             xx =
    829                 (p_rec->free_pad_ptr - ((pad_ptr + len) - &p_rec->attr_pad[0]));
    830             for (yy = 0; yy < xx; yy++, pad_ptr++) *pad_ptr = *(pad_ptr + len);
    831             p_rec->free_pad_ptr -= len;
    832           }
    833           return (true);
    834         }
    835       }
    836     }
    837   }
    838 #endif
    839   /* If here, not found */
    840   return (false);
    841 }
    842 
    843 /*******************************************************************************
    844  *
    845  * Function         SDP_ReadRecord
    846  *
    847  * Description      This function is called to get the raw data of the record
    848  *                  with the given handle from the database.
    849  *
    850  * Returns          -1, if the record is not found.
    851  *                  Otherwise, the offset (0 or 1) to start of data in p_data.
    852  *
    853  *                  The size of data copied into p_data is in *p_data_len.
    854  *
    855  ******************************************************************************/
    856 #if (SDP_RAW_DATA_INCLUDED == TRUE)
    857 int32_t SDP_ReadRecord(uint32_t handle, uint8_t* p_data, int32_t* p_data_len) {
    858   int32_t len = 0;     /* Number of bytes in the entry */
    859   int32_t offset = -1; /* default to not found */
    860 #if (SDP_SERVER_ENABLED == TRUE)
    861   tSDP_RECORD* p_rec;
    862   uint16_t start = 0;
    863   uint16_t end = 0xffff;
    864   tSDP_ATTRIBUTE* p_attr;
    865   uint16_t rem_len;
    866   uint8_t* p_rsp;
    867 
    868   /* Find the record in the database */
    869   p_rec = sdp_db_find_record(handle);
    870   if (p_rec && p_data && p_data_len) {
    871     p_rsp = &p_data[3];
    872     while ((p_attr = sdp_db_find_attr_in_rec(p_rec, start, end)) != NULL) {
    873       /* Check if attribute fits. Assume 3-byte value type/length */
    874       rem_len = *p_data_len - (uint16_t)(p_rsp - p_data);
    875 
    876       if (p_attr->len > (uint32_t)(rem_len - 6)) break;
    877 
    878       p_rsp = sdpu_build_attrib_entry(p_rsp, p_attr);
    879 
    880       /* next attr id */
    881       start = p_attr->id + 1;
    882     }
    883     len = (int32_t)(p_rsp - p_data);
    884 
    885     /* Put in the sequence header (2 or 3 bytes) */
    886     if (len > 255) {
    887       offset = 0;
    888       p_data[0] = (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
    889       p_data[1] = (uint8_t)((len - 3) >> 8);
    890       p_data[2] = (uint8_t)(len - 3);
    891     } else {
    892       offset = 1;
    893 
    894       p_data[1] = (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
    895       p_data[2] = (uint8_t)(len - 3);
    896 
    897       len--;
    898     }
    899     *p_data_len = len;
    900   }
    901 #endif
    902   /* If here, not found */
    903   return (offset);
    904 }
    905 #endif
    906