Home | History | Annotate | Download | only in gatt
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2009-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 GATT database building and query functions
     22  *
     23  ******************************************************************************/
     24 
     25 #include "bt_target.h"
     26 
     27 #if BLE_INCLUDED == TRUE
     28 
     29 #include "bt_trace.h"
     30 #include "bt_utils.h"
     31 
     32 #include <stdio.h>
     33 #include <string.h>
     34 #include "gatt_int.h"
     35 #include "l2c_api.h"
     36 #include "btm_int.h"
     37 
     38 /********************************************************************************
     39 **              L O C A L    F U N C T I O N     P R O T O T Y P E S            *
     40 *********************************************************************************/
     41 static BOOLEAN allocate_svc_db_buf(tGATT_SVC_DB *p_db);
     42 static void *allocate_attr_in_db(tGATT_SVC_DB *p_db, tBT_UUID *p_uuid, tGATT_PERM perm);
     43 static BOOLEAN deallocate_attr_in_db(tGATT_SVC_DB *p_db, void *p_attr);
     44 static BOOLEAN copy_extra_byte_in_db(tGATT_SVC_DB *p_db, void **p_dst, UINT16 len);
     45 
     46 static BOOLEAN gatts_db_add_service_declaration(tGATT_SVC_DB *p_db, tBT_UUID *p_service, BOOLEAN is_pri);
     47 static tGATT_STATUS gatts_send_app_read_request(tGATT_TCB *p_tcb, UINT8 op_code,
     48                                                 UINT16 handle, UINT16 offset, UINT32 trans_id);
     49 
     50 /*******************************************************************************
     51 **
     52 ** Function         gatts_init_service_db
     53 **
     54 ** Description      This function initialize a memory space to be a service database.
     55 **
     56 ** Parameter        p_db: database pointer.
     57 **                  len: size of the memory space.
     58 **
     59 ** Returns          Status of te operation.
     60 **
     61 *******************************************************************************/
     62 BOOLEAN gatts_init_service_db (tGATT_SVC_DB *p_db, tBT_UUID *p_service,  BOOLEAN is_pri,
     63                                UINT16 s_hdl, UINT16 num_handle)
     64 {
     65     if (!allocate_svc_db_buf(p_db))
     66     {
     67         GATT_TRACE_ERROR("gatts_init_service_db failed, no resources");
     68         return FALSE;
     69     }
     70 
     71     GATT_TRACE_DEBUG("gatts_init_service_db");
     72     GATT_TRACE_DEBUG("s_hdl = %d num_handle = %d", s_hdl, num_handle );
     73 
     74     /* update service database information */
     75     p_db->next_handle   = s_hdl;
     76     p_db->end_handle    = s_hdl + num_handle;
     77 
     78     return gatts_db_add_service_declaration(p_db, p_service, is_pri);
     79 }
     80 
     81 /*******************************************************************************
     82 **
     83 ** Function         gatts_init_service_db
     84 **
     85 ** Description      This function initialize a memory space to be a service database.
     86 **
     87 ** Parameter        p_db: database pointer.
     88 **                  len: size of the memory space.
     89 **
     90 ** Returns          Status of te operation.
     91 **
     92 *******************************************************************************/
     93 tBT_UUID * gatts_get_service_uuid (tGATT_SVC_DB *p_db)
     94 {
     95     if (!p_db || !p_db->p_attr_list)
     96     {
     97         GATT_TRACE_ERROR("service DB empty");
     98 
     99         return NULL;
    100     }
    101     else
    102     {
    103         return &((tGATT_ATTR16 *)p_db->p_attr_list)->p_value->uuid;
    104     }
    105 }
    106 
    107 /*******************************************************************************
    108 **
    109 ** Function         gatts_check_attr_readability
    110 **
    111 ** Description      check attribute readability
    112 **
    113 ** Returns          status of operation.
    114 **
    115 *******************************************************************************/
    116 static tGATT_STATUS gatts_check_attr_readability(tGATT_ATTR16 *p_attr,
    117                                                  UINT16 offset,
    118                                                  BOOLEAN read_long,
    119                                                  tGATT_SEC_FLAG sec_flag,
    120                                                  UINT8 key_size)
    121 {
    122     UINT16          min_key_size;
    123     tGATT_PERM      perm = p_attr->permission;
    124 
    125     UNUSED(offset);
    126     min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12));
    127     if (min_key_size != 0 )
    128     {
    129         min_key_size +=6;
    130     }
    131 
    132     if (!(perm & GATT_READ_ALLOWED))
    133     {
    134         GATT_TRACE_ERROR( "GATT_READ_NOT_PERMIT");
    135         return GATT_READ_NOT_PERMIT;
    136     }
    137 
    138     if ((perm & GATT_READ_AUTH_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED) &&
    139         !(sec_flag & BTM_SEC_FLAG_ENCRYPTED))
    140     {
    141         GATT_TRACE_ERROR( "GATT_INSUF_AUTHENTICATION");
    142         return GATT_INSUF_AUTHENTICATION;
    143     }
    144 
    145     if ((perm & GATT_READ_MITM_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED))
    146     {
    147         GATT_TRACE_ERROR( "GATT_INSUF_AUTHENTICATION: MITM Required");
    148         return GATT_INSUF_AUTHENTICATION;
    149     }
    150 
    151     if ((perm & GATT_READ_ENCRYPTED_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED))
    152     {
    153         GATT_TRACE_ERROR( "GATT_INSUF_ENCRYPTION");
    154         return GATT_INSUF_ENCRYPTION;
    155     }
    156 
    157     if ( (perm & GATT_READ_ENCRYPTED_REQUIRED) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED) && (key_size < min_key_size))
    158     {
    159         GATT_TRACE_ERROR( "GATT_INSUF_KEY_SIZE");
    160         return GATT_INSUF_KEY_SIZE;
    161     }
    162 
    163 
    164     if (read_long)
    165     {
    166         switch (p_attr->uuid)
    167         {
    168             case GATT_UUID_PRI_SERVICE:
    169             case GATT_UUID_SEC_SERVICE:
    170             case GATT_UUID_CHAR_DECLARE:
    171             case GATT_UUID_INCLUDE_SERVICE:
    172             case GATT_UUID_CHAR_EXT_PROP:
    173             case GATT_UUID_CHAR_CLIENT_CONFIG:
    174             case GATT_UUID_CHAR_SRVR_CONFIG:
    175             case GATT_UUID_CHAR_PRESENT_FORMAT:
    176                 GATT_TRACE_ERROR("GATT_NOT_LONG");
    177                 return GATT_NOT_LONG;
    178 
    179             default:
    180                 break;
    181         }
    182     }
    183 
    184     return GATT_SUCCESS;
    185 }
    186 
    187 /*******************************************************************************
    188 **
    189 ** Function         read_attr_value
    190 **
    191 ** Description      Utility function to read an attribute value.
    192 **
    193 ** Parameter        p_attr: pointer to the attribute to read.
    194 **                  offset: read offset.
    195 **                  p_value: output parameter to carry out the attribute value.
    196 **                  p_len: output parameter to carry out the attribute length.
    197 **                  read_long: this is a read blob request.
    198 **                  mtu: MTU
    199 **                  sec_flag: current link security status.
    200 **                  key_size: encryption key size.
    201 **
    202 ** Returns          status of operation.
    203 **
    204 *******************************************************************************/
    205 static tGATT_STATUS read_attr_value (void *p_attr,
    206                                      UINT16 offset,
    207                                      UINT8 **p_data,
    208                                      BOOLEAN read_long,
    209                                      UINT16 mtu,
    210                                      UINT16 *p_len,
    211                                      tGATT_SEC_FLAG sec_flag,
    212                                      UINT8 key_size)
    213 {
    214     UINT16          len = 0, uuid16 = 0;
    215     UINT8           *p = *p_data;
    216     tGATT_STATUS    status;
    217     UINT16          read_long_uuid=0;
    218     tGATT_ATTR16    *p_attr16  = (tGATT_ATTR16  *)p_attr;
    219 
    220     GATT_TRACE_DEBUG("read_attr_value uuid=0x%04x perm=0x%0x sec_flag=0x%x offset=%d read_long=%d",
    221                       p_attr16->uuid,
    222                       p_attr16->permission,
    223                       sec_flag,
    224                       offset,
    225                       read_long);
    226 
    227     status = gatts_check_attr_readability((tGATT_ATTR16 *)p_attr, offset, read_long, sec_flag, key_size);
    228 
    229     if (status != GATT_SUCCESS)
    230         return status;
    231 
    232     if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_16)
    233         uuid16 = p_attr16->uuid;
    234 
    235     status = GATT_NO_RESOURCES;
    236 
    237     if (read_long &&
    238         (uuid16 == GATT_UUID_CHAR_DESCRIPTION || uuid16 == GATT_UUID_CHAR_AGG_FORMAT))
    239     {
    240         read_long_uuid = p_attr16->uuid;
    241     }
    242 
    243     if (uuid16 == GATT_UUID_PRI_SERVICE || uuid16 == GATT_UUID_SEC_SERVICE)
    244     {
    245         len = p_attr16->p_value->uuid.len;
    246         if (mtu >= p_attr16->p_value->uuid.len)
    247         {
    248             gatt_build_uuid_to_stream(&p, p_attr16->p_value->uuid);
    249             status = GATT_SUCCESS;
    250         }
    251     }
    252     else if (uuid16 == GATT_UUID_CHAR_DECLARE)
    253     {
    254         len = (((tGATT_ATTR16 *)(p_attr16->p_next))->uuid_type == GATT_ATTR_UUID_TYPE_16) ? 5 :19;
    255 
    256         if (mtu >= len)
    257         {
    258             UINT8_TO_STREAM(p, p_attr16->p_value->char_decl.property);
    259             UINT16_TO_STREAM(p, p_attr16->p_value->char_decl.char_val_handle);
    260 
    261             if (((tGATT_ATTR16 *)(p_attr16->p_next))->uuid_type == GATT_ATTR_UUID_TYPE_16)
    262             {
    263                 UINT16_TO_STREAM(p, ((tGATT_ATTR16 *)(p_attr16->p_next))->uuid);
    264             }
    265             /* convert a 32bits UUID to 128 bits */
    266             else if (((tGATT_ATTR32 *)(p_attr16->p_next))->uuid_type == GATT_ATTR_UUID_TYPE_32)
    267             {
    268                 gatt_convert_uuid32_to_uuid128 (p, ((tGATT_ATTR32 *)(p_attr16->p_next))->uuid);
    269                 p += LEN_UUID_128;
    270             }
    271             else
    272             {
    273                 ARRAY_TO_STREAM (p, ((tGATT_ATTR128 *)(p_attr16->p_next))->uuid, LEN_UUID_128);
    274             }
    275             status = GATT_SUCCESS;
    276         }
    277 
    278     }
    279     else if (uuid16 == GATT_UUID_INCLUDE_SERVICE)
    280     {
    281         if (p_attr16->p_value->incl_handle.service_type.len == LEN_UUID_16)
    282             len = 6;
    283         else
    284             len = 4;
    285 
    286         if (mtu >= len)
    287         {
    288             UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.s_handle);
    289             UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.e_handle);
    290 
    291             if (p_attr16->p_value->incl_handle.service_type.len == LEN_UUID_16)
    292             {
    293                 UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.service_type.uu.uuid16);
    294             }
    295             status = GATT_SUCCESS;
    296         }
    297     }
    298     else /* characteristic description or characteristic value */
    299     {
    300         status = GATT_PENDING;
    301     }
    302 
    303     *p_len = len;
    304     *p_data = p;
    305     return status;
    306 }
    307 
    308 /*******************************************************************************
    309 **
    310 ** Function         gatts_db_read_attr_value_by_type
    311 **
    312 ** Description      Query attribute value by attribute type.
    313 **
    314 ** Parameter        p_db: pointer to the attribute database.
    315 **                  p_rsp: Read By type response data.
    316 **                  s_handle: starting handle of the range we are looking for.
    317 **                  e_handle: ending handle of the range we are looking for.
    318 **                  type: Attribute type.
    319 **                  mtu: MTU.
    320 **                  sec_flag: current link security status.
    321 **                  key_size: encryption key size.
    322 **
    323 ** Returns          Status of the operation.
    324 **
    325 *******************************************************************************/
    326 tGATT_STATUS gatts_db_read_attr_value_by_type (tGATT_TCB   *p_tcb,
    327                                                tGATT_SVC_DB    *p_db,
    328                                                UINT8        op_code,
    329                                                BT_HDR      *p_rsp,
    330                                                UINT16       s_handle,
    331                                                UINT16       e_handle,
    332                                                tBT_UUID     type,
    333                                                UINT16      *p_len,
    334                                                tGATT_SEC_FLAG sec_flag,
    335                                                UINT8        key_size,
    336                                                UINT32       trans_id,
    337                                                UINT16       *p_cur_handle)
    338 {
    339     tGATT_STATUS status = GATT_NOT_FOUND;
    340     tGATT_ATTR16  *p_attr;
    341     UINT16      len = 0;
    342     UINT8       *p = (UINT8 *)(p_rsp + 1) + p_rsp->len + L2CAP_MIN_OFFSET;
    343     tBT_UUID    attr_uuid;
    344 #if (defined(BLE_DELAY_REQUEST_ENC) && (BLE_DELAY_REQUEST_ENC == TRUE))
    345     UINT8       flag;
    346 #endif
    347 
    348     if (p_db && p_db->p_attr_list)
    349     {
    350         p_attr = (tGATT_ATTR16 *)p_db->p_attr_list;
    351 
    352         while (p_attr && p_attr->handle <= e_handle)
    353         {
    354             if (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16)
    355             {
    356                 attr_uuid.len = LEN_UUID_16;
    357                 attr_uuid.uu.uuid16 = p_attr->uuid;
    358             }
    359             else if (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_32)
    360             {
    361                 attr_uuid.len = LEN_UUID_32;
    362                 attr_uuid.uu.uuid32 = ((tGATT_ATTR32 *)p_attr)->uuid;
    363             }
    364             else
    365             {
    366                 attr_uuid.len = LEN_UUID_128;
    367                 memcpy(attr_uuid.uu.uuid128, ((tGATT_ATTR128 *)p_attr)->uuid, LEN_UUID_128);
    368             }
    369 
    370             if (p_attr->handle >= s_handle && gatt_uuid_compare(type, attr_uuid))
    371             {
    372                 if (*p_len <= 2)
    373                 {
    374                     status = GATT_NO_RESOURCES;
    375                     break;
    376                 }
    377 
    378                 UINT16_TO_STREAM (p, p_attr->handle);
    379 
    380                 status = read_attr_value ((void *)p_attr, 0, &p, FALSE, (UINT16)(*p_len -2), &len, sec_flag, key_size);
    381 
    382                 if (status == GATT_PENDING)
    383                 {
    384                     status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, 0, trans_id);
    385 
    386                     /* one callback at a time */
    387                     break;
    388                 }
    389                 else if (status == GATT_SUCCESS)
    390                 {
    391                     if (p_rsp->offset == 0)
    392                         p_rsp->offset = len + 2;
    393 
    394                     if (p_rsp->offset == len + 2)
    395                     {
    396                         p_rsp->len += (len  + 2);
    397                         *p_len -= (len + 2);
    398                     }
    399                     else
    400                     {
    401                         GATT_TRACE_ERROR("format mismatch");
    402                         status = GATT_NO_RESOURCES;
    403                         break;
    404                     }
    405                 }
    406                 else
    407                 {
    408                     *p_cur_handle = p_attr->handle;
    409                     break;
    410                 }
    411             }
    412             p_attr = (tGATT_ATTR16 *)p_attr->p_next;
    413         }
    414     }
    415 
    416 #if (defined(BLE_DELAY_REQUEST_ENC) && (BLE_DELAY_REQUEST_ENC == TRUE))
    417     if (BTM_GetSecurityFlags(p_tcb->peer_bda, &flag))
    418     {
    419         if ((p_tcb->att_lcid == L2CAP_ATT_CID) && (status == GATT_PENDING) &&
    420             (type.uu.uuid16 == GATT_UUID_GAP_DEVICE_NAME))
    421         {
    422             if ((flag & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_FLAG_ENCRYPTED)) ==
    423                  BTM_SEC_LINK_KEY_KNOWN)
    424             {
    425                 tACL_CONN         *p;
    426                 p = btm_bda_to_acl(p_tcb->peer_bda, BT_TRANSPORT_LE);
    427                 if ((p != NULL) && (p->link_role == BTM_ROLE_MASTER))
    428                 {
    429                     tBTM_BLE_SEC_ACT sec_act = BTM_BLE_SEC_ENCRYPT;
    430                     btm_ble_set_encryption(p_tcb->peer_bda, &sec_act, p->link_role);
    431                 }
    432             }
    433         }
    434     }
    435 #endif
    436     return status;
    437 }
    438 
    439 /*******************************************************************************
    440 **
    441 ** Function         gatts_add_included_service
    442 **
    443 ** Description      This function adds an included service into a database.
    444 **
    445 ** Parameter        p_db: database pointer.
    446 **                  inc_srvc_type: included service type.
    447 **
    448 ** Returns          Status of the operation.
    449 **
    450 *******************************************************************************/
    451 UINT16 gatts_add_included_service (tGATT_SVC_DB *p_db, UINT16 s_handle, UINT16 e_handle,
    452                                    tBT_UUID service)
    453 {
    454     tGATT_ATTR16      *p_attr;
    455     tBT_UUID         uuid = {LEN_UUID_16, {GATT_UUID_INCLUDE_SERVICE}};
    456 
    457     GATT_TRACE_DEBUG("gatts_add_included_service: s_hdl = 0x%04x e_hdl = 0x%04x uuid = 0x%04x",
    458                       s_handle, e_handle, service.uu.uuid16);
    459 
    460     if (service.len == 0 || s_handle == 0 || e_handle == 0)
    461     {
    462         GATT_TRACE_ERROR("gatts_add_included_service Illegal Params.");
    463         return 0;
    464     }
    465 
    466     if ((p_attr = (tGATT_ATTR16 *) allocate_attr_in_db(p_db, &uuid, GATT_PERM_READ)) != NULL)
    467     {
    468         if (copy_extra_byte_in_db(p_db, (void **)&p_attr->p_value, sizeof(tGATT_INCL_SRVC)))
    469         {
    470             p_attr->p_value->incl_handle.s_handle = s_handle;
    471             p_attr->p_value->incl_handle.e_handle = e_handle;
    472             memcpy(&p_attr->p_value->incl_handle.service_type, &service, sizeof(tBT_UUID));
    473 
    474             return p_attr->handle;
    475         }
    476         else
    477         {
    478             deallocate_attr_in_db(p_db, p_attr);
    479         }
    480     }
    481 
    482     return 0;
    483 }
    484 
    485 /*******************************************************************************
    486 **
    487 ** Function         gatts_add_characteristic
    488 **
    489 ** Description      This function add a characteristics and its descriptor into
    490 **                  a servce identified by the service database pointer.
    491 **
    492 ** Parameter        p_db: database pointer.
    493 **                  perm: permission (authentication and key size requirements)
    494 **                  property: property of the characteristic.
    495 **                  p_char: characteristic value information.
    496 **
    497 ** Returns          Status of te operation.
    498 **
    499 *******************************************************************************/
    500 UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm,
    501                                  tGATT_CHAR_PROP property,
    502                                  tBT_UUID * p_char_uuid)
    503 {
    504     tGATT_ATTR16     *p_char_decl, *p_char_val;
    505     tBT_UUID        uuid = {LEN_UUID_16, {GATT_UUID_CHAR_DECLARE}};
    506 
    507     GATT_TRACE_DEBUG("gatts_add_characteristic perm=0x%0x property=0x%0x", perm, property);
    508 
    509     if ((p_char_decl = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, &uuid, GATT_PERM_READ)) != NULL)
    510     {
    511         if (!copy_extra_byte_in_db(p_db, (void **)&p_char_decl->p_value, sizeof(tGATT_CHAR_DECL)))
    512         {
    513             deallocate_attr_in_db(p_db, p_char_decl);
    514             return 0;
    515         }
    516 
    517         p_char_val = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, p_char_uuid, perm);
    518 
    519         if (p_char_val == NULL)
    520         {
    521             deallocate_attr_in_db(p_db, p_char_decl);
    522             return 0;
    523         }
    524 
    525         p_char_decl->p_value->char_decl.property = property;
    526         p_char_decl->p_value->char_decl.char_val_handle  = p_char_val->handle;
    527 
    528         p_char_val->p_value = NULL;
    529 
    530         return p_char_val->handle;
    531     }
    532 
    533     return 0;
    534 }
    535 
    536 /*******************************************************************************
    537 **
    538 ** Function         gatt_convertchar_descr_type
    539 **
    540 ** Description      This function convert a char descript UUID into descriptor type.
    541 **
    542 ** Returns          descriptor type.
    543 **
    544 *******************************************************************************/
    545 UINT8 gatt_convertchar_descr_type(tBT_UUID *p_descr_uuid)
    546 {
    547     tBT_UUID std_descr = {LEN_UUID_16, {GATT_UUID_CHAR_EXT_PROP}};
    548 
    549     if (gatt_uuid_compare(std_descr, * p_descr_uuid))
    550         return GATT_DESCR_EXT_DSCPTOR;
    551 
    552     std_descr.uu.uuid16 ++;
    553     if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
    554         return GATT_DESCR_USER_DSCPTOR;
    555 
    556     std_descr.uu.uuid16 ++;
    557     if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
    558         return GATT_DESCR_CLT_CONFIG;
    559 
    560     std_descr.uu.uuid16 ++;
    561     if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
    562         return GATT_DESCR_SVR_CONFIG;
    563 
    564     std_descr.uu.uuid16 ++;
    565     if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
    566         return GATT_DESCR_PRES_FORMAT;
    567 
    568     std_descr.uu.uuid16 ++;
    569     if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
    570         return GATT_DESCR_AGGR_FORMAT;
    571 
    572     std_descr.uu.uuid16 ++;
    573     if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
    574         return GATT_DESCR_VALID_RANGE;
    575 
    576 
    577     return GATT_DESCR_UNKNOWN;
    578 }
    579 
    580 /*******************************************************************************
    581 **
    582 ** Function         gatts_add_char_descr
    583 **
    584 ** Description      This function add a characteristics descriptor.
    585 **
    586 ** Parameter        p_db: database pointer.
    587 **                  perm: characteristic descriptor permission type.
    588 **                  char_dscp_tpye: the characteristic descriptor masks.
    589 **                  p_dscp_params: characteristic descriptors values.
    590 **
    591 ** Returns          Status of the operation.
    592 **
    593 *******************************************************************************/
    594 UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm,
    595                              tBT_UUID *     p_descr_uuid)
    596 {
    597     tGATT_ATTR16    *p_char_dscptr;
    598 
    599     GATT_TRACE_DEBUG("gatts_add_char_descr uuid=0x%04x", p_descr_uuid->uu.uuid16);
    600 
    601     /* Add characteristic descriptors */
    602     if ((p_char_dscptr = (tGATT_ATTR16 *)allocate_attr_in_db(p_db,
    603                                                              p_descr_uuid,
    604                                                              perm))
    605         == NULL)
    606     {
    607         GATT_TRACE_DEBUG("gatts_add_char_descr Fail for adding char descriptors.");
    608         return 0;
    609     }
    610     else
    611     {
    612         return p_char_dscptr->handle;
    613     }
    614 }
    615 
    616 /*******************************************************************************/
    617 /* Service Attribute Database Query Utility Functions */
    618 /*******************************************************************************/
    619 /*******************************************************************************
    620 **
    621 ** Function         gatts_read_attr_value_by_handle
    622 **
    623 ** Description      Query attribute value by attribute handle.
    624 **
    625 ** Parameter        p_db: pointer to the attribute database.
    626 **                  handle: Attribute handle to read.
    627 **                  offset: Read offset.
    628 **                  p_value: output parameter to carry out the attribute value.
    629 **                  p_len: output parameter as attribute length read.
    630 **                  read_long: this is a read blob request.
    631 **                  mtu: MTU.
    632 **                  sec_flag: current link security status.
    633 **                  key_size: encryption key size
    634 **
    635 ** Returns          Status of operation.
    636 **
    637 *******************************************************************************/
    638 tGATT_STATUS gatts_read_attr_value_by_handle(tGATT_TCB *p_tcb,
    639                                              tGATT_SVC_DB *p_db,
    640                                              UINT8 op_code,
    641                                              UINT16 handle, UINT16 offset,
    642                                              UINT8 *p_value, UINT16 *p_len,
    643                                              UINT16 mtu,
    644                                              tGATT_SEC_FLAG sec_flag,
    645                                              UINT8 key_size,
    646                                              UINT32 trans_id)
    647 {
    648     tGATT_STATUS status = GATT_NOT_FOUND;
    649     tGATT_ATTR16  *p_attr;
    650     UINT8       *pp = p_value;
    651 
    652     if (p_db && p_db->p_attr_list)
    653     {
    654         p_attr = (tGATT_ATTR16 *)p_db->p_attr_list;
    655 
    656         while (p_attr && handle >= p_attr->handle)
    657         {
    658             if (p_attr->handle == handle)
    659             {
    660                 status = read_attr_value (p_attr, offset, &pp,
    661                                           (BOOLEAN)(op_code == GATT_REQ_READ_BLOB),
    662                                           mtu, p_len, sec_flag, key_size);
    663 
    664                 if (status == GATT_PENDING)
    665                 {
    666                     status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, offset, trans_id);
    667                 }
    668                 break;
    669             }
    670             p_attr = (tGATT_ATTR16 *)p_attr->p_next;
    671         }
    672     }
    673 
    674     return status;
    675 }
    676 
    677 /*******************************************************************************
    678 **
    679 ** Function         gatts_read_attr_perm_check
    680 **
    681 ** Description      Check attribute readability.
    682 **
    683 ** Parameter        p_db: pointer to the attribute database.
    684 **                  handle: Attribute handle to read.
    685 **                  offset: Read offset.
    686 **                  p_value: output parameter to carry out the attribute value.
    687 **                  p_len: output parameter as attribute length read.
    688 **                  read_long: this is a read blob request.
    689 **                  mtu: MTU.
    690 **                  sec_flag: current link security status.
    691 **                  key_size: encryption key size
    692 **
    693 ** Returns          Status of operation.
    694 **
    695 *******************************************************************************/
    696 tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB *p_db,
    697                                         BOOLEAN is_long,
    698                                         UINT16 handle,
    699                                         tGATT_SEC_FLAG sec_flag,
    700                                         UINT8 key_size)
    701 {
    702     tGATT_STATUS status = GATT_NOT_FOUND;
    703     tGATT_ATTR16  *p_attr;
    704 
    705     if (p_db && p_db->p_attr_list)
    706     {
    707         p_attr = (tGATT_ATTR16 *)p_db->p_attr_list;
    708 
    709         while (p_attr && handle >= p_attr->handle)
    710         {
    711             if (p_attr->handle == handle)
    712             {
    713                 status = gatts_check_attr_readability (p_attr, 0,
    714                                                        is_long,
    715                                                        sec_flag, key_size);
    716                 break;
    717             }
    718             p_attr = (tGATT_ATTR16 *) p_attr->p_next;
    719         }
    720     }
    721 
    722     return status;
    723 }
    724 /*******************************************************************************
    725 **
    726 ** Function         gatts_write_attr_perm_check
    727 **
    728 ** Description      Write attribute value into database.
    729 **
    730 ** Parameter        p_db: pointer to the attribute database.
    731 **                  op_code:op code of this write.
    732 **                  handle: handle of the attribute to write.
    733 **                  offset: Write offset if write op code is write blob.
    734 **                  p_data: Attribute value to write.
    735 **                  len: attribute data length.
    736 **                  sec_flag: current link security status.
    737 **                  key_size: encryption key size
    738 **
    739 ** Returns          Status of the operation.
    740 **
    741 *******************************************************************************/
    742 tGATT_STATUS gatts_write_attr_perm_check (tGATT_SVC_DB *p_db, UINT8 op_code,
    743                                           UINT16 handle, UINT16 offset, UINT8 *p_data,
    744                                           UINT16 len, tGATT_SEC_FLAG sec_flag, UINT8 key_size)
    745 {
    746     tGATT_STATUS    status = GATT_NOT_FOUND;
    747     tGATT_ATTR16    *p_attr;
    748     UINT16          max_size = 0;
    749     tGATT_PERM      perm;
    750     UINT16          min_key_size;
    751 
    752     GATT_TRACE_DEBUG( "gatts_write_attr_perm_check op_code=0x%0x handle=0x%04x offset=%d len=%d sec_flag=0x%0x key_size=%d",
    753                        op_code, handle, offset, len, sec_flag, key_size);
    754 
    755     if (p_db != NULL)
    756     {
    757         p_attr = (tGATT_ATTR16 *) p_db->p_attr_list;
    758 
    759         while (p_attr != NULL)
    760         {
    761             if (p_attr->handle == handle)
    762             {
    763                 perm = p_attr->permission;
    764                 min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12));
    765                 if (min_key_size != 0 )
    766                 {
    767                     min_key_size +=6;
    768                 }
    769                 GATT_TRACE_DEBUG( "gatts_write_attr_perm_check p_attr->permission =0x%04x min_key_size==0x%04x",
    770                                    p_attr->permission,
    771                                    min_key_size);
    772 
    773                 if ((op_code == GATT_CMD_WRITE || op_code == GATT_REQ_WRITE)
    774                     && (perm & GATT_WRITE_SIGNED_PERM))
    775                 {
    776                     /* use the rules for the mixed security see section 10.2.3*/
    777                     /* use security mode 1 level 2 when the following condition follows */
    778                     /* LE security mode 2 level 1 and LE security mode 1 level 2 */
    779                     if ((perm & GATT_PERM_WRITE_SIGNED) && (perm & GATT_PERM_WRITE_ENCRYPTED))
    780                     {
    781                         perm = GATT_PERM_WRITE_ENCRYPTED;
    782                     }
    783                     /* use security mode 1 level 3 when the following condition follows */
    784                     /* LE security mode 2 level 2 and security mode 1 and LE */
    785                     else if (((perm & GATT_PERM_WRITE_SIGNED_MITM) && (perm & GATT_PERM_WRITE_ENCRYPTED)) ||
    786                               /* LE security mode 2 and security mode 1 level 3 */
    787                              ((perm & GATT_WRITE_SIGNED_PERM) && (perm & GATT_PERM_WRITE_ENC_MITM)))
    788                     {
    789                         perm = GATT_PERM_WRITE_ENC_MITM;
    790                     }
    791                 }
    792 
    793                 if ((op_code == GATT_SIGN_CMD_WRITE) && !(perm & GATT_WRITE_SIGNED_PERM))
    794                 {
    795                     status = GATT_WRITE_NOT_PERMIT;
    796                     GATT_TRACE_DEBUG( "gatts_write_attr_perm_check - sign cmd write not allowed");
    797                 }
    798                  if ((op_code == GATT_SIGN_CMD_WRITE) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED))
    799                 {
    800                     status = GATT_INVALID_PDU;
    801                     GATT_TRACE_ERROR( "gatts_write_attr_perm_check - Error!! sign cmd write sent on a encypted link");
    802                 }
    803                 else if (!(perm & GATT_WRITE_ALLOWED))
    804                 {
    805                     status = GATT_WRITE_NOT_PERMIT;
    806                     GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_WRITE_NOT_PERMIT");
    807                 }
    808                 /* require authentication, but not been authenticated */
    809                 else if ((perm & GATT_WRITE_AUTH_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED))
    810                 {
    811                     status = GATT_INSUF_AUTHENTICATION;
    812                     GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION");
    813                 }
    814                 else if ((perm & GATT_WRITE_MITM_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED))
    815                 {
    816                     status = GATT_INSUF_AUTHENTICATION;
    817                     GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION: MITM required");
    818                 }
    819                 else if ((perm & GATT_WRITE_ENCRYPTED_PERM ) && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED))
    820                 {
    821                     status = GATT_INSUF_ENCRYPTION;
    822                     GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_ENCRYPTION");
    823                 }
    824                 else if ((perm & GATT_WRITE_ENCRYPTED_PERM ) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED) && (key_size < min_key_size))
    825                 {
    826                     status = GATT_INSUF_KEY_SIZE;
    827                     GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_KEY_SIZE");
    828                 }
    829                 /* LE security mode 2 attribute  */
    830                 else if (perm & GATT_WRITE_SIGNED_PERM && op_code != GATT_SIGN_CMD_WRITE && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED)
    831                     &&  (perm & GATT_WRITE_ALLOWED) == 0)
    832                 {
    833                     status = GATT_INSUF_AUTHENTICATION;
    834                     GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION: LE security mode 2 required");
    835                 }
    836                 else /* writable: must be char value declaration or char descritpors */
    837                 {
    838                     if(p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16)
    839                     {
    840                     switch (p_attr->uuid)
    841                     {
    842                         case GATT_UUID_CHAR_PRESENT_FORMAT:/* should be readable only */
    843                         case GATT_UUID_CHAR_EXT_PROP:/* should be readable only */
    844                         case GATT_UUID_CHAR_AGG_FORMAT: /* should be readable only */
    845                             case GATT_UUID_CHAR_VALID_RANGE:
    846                             status = GATT_WRITE_NOT_PERMIT;
    847                             break;
    848 
    849                         case GATT_UUID_CHAR_CLIENT_CONFIG:
    850 /* coverity[MISSING_BREAK] */
    851 /* intnended fall through, ignored */
    852                             /* fall through */
    853                         case GATT_UUID_CHAR_SRVR_CONFIG:
    854                             max_size = 2;
    855                         case GATT_UUID_CHAR_DESCRIPTION:
    856                         default: /* any other must be character value declaration */
    857                             status = GATT_SUCCESS;
    858                             break;
    859                         }
    860                     }
    861                     else if (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_128 ||
    862 				              p_attr->uuid_type == GATT_ATTR_UUID_TYPE_32)
    863                     {
    864                          status = GATT_SUCCESS;
    865                     }
    866                     else
    867                     {
    868                         status = GATT_INVALID_PDU;
    869                     }
    870 
    871                     if (p_data == NULL && len  > 0)
    872                     {
    873                         status = GATT_INVALID_PDU;
    874                     }
    875                     /* these attribute does not allow write blob */
    876 // btla-specific ++
    877                     else if ( (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16) &&
    878                               (p_attr->uuid == GATT_UUID_CHAR_CLIENT_CONFIG ||
    879                                p_attr->uuid == GATT_UUID_CHAR_SRVR_CONFIG) )
    880 // btla-specific --
    881                     {
    882                         if (op_code == GATT_REQ_PREPARE_WRITE && offset != 0) /* does not allow write blob */
    883                         {
    884                             status = GATT_NOT_LONG;
    885                             GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_NOT_LONG");
    886                         }
    887                         else if (len != max_size)    /* data does not match the required format */
    888                         {
    889                             status = GATT_INVALID_ATTR_LEN;
    890                             GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INVALID_PDU");
    891                         }
    892                         else
    893                         {
    894                             status = GATT_SUCCESS;
    895                         }
    896                     }
    897                 }
    898                 break;
    899             }
    900             else
    901                 p_attr = (tGATT_ATTR16 *)p_attr->p_next;
    902         }
    903     }
    904 
    905     return status;
    906 }
    907 
    908 /*******************************************************************************
    909 **
    910 ** Function         allocate_attr_in_db
    911 **
    912 ** Description      Allocate a memory space for a new attribute, and link this
    913 **                  attribute into the database attribute list.
    914 **
    915 **
    916 ** Parameter        p_db    : database pointer.
    917 **                  p_uuid:     pointer to attribute UUID
    918 **                  service : type of attribute to be added.
    919 **
    920 ** Returns          pointer to the newly allocated attribute.
    921 **
    922 *******************************************************************************/
    923 static void *allocate_attr_in_db(tGATT_SVC_DB *p_db, tBT_UUID *p_uuid, tGATT_PERM perm)
    924 {
    925     tGATT_ATTR16    *p_attr16 = NULL, *p_last;
    926     tGATT_ATTR32    *p_attr32 = NULL;
    927     tGATT_ATTR128   *p_attr128 = NULL;
    928     UINT16      len = sizeof(tGATT_ATTR128);
    929 
    930     if (p_uuid == NULL)
    931     {
    932         GATT_TRACE_ERROR("illegal UUID");
    933         return NULL;
    934     }
    935 
    936     if (p_uuid->len == LEN_UUID_16)
    937         len = sizeof(tGATT_ATTR16);
    938     else if (p_uuid->len == LEN_UUID_32)
    939         len = sizeof(tGATT_ATTR32);
    940 
    941     GATT_TRACE_DEBUG("allocate attr %d bytes ",len);
    942 
    943     if (p_db->end_handle <= p_db->next_handle)
    944     {
    945         GATT_TRACE_DEBUG("handle space full. handle_max = %d next_handle = %d",
    946                           p_db->end_handle, p_db->next_handle);
    947         return NULL;
    948     }
    949 
    950     if (p_db->mem_free < len)
    951     {
    952         if (!allocate_svc_db_buf(p_db))
    953         {
    954             GATT_TRACE_ERROR("allocate_attr_in_db failed, no resources");
    955             return NULL;
    956         }
    957     }
    958     memset(p_db->p_free_mem, 0, len);
    959     p_attr16 = (tGATT_ATTR16 *) p_db->p_free_mem;
    960 
    961     if (p_uuid->len == LEN_UUID_16 && p_uuid->uu.uuid16 != GATT_ILLEGAL_UUID)
    962     {
    963         p_attr16->uuid_type = GATT_ATTR_UUID_TYPE_16;
    964         p_attr16->uuid = p_uuid->uu.uuid16;
    965     }
    966     else if (p_uuid->len == LEN_UUID_32)
    967     {
    968         p_attr32 = (tGATT_ATTR32 *) p_db->p_free_mem;
    969         p_attr32->uuid_type = GATT_ATTR_UUID_TYPE_32;
    970         p_attr32->uuid = p_uuid->uu.uuid32;
    971     }
    972     else if (p_uuid->len == LEN_UUID_128)
    973     {
    974         p_attr128 = (tGATT_ATTR128 *) p_db->p_free_mem;
    975         p_attr128->uuid_type = GATT_ATTR_UUID_TYPE_128;
    976         memcpy(p_attr128->uuid, p_uuid->uu.uuid128, LEN_UUID_128);
    977     }
    978 
    979     p_db->p_free_mem += len;
    980     p_db->mem_free -= len;
    981 
    982     p_attr16->handle = p_db->next_handle++;
    983     p_attr16->permission = perm;
    984     p_attr16->p_next = NULL;
    985 
    986     /* link the attribute record into the end of DB */
    987     if (p_db->p_attr_list == NULL)
    988         p_db->p_attr_list = p_attr16;
    989     else
    990     {
    991         p_last = (tGATT_ATTR16 *)p_db->p_attr_list;
    992 
    993         while (p_last != NULL && p_last->p_next != NULL)
    994             p_last = (tGATT_ATTR16 *)p_last->p_next;
    995 
    996         p_last->p_next = p_attr16;
    997     }
    998 
    999     if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_16)
   1000     {
   1001         GATT_TRACE_DEBUG("=====> handle = [0x%04x] uuid16 = [0x%04x] perm=0x%02x ",
   1002                           p_attr16->handle, p_attr16->uuid, p_attr16->permission);
   1003     }
   1004     else if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_32)
   1005     {
   1006         GATT_TRACE_DEBUG("=====> handle = [0x%04x] uuid32 = [0x%08x] perm=0x%02x ",
   1007                           p_attr32->handle, p_attr32->uuid, p_attr32->permission);
   1008     }
   1009     else
   1010     {
   1011         GATT_TRACE_DEBUG("=====> handle = [0x%04x] uuid128 = [0x%02x:0x%02x] perm=0x%02x ",
   1012                           p_attr128->handle, p_attr128->uuid[0],p_attr128->uuid[1],
   1013                           p_attr128->permission);
   1014     }
   1015     return(void *)p_attr16;
   1016 }
   1017 
   1018 /*******************************************************************************
   1019 **
   1020 ** Function         deallocate_attr_in_db
   1021 **
   1022 ** Description      Free an attribute within the database.
   1023 **
   1024 ** Parameter        p_db: database pointer.
   1025 **                  p_attr: pointer to the attribute record to be freed.
   1026 **
   1027 ** Returns          BOOLEAN: success
   1028 **
   1029 *******************************************************************************/
   1030 static BOOLEAN deallocate_attr_in_db(tGATT_SVC_DB *p_db, void *p_attr)
   1031 {
   1032     tGATT_ATTR16  *p_cur, *p_next;
   1033     BOOLEAN     found = FALSE;
   1034 
   1035     if (p_db->p_attr_list == NULL)
   1036         return found;
   1037 
   1038     p_cur   = (tGATT_ATTR16 *) p_db->p_attr_list;
   1039     p_next  = (tGATT_ATTR16 *) p_cur->p_next;
   1040 
   1041     for (; p_cur != NULL && p_next != NULL;
   1042         p_cur = p_next, p_next = (tGATT_ATTR16 *)p_next->p_next)
   1043     {
   1044         if (p_next == p_attr)
   1045         {
   1046             p_cur->p_next = p_next->p_next;
   1047             found = TRUE;
   1048         }
   1049     }
   1050     if (p_cur == p_attr && p_cur == p_db->p_attr_list)
   1051     {
   1052         p_db->p_attr_list = p_cur->p_next;
   1053         found = TRUE;
   1054     }
   1055     /* else attr not found */
   1056     if ( found)
   1057         p_db->next_handle --;
   1058 
   1059     return found;
   1060 }
   1061 
   1062 /*******************************************************************************
   1063 **
   1064 ** Function         copy_extra_byte_in_db
   1065 **
   1066 ** Description      Utility function to allocate extra bytes memory in DB and copy
   1067 **                  the value from a source place.
   1068 **
   1069 **
   1070 ** Parameter        p_db: database pointer.
   1071 **                  p_dst: destination data pointer.
   1072 **                  p_src: source data pointer.
   1073 **                  len: data length to be copied.
   1074 **
   1075 ** Returns          None.
   1076 **
   1077 *******************************************************************************/
   1078 static BOOLEAN copy_extra_byte_in_db(tGATT_SVC_DB *p_db, void **p_dst, UINT16 len)
   1079 {
   1080     UINT8 *p = (UINT8 *)*p_dst;
   1081 
   1082     if (p_db->mem_free < len)
   1083     {
   1084         if (!allocate_svc_db_buf(p_db))
   1085         {
   1086             GATT_TRACE_ERROR("copy_extra_byte_in_db failed, no resources");
   1087             return FALSE;
   1088         }
   1089     }
   1090 
   1091     p = p_db->p_free_mem;
   1092     p_db->p_free_mem += len;
   1093     p_db->mem_free -= len;
   1094     memset((void *)p, 0, len);
   1095     *p_dst = (void *)p;
   1096 
   1097     return TRUE;
   1098 }
   1099 
   1100 /*******************************************************************************
   1101 **
   1102 ** Function         allocate_svc_db_buf
   1103 **
   1104 ** Description      Utility function to allocate extra buffer for service database.
   1105 **
   1106 ** Returns          TRUE if allocation succeed, otherwise FALSE.
   1107 **
   1108 *******************************************************************************/
   1109 static BOOLEAN allocate_svc_db_buf(tGATT_SVC_DB *p_db)
   1110 {
   1111     BT_HDR  *p_buf;
   1112 
   1113     GATT_TRACE_DEBUG("allocate_svc_db_buf allocating extra buffer");
   1114 
   1115     if ((p_buf = (BT_HDR *)GKI_getpoolbuf(GATT_DB_POOL_ID)) == NULL)
   1116     {
   1117         GATT_TRACE_ERROR("allocate_svc_db_buf failed, no resources");
   1118         return FALSE;
   1119     }
   1120 
   1121     memset(p_buf, 0, GKI_get_buf_size(p_buf));
   1122     p_db->p_free_mem    = (UINT8 *) p_buf;
   1123     p_db->mem_free      = GKI_get_buf_size(p_buf);
   1124 
   1125     GKI_enqueue(&p_db->svc_buffer, p_buf);
   1126 
   1127     return TRUE;
   1128 
   1129 }
   1130 
   1131 /*******************************************************************************
   1132 **
   1133 ** Function         gatts_send_app_read_request
   1134 **
   1135 ** Description      Send application read request callback
   1136 **
   1137 ** Returns          status of operation.
   1138 **
   1139 *******************************************************************************/
   1140 static tGATT_STATUS gatts_send_app_read_request(tGATT_TCB *p_tcb, UINT8 op_code,
   1141                                                 UINT16 handle, UINT16 offset, UINT32 trans_id)
   1142 {
   1143     tGATTS_DATA   sr_data;
   1144     UINT8       i_rcb;
   1145     tGATT_SR_REG *p_sreg;
   1146     UINT16   conn_id;
   1147 
   1148     i_rcb = gatt_sr_find_i_rcb_by_handle(handle);
   1149     p_sreg = &gatt_cb.sr_reg[i_rcb];
   1150     conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_sreg->gatt_if);
   1151 
   1152     if (trans_id == 0)
   1153     {
   1154         trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle);
   1155         gatt_sr_update_cback_cnt(p_tcb, p_sreg->gatt_if, TRUE, TRUE);
   1156     }
   1157 
   1158     if (trans_id != 0 )
   1159     {
   1160         memset(&sr_data, 0, sizeof(tGATTS_DATA));
   1161 
   1162         sr_data.read_req.handle = handle;
   1163         sr_data.read_req.is_long = (BOOLEAN)(op_code == GATT_REQ_READ_BLOB);
   1164         sr_data.read_req.offset = offset;
   1165 
   1166         gatt_sr_send_req_callback(conn_id,
   1167                                   trans_id, GATTS_REQ_TYPE_READ, &sr_data);
   1168         return(tGATT_STATUS) GATT_PENDING;
   1169     }
   1170     else
   1171         return(tGATT_STATUS) GATT_BUSY; /* max pending command, application error */
   1172 
   1173 }
   1174 
   1175 /*******************************************************************************
   1176 **
   1177 ** Function         gatts_db_add_service_declaration
   1178 **
   1179 ** Description      Update a service database service declaration record.
   1180 **
   1181 ** Parameter        p_db: database pointer.
   1182 **                  service: UUID of the service.
   1183 **
   1184 ** Returns          void
   1185 **
   1186 *******************************************************************************/
   1187 static BOOLEAN gatts_db_add_service_declaration(tGATT_SVC_DB *p_db, tBT_UUID *p_service, BOOLEAN is_pri)
   1188 {
   1189     tGATT_ATTR16  *p_attr;
   1190     tBT_UUID    uuid = {LEN_UUID_16, {0}};
   1191     BOOLEAN     rt = FALSE;
   1192 
   1193     GATT_TRACE_DEBUG( "add_service_declaration");
   1194 
   1195     if (is_pri)
   1196         uuid.uu.uuid16 = GATT_UUID_PRI_SERVICE;
   1197     else
   1198         uuid.uu.uuid16 = GATT_UUID_SEC_SERVICE;
   1199 
   1200     /* add service declration record */
   1201     if ((p_attr = (tGATT_ATTR16 *)(allocate_attr_in_db(p_db, &uuid, GATT_PERM_READ))) != NULL)
   1202     {
   1203         if (copy_extra_byte_in_db (p_db, (void **)&p_attr->p_value, sizeof(tBT_UUID)))
   1204         {
   1205             if (p_service->len == LEN_UUID_16)
   1206             {
   1207                 p_attr->p_value->uuid.len = LEN_UUID_16;
   1208                 p_attr->p_value->uuid.uu.uuid16 = p_service->uu.uuid16;
   1209             }
   1210             else if (p_service->len == LEN_UUID_32)
   1211             {
   1212                 p_attr->p_value->uuid.len = LEN_UUID_128;
   1213                 gatt_convert_uuid32_to_uuid128(p_attr->p_value->uuid.uu.uuid128, p_service->uu.uuid32);
   1214             }
   1215             else
   1216             {
   1217                 p_attr->p_value->uuid.len = LEN_UUID_128;
   1218                 memcpy(p_attr->p_value->uuid.uu.uuid128, p_service->uu.uuid128, LEN_UUID_128);
   1219             }
   1220             rt = TRUE;
   1221         }
   1222 
   1223     }
   1224     return rt;
   1225 }
   1226 
   1227 #endif /* BLE_INCLUDED */
   1228