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