Home | History | Annotate | Download | only in gatt
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 1999-2012 Broadcom Corporation
      4  *
      5  *  Licensed under the Apache License, Version 2.0 (the "License");
      6  *  you may not use this file except in compliance with the License.
      7  *  You may obtain a copy of the License at:
      8  *
      9  *  http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  ******************************************************************************/
     18 
     19 /******************************************************************************
     20  *
     21  *  this file contains GATT interface functions
     22  *
     23  ******************************************************************************/
     24 #include "bt_target.h"
     25 
     26 
     27 #if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)
     28 
     29 #include "bt_common.h"
     30 #include <stdio.h>
     31 #include <string.h>
     32 #include "gatt_api.h"
     33 #include "gatt_int.h"
     34 #include "l2c_api.h"
     35 #include "btm_int.h"
     36 
     37 /*******************************************************************************
     38 **
     39 ** Function         GATT_SetTraceLevel
     40 **
     41 ** Description      This function sets the trace level.  If called with
     42 **                  a value of 0xFF, it simply returns the current trace level.
     43 **
     44 **                  Input Parameters:
     45 **                      level:  The level to set the GATT tracing to:
     46 **                      0xff-returns the current setting.
     47 **                      0-turns off tracing.
     48 **                      >= 1-Errors.
     49 **                      >= 2-Warnings.
     50 **                      >= 3-APIs.
     51 **                      >= 4-Events.
     52 **                      >= 5-Debug.
     53 **
     54 ** Returns          The new or current trace level
     55 **
     56 *******************************************************************************/
     57 UINT8 GATT_SetTraceLevel (UINT8 new_level)
     58 {
     59     if (new_level != 0xFF)
     60         gatt_cb.trace_level = new_level;
     61 
     62     return(gatt_cb.trace_level);
     63 }
     64 
     65 /*****************************************************************************
     66 **
     67 **                  GATT SERVER API
     68 **
     69 ******************************************************************************/
     70 /*******************************************************************************
     71 **
     72 ** Function         GATTS_AddHandleRange
     73 **
     74 ** Description      This function add the allocated handles range for the specifed
     75 **                  application UUID, service UUID and service instance
     76 **
     77 ** Parameter        p_hndl_range:   pointer to allocated handles information
     78 **
     79 ** Returns          TRUE if handle range is added sucessfully; otherwise FALSE.
     80 **
     81 *******************************************************************************/
     82 
     83 BOOLEAN GATTS_AddHandleRange(tGATTS_HNDL_RANGE *p_hndl_range)
     84 {
     85     tGATT_HDL_LIST_ELEM *p_buf;
     86     BOOLEAN status= FALSE;
     87 
     88     if ((p_buf = gatt_alloc_hdl_buffer()) != NULL)
     89     {
     90         p_buf->asgn_range = *p_hndl_range;
     91         status  = gatt_add_an_item_to_list(&gatt_cb.hdl_list_info, p_buf);
     92     }
     93     return status;
     94 }
     95 
     96 
     97 /*******************************************************************************
     98 **
     99 ** Function         GATTS_NVRegister
    100 **
    101 ** Description      Application manager calls this function to register for
    102 **                  NV save callback function.  There can be one and only one
    103 **                  NV save callback function.
    104 **
    105 ** Parameter        p_cb_info : callback informaiton
    106 **
    107 ** Returns          TRUE if registered OK, else FALSE
    108 **
    109 *******************************************************************************/
    110 BOOLEAN  GATTS_NVRegister (tGATT_APPL_INFO *p_cb_info)
    111 {
    112     BOOLEAN status= FALSE;
    113     if (p_cb_info)
    114     {
    115         gatt_cb.cb_info = *p_cb_info;
    116         status = TRUE;
    117         gatt_init_srv_chg();
    118     }
    119 
    120     return status;
    121 }
    122 
    123 /*******************************************************************************
    124 **
    125 ** Function         GATTS_CreateService
    126 **
    127 ** Description      This function is called to reserve a block of handles for a service.
    128 **
    129 **                  *** It should be called only once per service instance  ***
    130 **
    131 ** Parameter        gatt_if       : application if
    132 **                  p_svc_uuid    : service UUID
    133 **                  svc_inst      : instance of the service inside the application
    134 **                  num_handles   : number of handles needed by the service.
    135 **                  is_pri        : is a primary service or not.
    136 **
    137 ** Returns          service handle if sucessful, otherwise 0.
    138 **
    139 *******************************************************************************/
    140 UINT16 GATTS_CreateService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid,
    141                             UINT16 svc_inst, UINT16 num_handles, BOOLEAN is_pri)
    142 {
    143 
    144     tGATT_HDL_LIST_INFO     *p_list_info= &gatt_cb.hdl_list_info;
    145     tGATT_HDL_LIST_ELEM     *p_list=NULL;
    146     UINT16                  s_hdl=0;
    147     BOOLEAN                 save_hdl=FALSE;
    148     tGATTS_PENDING_NEW_SRV_START      *p_buf=NULL;
    149     tGATT_REG              *p_reg = gatt_get_regcb(gatt_if);
    150     tBT_UUID     *p_app_uuid128;
    151 
    152 
    153     GATT_TRACE_API ("GATTS_CreateService" );
    154 
    155     if (p_reg == NULL)
    156     {
    157         GATT_TRACE_ERROR ("Inavlid gatt_if=%d", gatt_if);
    158         return(0);
    159     }
    160 
    161     p_app_uuid128 = &p_reg->app_uuid128;
    162 
    163     if ((p_list = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst)) != NULL)
    164     {
    165         s_hdl = p_list->asgn_range.s_handle;
    166         GATT_TRACE_DEBUG ("Service already been created!!");
    167     }
    168     else
    169     {
    170         if ( (p_svc_uuid->len == LEN_UUID_16) && (p_svc_uuid->uu.uuid16 == UUID_SERVCLASS_GATT_SERVER))
    171         {
    172             s_hdl=  gatt_cb.hdl_cfg.gatt_start_hdl;
    173         }
    174         else if ((p_svc_uuid->len == LEN_UUID_16) && (p_svc_uuid->uu.uuid16 == UUID_SERVCLASS_GAP_SERVER))
    175         {
    176             s_hdl= gatt_cb.hdl_cfg.gap_start_hdl;
    177         }
    178         else
    179         {
    180             p_list = p_list_info->p_first;
    181 
    182             if (p_list)
    183             {
    184                 s_hdl = p_list->asgn_range.e_handle + 1;
    185             }
    186 
    187             if (s_hdl < gatt_cb.hdl_cfg.app_start_hdl)
    188             {
    189 
    190                 s_hdl= gatt_cb.hdl_cfg.app_start_hdl;
    191             }
    192             save_hdl = TRUE;
    193         }
    194 
    195         /* check for space */
    196         if (num_handles > (0xFFFF - s_hdl + 1))
    197         {
    198             GATT_TRACE_ERROR ("GATTS_ReserveHandles: no handles, s_hdl: %u  needed: %u", s_hdl, num_handles);
    199             return(0);
    200         }
    201 
    202         if ( (p_list = gatt_alloc_hdl_buffer()) == NULL)
    203         {
    204             /* No free entry */
    205             GATT_TRACE_ERROR ("GATTS_ReserveHandles: no free handle blocks");
    206             return(0);
    207         }
    208 
    209         p_list->asgn_range.app_uuid128 = *p_app_uuid128;
    210         p_list->asgn_range.svc_uuid    = *p_svc_uuid;
    211         p_list->asgn_range.svc_inst    = svc_inst;
    212         p_list->asgn_range.s_handle    = s_hdl;
    213         p_list->asgn_range.e_handle    = s_hdl+num_handles-1;
    214         p_list->asgn_range.is_primary  = is_pri;
    215 
    216         gatt_add_an_item_to_list(p_list_info, p_list);
    217 
    218         if (save_hdl)
    219         {
    220             if (gatt_cb.cb_info.p_nv_save_callback)
    221                 (*gatt_cb.cb_info.p_nv_save_callback)(TRUE, &p_list->asgn_range);
    222             /* add a pending new  service change item to the list */
    223             if ( (p_buf = gatt_add_pending_new_srv_start(&p_list->asgn_range)) == NULL)
    224             {
    225                 /* No free entry */
    226                 GATT_TRACE_ERROR ("gatt_add_pending_new_srv_start: no free blocks");
    227 
    228                 if (p_list)
    229                 {
    230                     gatt_remove_an_item_from_list(p_list_info, p_list);
    231                     gatt_free_hdl_buffer(p_list);
    232                 }
    233                 return(0);
    234             }
    235 
    236             GATT_TRACE_DEBUG ("Add a new srv chg item");
    237         }
    238     }
    239 
    240     if (!gatts_init_service_db(&p_list->svc_db, p_svc_uuid, is_pri, s_hdl , num_handles))
    241     {
    242         GATT_TRACE_ERROR ("GATTS_ReserveHandles: service DB initialization failed");
    243         if (p_list)
    244         {
    245             gatt_remove_an_item_from_list(p_list_info, p_list);
    246             gatt_free_hdl_buffer(p_list);
    247         }
    248 
    249         if (p_buf)
    250             osi_free(fixed_queue_try_remove_from_queue(gatt_cb.pending_new_srv_start_q, p_buf));
    251         return(0);
    252     }
    253 
    254     GATT_TRACE_DEBUG ("GATTS_CreateService(success): handles needed:%u s_hdl=%u e_hdl=%u %s[%x] is_primary=%d",
    255                        num_handles, p_list->asgn_range.s_handle , p_list->asgn_range.e_handle,
    256                        ((p_list->asgn_range.svc_uuid.len == 2) ? "uuid16": "uuid128" ),
    257                        p_list->asgn_range.svc_uuid.uu.uuid16,
    258                        p_list->asgn_range.is_primary);
    259 
    260     return(s_hdl);
    261 }
    262 
    263 /*******************************************************************************
    264 **
    265 ** Function         GATTS_AddIncludeService
    266 **
    267 ** Description      This function is called to add an included service.
    268 **
    269 ** Parameter        service_handle : To which service this included service is added to.
    270 **                  include_svc_handle    : included service handle.
    271 **
    272 ** Returns          included service attribute handle. If 0, add included service
    273 **                  fail.
    274 **
    275 *******************************************************************************/
    276 UINT16 GATTS_AddIncludeService (UINT16 service_handle, UINT16 include_svc_handle)
    277 
    278 {
    279     tGATT_HDL_LIST_ELEM  *p_decl, *p_incl_decl;
    280 
    281     if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL)
    282     {
    283         GATT_TRACE_DEBUG("Service not created");
    284         return 0;
    285     }
    286     if ((p_incl_decl = gatt_find_hdl_buffer_by_handle(include_svc_handle)) == NULL)
    287     {
    288         GATT_TRACE_DEBUG("Included Service not created");
    289         return 0;
    290     }
    291 
    292     return gatts_add_included_service(&p_decl->svc_db,
    293                                       p_incl_decl->asgn_range.s_handle,
    294                                       p_incl_decl->asgn_range.e_handle,
    295                                       p_incl_decl->asgn_range.svc_uuid);
    296 }
    297 /*******************************************************************************
    298 **
    299 ** Function         GATTS_AddCharacteristic
    300 **
    301 ** Description      This function is called to add a characteristic into a service.
    302 **                  It will add a characteristic declaration and characteristic
    303 **                  value declaration into the service database identified by the
    304 **                  service handle.
    305 **
    306 ** Parameter        service_handle : To which service this included service is added to.
    307 **                  char_uuid : Characteristic UUID.
    308 **                  perm      : Characteristic value declaration attribute permission.
    309 **                  property  : Characteristic Properties
    310 **
    311 ** Returns          Characteristic value declaration attribute handle. 0 if failed.
    312 **
    313 *******************************************************************************/
    314 UINT16 GATTS_AddCharacteristic (UINT16 service_handle, tBT_UUID *p_char_uuid,
    315                                 tGATT_PERM perm,tGATT_CHAR_PROP property)
    316 {
    317     tGATT_HDL_LIST_ELEM  *p_decl;
    318 
    319     if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL)
    320     {
    321         GATT_TRACE_DEBUG("Service not created");
    322         return 0;
    323     }
    324     /* data validity checking */
    325     if (  ((property & GATT_CHAR_PROP_BIT_AUTH) && !(perm & GATT_WRITE_SIGNED_PERM)) ||
    326           ((perm & GATT_WRITE_SIGNED_PERM) && !(property & GATT_CHAR_PROP_BIT_AUTH)) )
    327     {
    328         GATT_TRACE_DEBUG("Invalid configuration property=0x%x perm=0x%x ", property, perm);
    329         return 0;
    330     }
    331 
    332     return gatts_add_characteristic(&p_decl->svc_db,
    333                                     perm,
    334                                     property,
    335                                     p_char_uuid);
    336 }
    337 /*******************************************************************************
    338 **
    339 ** Function         GATTS_AddCharDescriptor
    340 **
    341 ** Description      This function is called to add a characteristic descriptor
    342 **                  into a service database. Add descriptor should follow add char
    343 **                  to which it belongs, and next add char should be done only
    344 **                  after all add descriptors for the previous char.
    345 **
    346 ** Parameter        service_handle  : To which service this characteristic descriptor
    347 **                                    is added to.
    348 **                  perm            : Characteristic value declaration attribute
    349 **                                    permission.
    350 **                  p_descr_uuid    : Characteristic descriptor UUID
    351 **
    352 ** Returns         Characteristic descriptor attribute handle. 0 if add
    353 **                 characteristic descriptor failed.
    354 **
    355 *******************************************************************************/
    356 UINT16 GATTS_AddCharDescriptor (UINT16 service_handle,
    357                                  tGATT_PERM perm,
    358                                  tBT_UUID  * p_descr_uuid)
    359 {
    360     tGATT_HDL_LIST_ELEM  *p_decl;
    361 
    362     if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL)
    363     {
    364         GATT_TRACE_DEBUG("Service not created");
    365         return 0;
    366     }
    367     if (p_descr_uuid == NULL ||
    368         (p_descr_uuid->len != LEN_UUID_128 && p_descr_uuid->len !=  LEN_UUID_16
    369          && p_descr_uuid->len !=  LEN_UUID_32))
    370     {
    371         GATT_TRACE_DEBUG("Illegal parameter");
    372         return 0;
    373     }
    374 
    375     return gatts_add_char_descr(&p_decl->svc_db,
    376                                 perm,
    377                                 p_descr_uuid);
    378 
    379 }
    380 /*******************************************************************************
    381 **
    382 ** Function         GATTS_DeleteService
    383 **
    384 ** Description      This function is called to delete a service.
    385 **
    386 ** Parameter        gatt_if       : application interface
    387 **                  p_svc_uuid    : service UUID
    388 **                  svc_inst      : instance of the service inside the application
    389 **
    390 ** Returns          TRUE if operation succeed, FALSE if handle block was not found.
    391 **
    392 *******************************************************************************/
    393 BOOLEAN GATTS_DeleteService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, UINT16 svc_inst)
    394 {
    395 
    396     tGATT_HDL_LIST_INFO             *p_list_info= &gatt_cb.hdl_list_info;
    397     tGATT_HDL_LIST_ELEM             *p_list=NULL;
    398     UINT8                           i_sreg;
    399     tGATTS_PENDING_NEW_SRV_START    *p_buf;
    400     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
    401     tBT_UUID *p_app_uuid128;
    402 
    403     GATT_TRACE_DEBUG ("GATTS_DeleteService");
    404 
    405     if (p_reg == NULL)
    406     {
    407         GATT_TRACE_ERROR ("Applicaiton not foud");
    408         return(FALSE);
    409     }
    410     p_app_uuid128 = &p_reg->app_uuid128;
    411 
    412     if ((p_list = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst)) == NULL)
    413     {
    414         GATT_TRACE_ERROR ("No Service found");
    415         return(FALSE);
    416     }
    417 
    418     if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128,
    419                                          &p_list->asgn_range.svc_uuid,
    420                                          p_list->asgn_range.svc_inst)) != NULL)
    421     {
    422         GATT_TRACE_DEBUG ("Delete a new service changed item - the service has not yet started");
    423         osi_free(fixed_queue_try_remove_from_queue(gatt_cb.pending_new_srv_start_q, p_buf));
    424     }
    425     else
    426     {
    427         gatt_proc_srv_chg();
    428     }
    429 
    430     if ((i_sreg = gatt_sr_find_i_rcb_by_app_id (p_app_uuid128,
    431                                                 p_svc_uuid,
    432                                                 svc_inst)) != GATT_MAX_SR_PROFILES)
    433     {
    434         GATTS_StopService(gatt_cb.sr_reg[i_sreg].s_hdl);
    435     }
    436 
    437     GATT_TRACE_DEBUG ("released handles s_hdl=%u e_hdl=%u",
    438                        p_list->asgn_range.s_handle , p_list->asgn_range.e_handle  );
    439 
    440     if ( (p_list->asgn_range.s_handle >= gatt_cb.hdl_cfg.app_start_hdl)
    441          && gatt_cb.cb_info.p_nv_save_callback)
    442         (*gatt_cb.cb_info.p_nv_save_callback)(FALSE, &p_list->asgn_range);
    443 
    444     gatt_remove_an_item_from_list(p_list_info, p_list);
    445     gatt_free_hdl_buffer(p_list);
    446 
    447     return(TRUE);
    448 }
    449 
    450 /*******************************************************************************
    451 **
    452 ** Function         GATTS_StartService
    453 **
    454 ** Description      This function is called to start a service with GATT
    455 **
    456 ** Parameter        gatt_if : service handle.
    457 **                  p_cback       : application service callback functions.
    458 **                  sup_transport : supported transport(s) for this primary service
    459 **
    460 ** return           GATT_SUCCESS if sucessfully started; otherwise error code.
    461 **
    462 *******************************************************************************/
    463 tGATT_STATUS GATTS_StartService (tGATT_IF gatt_if, UINT16 service_handle,
    464                                  tGATT_TRANSPORT sup_transport)
    465 {
    466     tGATT_SR_REG            *p_sreg;
    467     tGATT_HDL_LIST_ELEM      *p_list=NULL;
    468     UINT8                    i_sreg;
    469     tBT_UUID                *p_uuid;
    470     tGATT_REG              *p_reg = gatt_get_regcb(gatt_if);
    471 
    472     tGATTS_PENDING_NEW_SRV_START *p_buf;
    473 
    474     GATT_TRACE_API ("GATTS_StartService");
    475 
    476     if (p_reg == NULL)
    477     {
    478         /* Not found  */
    479         GATT_TRACE_ERROR ("Applicaiton not found ");
    480         return GATT_NOT_FOUND;
    481     }
    482 
    483     if ((p_list = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL)
    484     {
    485         /* Not found  */
    486         GATT_TRACE_ERROR ("no service found");
    487         return GATT_NOT_FOUND;
    488     }
    489 
    490     if (gatt_sr_find_i_rcb_by_app_id (&p_list->asgn_range.app_uuid128,
    491                                       &p_list->asgn_range.svc_uuid,
    492                                       p_list->asgn_range.svc_inst) != GATT_MAX_SR_PROFILES)
    493     {
    494         GATT_TRACE_ERROR ("Duplicate Service start - Service already started");
    495         return GATT_SERVICE_STARTED;
    496     }
    497 
    498     /*this is a new application servoce start */
    499     if ((i_sreg = gatt_sr_alloc_rcb(p_list)) ==  GATT_MAX_SR_PROFILES)
    500     {
    501         GATT_TRACE_ERROR ("GATTS_StartService: no free server registration block");
    502         return GATT_NO_RESOURCES;
    503     }
    504 
    505     p_sreg = &gatt_cb.sr_reg[i_sreg];
    506     p_sreg->gatt_if = gatt_if;
    507 
    508     switch (sup_transport)
    509     {
    510         case GATT_TRANSPORT_BR_EDR:
    511         case GATT_TRANSPORT_LE_BR_EDR:
    512             if (p_sreg->type == GATT_UUID_PRI_SERVICE)
    513             {
    514                 p_uuid = gatts_get_service_uuid (p_sreg->p_db);
    515 
    516                 p_sreg->sdp_handle = gatt_add_sdp_record(p_uuid, p_sreg->s_hdl, p_sreg->e_hdl);
    517             }
    518             break;
    519         default:
    520             break;
    521     }
    522 
    523     gatts_update_srv_list_elem(i_sreg, p_sreg->s_hdl,
    524                                p_list->asgn_range.is_primary);
    525 
    526     gatt_add_a_srv_to_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[i_sreg]);
    527 
    528     GATT_TRACE_DEBUG ("allocated i_sreg=%d ",i_sreg);
    529 
    530     GATT_TRACE_DEBUG ("s_hdl=%d e_hdl=%d type=0x%x svc_inst=%d sdp_hdl=0x%x",
    531                        p_sreg->s_hdl,p_sreg->e_hdl,
    532                        p_sreg->type,  p_sreg->service_instance,
    533                        p_sreg->sdp_handle);
    534 
    535 
    536     if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128,
    537                                          &p_list->asgn_range.svc_uuid,
    538                                          p_list->asgn_range.svc_inst)) != NULL)
    539     {
    540         gatt_proc_srv_chg();
    541         /* remove the new service element after the srv changed processing is completed*/
    542 
    543         osi_free(fixed_queue_try_remove_from_queue(gatt_cb.pending_new_srv_start_q, p_buf));
    544     }
    545     return GATT_SUCCESS;
    546 }
    547 
    548 /*******************************************************************************
    549 **
    550 ** Function         GATTS_StopService
    551 **
    552 ** Description      This function is called to stop a service
    553 **
    554 ** Parameter         service_handle : this is the start handle of a service
    555 **
    556 ** Returns          None.
    557 **
    558 *******************************************************************************/
    559 void GATTS_StopService (UINT16 service_handle)
    560 {
    561     UINT8           ii = gatt_sr_find_i_rcb_by_handle(service_handle);
    562 
    563     GATT_TRACE_API("GATTS_StopService %u", service_handle);
    564 
    565     /* Index 0 is reserved for GATT, and is never stopped */
    566     if ( (ii > 0) && (ii < GATT_MAX_SR_PROFILES) && (gatt_cb.sr_reg[ii].in_use) )
    567     {
    568         if (gatt_cb.sr_reg[ii].sdp_handle)
    569         {
    570             SDP_DeleteRecord(gatt_cb.sr_reg[ii].sdp_handle);
    571         }
    572         gatt_remove_a_srv_from_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[ii]);
    573         gatt_cb.srv_list[ii].in_use = FALSE;
    574         memset (&gatt_cb.sr_reg[ii], 0, sizeof(tGATT_SR_REG));
    575     }
    576     else
    577     {
    578         GATT_TRACE_ERROR("GATTS_StopService service_handle: %u is not in use", service_handle);
    579     }
    580 }
    581 /*******************************************************************************
    582 **
    583 ** Function         GATTs_HandleValueIndication
    584 **
    585 ** Description      This function sends a handle value indication to a client.
    586 **
    587 ** Parameter        conn_id: connection identifier.
    588 **                  attr_handle: Attribute handle of this handle value indication.
    589 **                  val_len: Length of the indicated attribute value.
    590 **                  p_val: Pointer to the indicated attribute value data.
    591 **
    592 ** Returns          GATT_SUCCESS if sucessfully sent or queued; otherwise error code.
    593 **
    594 *******************************************************************************/
    595 tGATT_STATUS GATTS_HandleValueIndication (UINT16 conn_id,  UINT16 attr_handle, UINT16 val_len, UINT8 *p_val)
    596 {
    597     tGATT_STATUS    cmd_status = GATT_NO_RESOURCES;
    598 
    599     tGATT_VALUE      indication;
    600     BT_HDR          *p_msg;
    601     tGATT_VALUE     *p_buf;
    602     tGATT_IF         gatt_if = GATT_GET_GATT_IF(conn_id);
    603     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
    604     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
    605     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
    606 
    607 
    608     GATT_TRACE_API ("GATTS_HandleValueIndication");
    609     if ( (p_reg == NULL) || (p_tcb == NULL))
    610     {
    611         GATT_TRACE_ERROR ("GATTS_HandleValueIndication Unknown  conn_id: %u ", conn_id);
    612         return(tGATT_STATUS) GATT_INVALID_CONN_ID;
    613     }
    614 
    615     if (! GATT_HANDLE_IS_VALID (attr_handle))
    616         return GATT_ILLEGAL_PARAMETER;
    617 
    618     indication.conn_id  = conn_id;
    619     indication.handle   = attr_handle;
    620     indication.len      = val_len;
    621     memcpy (indication.value, p_val, val_len);
    622     indication.auth_req = GATT_AUTH_REQ_NONE;
    623 
    624     if (GATT_HANDLE_IS_VALID(p_tcb->indicate_handle))
    625     {
    626         GATT_TRACE_DEBUG ("Add a pending indication");
    627         if ((p_buf = gatt_add_pending_ind(p_tcb, &indication)) !=NULL)
    628         {
    629             cmd_status = GATT_SUCCESS;
    630         }
    631         else
    632         {
    633             cmd_status = GATT_NO_RESOURCES;
    634         }
    635     }
    636     else
    637     {
    638 
    639         if ( (p_msg = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_IND, (tGATT_SR_MSG *)&indication)) != NULL)
    640         {
    641             cmd_status = attp_send_sr_msg (p_tcb, p_msg);
    642 
    643             if (cmd_status == GATT_SUCCESS || cmd_status == GATT_CONGESTED)
    644             {
    645                 p_tcb->indicate_handle = indication.handle;
    646                 gatt_start_conf_timer(p_tcb);
    647             }
    648         }
    649     }
    650     return cmd_status;
    651 }
    652 
    653 /*******************************************************************************
    654 **
    655 ** Function         GATTS_HandleValueNotification
    656 **
    657 ** Description      This function sends a handle value notification to a client.
    658 **
    659 ** Parameter        conn_id: connection identifier.
    660 **                  attr_handle: Attribute handle of this handle value indication.
    661 **                  val_len: Length of the indicated attribute value.
    662 **                  p_val: Pointer to the indicated attribute value data.
    663 **
    664 ** Returns          GATT_SUCCESS if sucessfully sent; otherwise error code.
    665 **
    666 *******************************************************************************/
    667 tGATT_STATUS GATTS_HandleValueNotification (UINT16 conn_id, UINT16 attr_handle,
    668                                             UINT16 val_len, UINT8 *p_val)
    669 {
    670     tGATT_STATUS    cmd_sent = GATT_ILLEGAL_PARAMETER;
    671     BT_HDR          *p_buf;
    672     tGATT_VALUE     notif;
    673     tGATT_IF         gatt_if = GATT_GET_GATT_IF(conn_id);
    674     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
    675     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
    676     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
    677 
    678     GATT_TRACE_API ("GATTS_HandleValueNotification");
    679 
    680     if ( (p_reg == NULL) || (p_tcb == NULL))
    681     {
    682         GATT_TRACE_ERROR ("GATTS_HandleValueNotification Unknown  conn_id: %u ", conn_id);
    683         return(tGATT_STATUS) GATT_INVALID_CONN_ID;
    684     }
    685 
    686     if (GATT_HANDLE_IS_VALID (attr_handle))
    687     {
    688         notif.handle    = attr_handle;
    689         notif.len       = val_len;
    690         memcpy (notif.value, p_val, val_len);
    691         notif.auth_req = GATT_AUTH_REQ_NONE;;
    692 
    693         if ((p_buf = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_NOTIF, (tGATT_SR_MSG *)&notif))
    694                    != NULL)
    695         {
    696             cmd_sent = attp_send_sr_msg (p_tcb, p_buf);
    697         }
    698         else
    699             cmd_sent = GATT_NO_RESOURCES;
    700     }
    701     return cmd_sent;
    702 }
    703 
    704 /*******************************************************************************
    705 **
    706 ** Function         GATTS_SendRsp
    707 **
    708 ** Description      This function sends the server response to client.
    709 **
    710 ** Parameter        conn_id: connection identifier.
    711 **                  trans_id: transaction id
    712 **                  status: response status
    713 **                  p_msg: pointer to message parameters structure.
    714 **
    715 ** Returns          GATT_SUCCESS if sucessfully sent; otherwise error code.
    716 **
    717 *******************************************************************************/
    718 tGATT_STATUS GATTS_SendRsp (UINT16 conn_id,  UINT32 trans_id,
    719                             tGATT_STATUS status, tGATTS_RSP *p_msg)
    720 {
    721     tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER;
    722     tGATT_IF         gatt_if = GATT_GET_GATT_IF(conn_id);
    723     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
    724     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
    725     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
    726 
    727     GATT_TRACE_API ("GATTS_SendRsp: conn_id: %u  trans_id: %u  Status: 0x%04x",
    728                      conn_id, trans_id, status);
    729 
    730     if ( (p_reg == NULL) || (p_tcb == NULL))
    731     {
    732         GATT_TRACE_ERROR ("GATTS_SendRsp Unknown  conn_id: %u ", conn_id);
    733         return(tGATT_STATUS) GATT_INVALID_CONN_ID;
    734     }
    735 
    736     if (p_tcb->sr_cmd.trans_id != trans_id)
    737     {
    738         GATT_TRACE_ERROR ("GATTS_SendRsp conn_id: %u  waiting for op_code = %02x",
    739                            conn_id, p_tcb->sr_cmd.op_code);
    740 
    741         return(GATT_WRONG_STATE);
    742     }
    743     /* Process App response */
    744     cmd_sent = gatt_sr_process_app_rsp (p_tcb,  gatt_if, trans_id, p_tcb->sr_cmd.op_code, status, p_msg);
    745 
    746     return cmd_sent;
    747 }
    748 
    749 /*******************************************************************************/
    750 /* GATT Profile Srvr Functions */
    751 /*******************************************************************************/
    752 
    753 /*******************************************************************************/
    754 /*                                                                             */
    755 /*                   GATT CLIENT APIs                                          */
    756 /*                                                                             */
    757 /*******************************************************************************/
    758 
    759 
    760 /*******************************************************************************
    761 **
    762 ** Function         GATTC_ConfigureMTU
    763 **
    764 ** Description      This function is called to configure the ATT MTU size.
    765 **
    766 ** Parameters       conn_id: connection identifier.
    767 **                  mtu    - attribute MTU size..
    768 **
    769 ** Returns          GATT_SUCCESS if command started successfully.
    770 **
    771 *******************************************************************************/
    772 tGATT_STATUS GATTC_ConfigureMTU (UINT16 conn_id, UINT16 mtu)
    773 {
    774     UINT8           ret = GATT_NO_RESOURCES;
    775     tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
    776     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
    777     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
    778     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
    779 
    780     tGATT_CLCB    *p_clcb;
    781 
    782     GATT_TRACE_API ("GATTC_ConfigureMTU conn_id=%d mtu=%d", conn_id, mtu );
    783 
    784     /* Validate that the link is BLE, not BR/EDR */
    785     if (p_tcb->transport != BT_TRANSPORT_LE)
    786     {
    787         return GATT_ERROR;
    788     }
    789 
    790     if ( (p_tcb == NULL) || (p_reg==NULL) || (mtu < GATT_DEF_BLE_MTU_SIZE) || (mtu > GATT_MAX_MTU_SIZE))
    791     {
    792         return GATT_ILLEGAL_PARAMETER;
    793     }
    794 
    795     if (gatt_is_clcb_allocated(conn_id))
    796     {
    797         GATT_TRACE_ERROR("GATTC_ConfigureMTU GATT_BUSY conn_id = %d", conn_id);
    798         return GATT_BUSY;
    799     }
    800 
    801     if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL)
    802     {
    803         p_clcb->p_tcb->payload_size = mtu;
    804         p_clcb->operation = GATTC_OPTYPE_CONFIG;
    805 
    806         ret = attp_send_cl_msg (p_clcb->p_tcb, p_clcb->clcb_idx, GATT_REQ_MTU, (tGATT_CL_MSG *)&mtu);
    807     }
    808 
    809     return ret;
    810 }
    811 
    812 /*******************************************************************************
    813 **
    814 ** Function         GATTC_Discover
    815 **
    816 ** Description      This function is called to do a discovery procedure on ATT server.
    817 **
    818 ** Parameters       conn_id: connection identifier.
    819 **                  disc_type:discovery type.
    820 **                  p_param: parameters of discovery requirement.
    821 **
    822 ** Returns          GATT_SUCCESS if command received/sent successfully.
    823 **
    824 *******************************************************************************/
    825 tGATT_STATUS GATTC_Discover (UINT16 conn_id, tGATT_DISC_TYPE disc_type,
    826                              tGATT_DISC_PARAM *p_param)
    827 {
    828     tGATT_STATUS    status = GATT_SUCCESS;
    829     tGATT_CLCB      *p_clcb;
    830     tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
    831     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
    832     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
    833     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
    834 
    835 
    836     GATT_TRACE_API ("GATTC_Discover conn_id=%d disc_type=%d",conn_id, disc_type);
    837 
    838     if ( (p_tcb == NULL) || (p_reg==NULL) ||(p_param == NULL) ||
    839          (disc_type >= GATT_DISC_MAX))
    840     {
    841         GATT_TRACE_ERROR("GATTC_Discover Illegal param: disc_type %d conn_id = %d", disc_type, conn_id);
    842         return GATT_ILLEGAL_PARAMETER;
    843     }
    844 
    845 
    846     if (gatt_is_clcb_allocated(conn_id))
    847     {
    848         GATT_TRACE_ERROR("GATTC_Discover GATT_BUSY conn_id = %d", conn_id);
    849         return GATT_BUSY;
    850     }
    851 
    852 
    853     if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
    854     {
    855         if (!GATT_HANDLE_IS_VALID(p_param->s_handle) ||
    856             !GATT_HANDLE_IS_VALID(p_param->e_handle) ||
    857             /* search by type does not have a valid UUID param */
    858             (disc_type == GATT_DISC_SRVC_BY_UUID &&
    859              p_param->service.len == 0))
    860         {
    861             gatt_clcb_dealloc(p_clcb);
    862             return GATT_ILLEGAL_PARAMETER;
    863         }
    864 
    865         p_clcb->operation  = GATTC_OPTYPE_DISCOVERY;
    866         p_clcb->op_subtype = disc_type;
    867         p_clcb->s_handle   = p_param->s_handle;
    868         p_clcb->e_handle   = p_param->e_handle;
    869         p_clcb->uuid       = p_param->service;
    870 
    871         gatt_act_discovery(p_clcb);
    872     }
    873     else
    874     {
    875         status = GATT_NO_RESOURCES;
    876     }
    877     return status;
    878 }
    879 
    880 /*******************************************************************************
    881 **
    882 ** Function         GATTC_Read
    883 **
    884 ** Description      This function is called to read the value of an attribute from
    885 **                  the server.
    886 **
    887 ** Parameters       conn_id: connection identifier.
    888 **                  type    - attribute read type.
    889 **                  p_read  - read operation parameters.
    890 **
    891 ** Returns          GATT_SUCCESS if command started successfully.
    892 **
    893 *******************************************************************************/
    894 tGATT_STATUS GATTC_Read (UINT16 conn_id, tGATT_READ_TYPE type, tGATT_READ_PARAM *p_read)
    895 {
    896     tGATT_STATUS status = GATT_SUCCESS;
    897     tGATT_CLCB          *p_clcb;
    898     tGATT_IF            gatt_if=GATT_GET_GATT_IF(conn_id);
    899     UINT8               tcb_idx = GATT_GET_TCB_IDX(conn_id);
    900     tGATT_TCB           *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
    901     tGATT_REG           *p_reg = gatt_get_regcb(gatt_if);
    902 
    903 
    904     GATT_TRACE_API ("GATTC_Read conn_id=%d type=%d", conn_id, type);
    905 
    906     if ( (p_tcb == NULL) || (p_reg==NULL) || (p_read == NULL) || ((type >= GATT_READ_MAX) || (type == 0)))
    907     {
    908         GATT_TRACE_ERROR("GATT_Read Illegal param: conn_id %d, type 0%d,", conn_id, type);
    909         return GATT_ILLEGAL_PARAMETER;
    910     }
    911 
    912     if (gatt_is_clcb_allocated(conn_id))
    913     {
    914         GATT_TRACE_ERROR("GATTC_Read GATT_BUSY conn_id = %d", conn_id);
    915         return GATT_BUSY;
    916     }
    917 
    918     if ( (p_clcb = gatt_clcb_alloc(conn_id)) != NULL  )
    919     {
    920         p_clcb->operation = GATTC_OPTYPE_READ;
    921         p_clcb->op_subtype = type;
    922         p_clcb->auth_req = p_read->by_handle.auth_req;
    923         p_clcb->counter = 0;
    924 
    925         switch (type)
    926         {
    927             case GATT_READ_BY_TYPE:
    928             case GATT_READ_CHAR_VALUE:
    929                 p_clcb->s_handle = p_read->service.s_handle;
    930                 p_clcb->e_handle = p_read->service.e_handle;
    931                 memcpy(&p_clcb->uuid, &p_read->service.uuid, sizeof(tBT_UUID));
    932                 break;
    933             case GATT_READ_MULTIPLE:
    934                 p_clcb->s_handle = 0;
    935                 /* copy multiple handles in CB */
    936                 tGATT_READ_MULTI *p_read_multi =
    937                     (tGATT_READ_MULTI *)osi_malloc(sizeof(tGATT_READ_MULTI));
    938                 p_clcb->p_attr_buf = (UINT8*)p_read_multi;
    939                 memcpy(p_read_multi, &p_read->read_multiple, sizeof(tGATT_READ_MULTI));
    940             case GATT_READ_BY_HANDLE:
    941             case GATT_READ_PARTIAL:
    942                 memset(&p_clcb->uuid, 0, sizeof(tBT_UUID));
    943                 p_clcb->s_handle = p_read->by_handle.handle;
    944 
    945                 if (type == GATT_READ_PARTIAL)
    946                 {
    947                     p_clcb->counter = p_read->partial.offset;
    948                 }
    949 
    950                 break;
    951             default:
    952                 break;
    953         }
    954         /* start security check */
    955         if (gatt_security_check_start(p_clcb) == FALSE)
    956         {
    957             status = GATT_NO_RESOURCES;
    958             gatt_clcb_dealloc(p_clcb);
    959         }
    960     }
    961     else
    962     {
    963         status = GATT_NO_RESOURCES;
    964     }
    965     return status;
    966 }
    967 
    968 /*******************************************************************************
    969 **
    970 ** Function         GATTC_Write
    971 **
    972 ** Description      This function is called to write the value of an attribute to
    973 **                  the server.
    974 **
    975 ** Parameters       conn_id: connection identifier.
    976 **                  type    - attribute write type.
    977 **                  p_write  - write operation parameters.
    978 **
    979 ** Returns          GATT_SUCCESS if command started successfully.
    980 **
    981 *******************************************************************************/
    982 tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write)
    983 {
    984     tGATT_STATUS status = GATT_SUCCESS;
    985     tGATT_CLCB      *p_clcb;
    986     tGATT_VALUE     *p;
    987     tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
    988     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
    989     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
    990     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
    991 
    992     if ( (p_tcb == NULL) || (p_reg==NULL) || (p_write == NULL) ||
    993          ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && (type != GATT_WRITE_NO_RSP)) )
    994     {
    995         GATT_TRACE_ERROR("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id, type);
    996         return GATT_ILLEGAL_PARAMETER;
    997     }
    998 
    999     if (gatt_is_clcb_allocated(conn_id))
   1000     {
   1001         GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
   1002         return GATT_BUSY;
   1003     }
   1004 
   1005     if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
   1006     {
   1007         p_clcb->operation  = GATTC_OPTYPE_WRITE;
   1008         p_clcb->op_subtype = type;
   1009         p_clcb->auth_req = p_write->auth_req;
   1010 
   1011         p_clcb->p_attr_buf = (UINT8 *)osi_malloc(sizeof(tGATT_VALUE));
   1012         memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE));
   1013 
   1014         p = (tGATT_VALUE *)p_clcb->p_attr_buf;
   1015         if (type == GATT_WRITE_PREPARE) {
   1016             p_clcb->start_offset = p_write->offset;
   1017             p->offset = 0;
   1018         }
   1019 
   1020         if (gatt_security_check_start(p_clcb) == FALSE) {
   1021             status = GATT_NO_RESOURCES;
   1022         }
   1023 
   1024         if (status == GATT_NO_RESOURCES)
   1025             gatt_clcb_dealloc(p_clcb);
   1026     } else {
   1027         status = GATT_NO_RESOURCES;
   1028     }
   1029     return status;
   1030 }
   1031 
   1032 
   1033 /*******************************************************************************
   1034 **
   1035 ** Function         GATTC_ExecuteWrite
   1036 **
   1037 ** Description      This function is called to send an Execute write request to
   1038 **                  the server.
   1039 **
   1040 ** Parameters       conn_id: connection identifier.
   1041 **                  is_execute - to execute or cancel the prepare write requet(s)
   1042 **
   1043 ** Returns          GATT_SUCCESS if command started successfully.
   1044 **
   1045 *******************************************************************************/
   1046 tGATT_STATUS GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute)
   1047 {
   1048     tGATT_STATUS status = GATT_SUCCESS;
   1049     tGATT_CLCB      *p_clcb;
   1050     tGATT_EXEC_FLAG flag;
   1051     tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
   1052     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
   1053     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
   1054     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
   1055 
   1056     GATT_TRACE_API ("GATTC_ExecuteWrite conn_id=%d is_execute=%d", conn_id, is_execute);
   1057 
   1058     if ( (p_tcb == NULL) || (p_reg==NULL) )
   1059     {
   1060         GATT_TRACE_ERROR("GATTC_ExecuteWrite Illegal param: conn_id %d", conn_id);
   1061         return GATT_ILLEGAL_PARAMETER;
   1062     }
   1063 
   1064     if (gatt_is_clcb_allocated(conn_id))
   1065     {
   1066         GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
   1067         return GATT_BUSY;
   1068     }
   1069 
   1070     if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL)
   1071     {
   1072         p_clcb->operation  = GATTC_OPTYPE_EXE_WRITE;
   1073         flag = is_execute ? GATT_PREP_WRITE_EXEC : GATT_PREP_WRITE_CANCEL;
   1074         gatt_send_queue_write_cancel (p_clcb->p_tcb, p_clcb, flag);
   1075     }
   1076     else
   1077     {
   1078         GATT_TRACE_ERROR("Unable to allocate client CB for conn_id %d ", conn_id);
   1079         status = GATT_NO_RESOURCES;
   1080     }
   1081     return status;
   1082 }
   1083 
   1084 /*******************************************************************************
   1085 **
   1086 ** Function         GATTC_SendHandleValueConfirm
   1087 **
   1088 ** Description      This function is called to send a handle value confirmation
   1089 **                  as response to a handle value notification from server.
   1090 **
   1091 ** Parameters       conn_id: connection identifier.
   1092 **                  handle: the handle of the attribute confirmation.
   1093 **
   1094 ** Returns          GATT_SUCCESS if command started successfully.
   1095 **
   1096 *******************************************************************************/
   1097 tGATT_STATUS GATTC_SendHandleValueConfirm (UINT16 conn_id, UINT16 handle)
   1098 {
   1099     tGATT_STATUS    ret = GATT_ILLEGAL_PARAMETER;
   1100     tGATT_TCB     *p_tcb=gatt_get_tcb_by_idx(GATT_GET_TCB_IDX(conn_id));
   1101 
   1102     GATT_TRACE_API ("GATTC_SendHandleValueConfirm conn_id=%d handle=0x%x", conn_id, handle);
   1103 
   1104     if (p_tcb)
   1105     {
   1106         if (p_tcb->ind_count > 0 )
   1107         {
   1108             alarm_cancel(p_tcb->ind_ack_timer);
   1109 
   1110             GATT_TRACE_DEBUG ("notif_count=%d ", p_tcb->ind_count);
   1111             /* send confirmation now */
   1112             ret = attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, (tGATT_CL_MSG *)&handle);
   1113 
   1114             p_tcb->ind_count = 0;
   1115 
   1116         }
   1117         else
   1118         {
   1119             GATT_TRACE_DEBUG ("GATTC_SendHandleValueConfirm - conn_id: %u - ignored not waiting for indicaiton ack", conn_id);
   1120             ret = GATT_SUCCESS;
   1121         }
   1122     }
   1123     else
   1124     {
   1125         GATT_TRACE_ERROR ("GATTC_SendHandleValueConfirm - Unknown conn_id: %u", conn_id);
   1126     }
   1127     return ret;
   1128 }
   1129 
   1130 
   1131 /*******************************************************************************/
   1132 /*                                                                             */
   1133 /*                   GATT  APIs                                                */
   1134 /*                                                                             */
   1135 /*******************************************************************************/
   1136 /*******************************************************************************
   1137 **
   1138 ** Function         GATT_SetIdleTimeout
   1139 **
   1140 ** Description      This function (common to both client and server) sets the idle
   1141 **                  timeout for a tansport connection
   1142 **
   1143 ** Parameter        bd_addr:   target device bd address.
   1144 **                  idle_tout: timeout value in seconds.
   1145 **
   1146 ** Returns          void
   1147 **
   1148 *******************************************************************************/
   1149 void GATT_SetIdleTimeout (BD_ADDR bd_addr, UINT16 idle_tout, tBT_TRANSPORT transport)
   1150 {
   1151     tGATT_TCB       *p_tcb;
   1152     BOOLEAN         status = FALSE;
   1153 
   1154     if ((p_tcb = gatt_find_tcb_by_addr (bd_addr, transport)) != NULL)
   1155     {
   1156         if (p_tcb->att_lcid == L2CAP_ATT_CID)
   1157         {
   1158             status = L2CA_SetFixedChannelTout (bd_addr, L2CAP_ATT_CID, idle_tout);
   1159 
   1160             if (idle_tout == GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP)
   1161                 L2CA_SetIdleTimeoutByBdAddr(p_tcb->peer_bda,
   1162                                             GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP, BT_TRANSPORT_LE);
   1163         }
   1164         else
   1165         {
   1166             status = L2CA_SetIdleTimeout (p_tcb->att_lcid, idle_tout, FALSE);
   1167         }
   1168     }
   1169 
   1170     GATT_TRACE_API ("GATT_SetIdleTimeout idle_tout=%d status=%d(1-OK 0-not performed)",
   1171                     idle_tout, status);
   1172 }
   1173 
   1174 
   1175 /*******************************************************************************
   1176 **
   1177 ** Function         GATT_Register
   1178 **
   1179 ** Description      This function is called to register an  application
   1180 **                  with GATT
   1181 **
   1182 ** Parameter        p_app_uuid128: Application UUID
   1183 **                  p_cb_info: callback functions.
   1184 **
   1185 ** Returns          0 for error, otherwise the index of the client registered with GATT
   1186 **
   1187 *******************************************************************************/
   1188 tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info)
   1189 {
   1190     tGATT_REG    *p_reg;
   1191     UINT8        i_gatt_if=0;
   1192     tGATT_IF     gatt_if=0;
   1193 
   1194     GATT_TRACE_API ("%s", __func__);
   1195     gatt_dbg_display_uuid(*p_app_uuid128);
   1196 
   1197     for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
   1198     {
   1199         if (p_reg->in_use  && !memcmp(p_app_uuid128->uu.uuid128, p_reg->app_uuid128.uu.uuid128, LEN_UUID_128))
   1200         {
   1201             GATT_TRACE_ERROR("application already registered.");
   1202             return 0;
   1203         }
   1204     }
   1205 
   1206     for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
   1207     {
   1208         if (!p_reg->in_use)
   1209         {
   1210             memset(p_reg, 0 , sizeof(tGATT_REG));
   1211             i_gatt_if++;              /* one based number */
   1212             p_reg->app_uuid128 =  *p_app_uuid128;
   1213             gatt_if            =
   1214             p_reg->gatt_if     = (tGATT_IF)i_gatt_if;
   1215             p_reg->app_cb      = *p_cb_info;
   1216             p_reg->in_use      = TRUE;
   1217 
   1218             GATT_TRACE_API ("%s: allocated gatt_if=%d", __func__, gatt_if);
   1219             return gatt_if;
   1220         }
   1221     }
   1222 
   1223     GATT_TRACE_ERROR ("%s: can't Register GATT client, MAX client reached!", __func__);
   1224     return 0;
   1225 }
   1226 
   1227 
   1228 /*******************************************************************************
   1229 **
   1230 ** Function         GATT_Deregister
   1231 **
   1232 ** Description      This function deregistered the application from GATT.
   1233 **
   1234 ** Parameters       gatt_if: applicaiton interface.
   1235 **
   1236 ** Returns          None.
   1237 **
   1238 *******************************************************************************/
   1239 void GATT_Deregister (tGATT_IF gatt_if)
   1240 {
   1241     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
   1242     tGATT_TCB       *p_tcb;
   1243     tGATT_CLCB       *p_clcb;
   1244     UINT8           i, ii, j;
   1245     tGATT_SR_REG    *p_sreg;
   1246 
   1247     GATT_TRACE_API ("GATT_Deregister gatt_if=%d", gatt_if);
   1248     /* Index 0 is GAP and is never deregistered */
   1249     if ( (gatt_if == 0) || (p_reg == NULL) )
   1250     {
   1251         GATT_TRACE_ERROR ("GATT_Deregister with invalid gatt_if: %u", gatt_if);
   1252         return;
   1253     }
   1254 
   1255     /* stop all services  */
   1256     /* todo an applcaiton can not be deregistered if its services is also used by other application
   1257       deregisteration need to bed performed in an orderly fashion
   1258       no check for now */
   1259 
   1260     for (ii = 0, p_sreg = gatt_cb.sr_reg; ii < GATT_MAX_SR_PROFILES; ii++, p_sreg++)
   1261     {
   1262         if (p_sreg->in_use && (p_sreg->gatt_if == gatt_if))
   1263         {
   1264             GATTS_StopService(p_sreg->s_hdl);
   1265         }
   1266     }
   1267 
   1268     /* free all services db buffers if owned by this application */
   1269     gatt_free_srvc_db_buffer_app_id(&p_reg->app_uuid128);
   1270 
   1271     /* When an application deregisters, check remove the link associated with the app */
   1272 
   1273     for (i=0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++)
   1274     {
   1275         if (p_tcb->in_use)
   1276         {
   1277             if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE)
   1278             {
   1279                 gatt_update_app_use_link_flag(gatt_if, p_tcb,  FALSE, TRUE);
   1280             }
   1281 
   1282             for (j = 0, p_clcb= &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB; j++, p_clcb++)
   1283             {
   1284                 if (p_clcb->in_use &&
   1285                     (p_clcb->p_reg->gatt_if == gatt_if) &&
   1286                     (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx))
   1287                 {
   1288                     alarm_cancel(p_clcb->gatt_rsp_timer_ent);
   1289                     gatt_clcb_dealloc (p_clcb);
   1290                     break;
   1291                 }
   1292             }
   1293         }
   1294     }
   1295 
   1296     gatt_deregister_bgdev_list(gatt_if);
   1297     /* update the listen mode */
   1298 #if (defined(BLE_PERIPHERAL_MODE_SUPPORT) && (BLE_PERIPHERAL_MODE_SUPPORT == TRUE))
   1299     GATT_Listen(gatt_if, FALSE, NULL);
   1300 #endif
   1301 
   1302     memset (p_reg, 0, sizeof(tGATT_REG));
   1303 }
   1304 
   1305 
   1306 /*******************************************************************************
   1307 **
   1308 ** Function         GATT_StartIf
   1309 **
   1310 ** Description      This function is called after registration to start receiving
   1311 **                  callbacks for registered interface.  Function may call back
   1312 **                  with connection status and queued notifications
   1313 **
   1314 ** Parameter        gatt_if: applicaiton interface.
   1315 **
   1316 ** Returns          None.
   1317 **
   1318 *******************************************************************************/
   1319 void GATT_StartIf (tGATT_IF gatt_if)
   1320 {
   1321     tGATT_REG   *p_reg;
   1322     tGATT_TCB   *p_tcb;
   1323     BD_ADDR     bda;
   1324     UINT8       start_idx, found_idx;
   1325     UINT16      conn_id;
   1326     tGATT_TRANSPORT transport ;
   1327 
   1328     GATT_TRACE_API ("GATT_StartIf gatt_if=%d", gatt_if);
   1329     if ((p_reg = gatt_get_regcb(gatt_if)) != NULL)
   1330     {
   1331         start_idx = 0;
   1332         while (gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport))
   1333         {
   1334             p_tcb = gatt_find_tcb_by_addr(bda, transport);
   1335             if (p_reg->app_cb.p_conn_cb && p_tcb)
   1336             {
   1337                 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
   1338                 (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, TRUE, 0, transport);
   1339             }
   1340             start_idx = ++found_idx;
   1341         }
   1342     }
   1343 }
   1344 
   1345 
   1346 /*******************************************************************************
   1347 **
   1348 ** Function         GATT_Connect
   1349 **
   1350 ** Description      This function initiate a connecttion to a remote device on GATT
   1351 **                  channel.
   1352 **
   1353 ** Parameters       gatt_if: applicaiton interface
   1354 **                  bd_addr: peer device address.
   1355 **                  is_direct: is a direct conenection or a background auto connection
   1356 **
   1357 ** Returns          TRUE if connection started; FALSE if connection start failure.
   1358 **
   1359 *******************************************************************************/
   1360 BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct,
   1361                       tBT_TRANSPORT transport, BOOLEAN opportunistic)
   1362 {
   1363     tGATT_REG    *p_reg;
   1364     BOOLEAN status = FALSE;
   1365 
   1366     GATT_TRACE_API ("GATT_Connect gatt_if=%d", gatt_if);
   1367 
   1368     /* Make sure app is registered */
   1369     if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
   1370     {
   1371         GATT_TRACE_ERROR("GATT_Connect - gatt_if =%d is not registered", gatt_if);
   1372         return(FALSE);
   1373     }
   1374 
   1375     if (is_direct)
   1376         status = gatt_act_connect (p_reg, bd_addr, transport, opportunistic);
   1377     else
   1378     {
   1379         if (transport == BT_TRANSPORT_LE)
   1380         status = gatt_update_auto_connect_dev(gatt_if,TRUE, bd_addr, TRUE);
   1381         else
   1382         {
   1383             GATT_TRACE_ERROR("Unsupported transport for background connection");
   1384         }
   1385     }
   1386 
   1387     return status;
   1388 
   1389 }
   1390 
   1391 /*******************************************************************************
   1392 **
   1393 ** Function         GATT_CancelConnect
   1394 **
   1395 ** Description      This function terminate the connection initaition to a remote
   1396 **                  device on GATT channel.
   1397 **
   1398 ** Parameters       gatt_if: client interface. If 0 used as unconditionally disconnect,
   1399 **                          typically used for direct connection cancellation.
   1400 **                  bd_addr: peer device address.
   1401 **
   1402 ** Returns          TRUE if connection started; FALSE if connection start failure.
   1403 **
   1404 *******************************************************************************/
   1405 BOOLEAN GATT_CancelConnect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){
   1406     tGATT_REG     *p_reg;
   1407     tGATT_TCB     *p_tcb;
   1408     BOOLEAN       status = TRUE;
   1409     tGATT_IF      temp_gatt_if;
   1410     UINT8         start_idx, found_idx;
   1411 
   1412     GATT_TRACE_API ("GATT_CancelConnect gatt_if=%d", gatt_if);
   1413 
   1414     if ((gatt_if != 0) && ((p_reg = gatt_get_regcb(gatt_if)) == NULL))
   1415     {
   1416         GATT_TRACE_ERROR("GATT_CancelConnect - gatt_if =%d is not registered", gatt_if);
   1417         return(FALSE);
   1418     }
   1419 
   1420     if (is_direct)
   1421     {
   1422         if (!gatt_if)
   1423         {
   1424             GATT_TRACE_DEBUG("GATT_CancelConnect - unconditional");
   1425             start_idx = 0;
   1426             /* only LE connection can be cancelled */
   1427             p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
   1428             if (p_tcb && gatt_num_apps_hold_link(p_tcb))
   1429             {
   1430                 while (status && gatt_find_app_hold_link(p_tcb, start_idx, &found_idx, &temp_gatt_if))
   1431                 {
   1432                     status = gatt_cancel_open(temp_gatt_if, bd_addr);
   1433                     start_idx = ++found_idx;
   1434                 }
   1435             }
   1436             else
   1437             {
   1438                 GATT_TRACE_ERROR("GATT_CancelConnect - no app found");
   1439                 status = FALSE;
   1440             }
   1441         }
   1442         else
   1443         {
   1444             status = gatt_cancel_open(gatt_if, bd_addr);
   1445         }
   1446     }
   1447     else
   1448     {
   1449         if (!gatt_if)
   1450         {
   1451             if (gatt_get_num_apps_for_bg_dev(bd_addr))
   1452             {
   1453                 while (gatt_find_app_for_bg_dev(bd_addr, &temp_gatt_if))
   1454                     gatt_remove_bg_dev_for_app(temp_gatt_if, bd_addr);
   1455             }
   1456             else
   1457             {
   1458                 GATT_TRACE_ERROR("GATT_CancelConnect -no app associated with the bg device for unconditional removal");
   1459                 status = FALSE;
   1460             }
   1461         }
   1462         else
   1463         {
   1464             status = gatt_remove_bg_dev_for_app(gatt_if, bd_addr);
   1465         }
   1466     }
   1467 
   1468     return status;
   1469 }
   1470 
   1471 /*******************************************************************************
   1472 **
   1473 ** Function         GATT_Disconnect
   1474 **
   1475 ** Description      This function disconnect the GATT channel for this registered
   1476 **                  application.
   1477 **
   1478 ** Parameters       conn_id: connection identifier.
   1479 **
   1480 ** Returns          GATT_SUCCESS if disconnected.
   1481 **
   1482 *******************************************************************************/
   1483 tGATT_STATUS GATT_Disconnect (UINT16 conn_id)
   1484 {
   1485     tGATT_STATUS    ret = GATT_ILLEGAL_PARAMETER;
   1486     tGATT_TCB       *p_tcb=NULL;
   1487     tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
   1488     UINT8          tcb_idx = GATT_GET_TCB_IDX(conn_id);
   1489 
   1490     GATT_TRACE_API ("GATT_Disconnect conn_id=%d ", conn_id);
   1491 
   1492     p_tcb = gatt_get_tcb_by_idx(tcb_idx);
   1493 
   1494     if (p_tcb)
   1495     {
   1496         gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, TRUE);
   1497         ret = GATT_SUCCESS;
   1498     }
   1499     return ret;
   1500 }
   1501 
   1502 
   1503 /*******************************************************************************
   1504 **
   1505 ** Function         GATT_GetConnectionInfor
   1506 **
   1507 ** Description      This function use conn_id to find its associated BD address and applciation
   1508 **                  interface
   1509 **
   1510 ** Parameters        conn_id: connection id  (input)
   1511 **                   p_gatt_if: applicaiton interface (output)
   1512 **                   bd_addr: peer device address. (output)
   1513 **
   1514 ** Returns          TRUE the ligical link information is found for conn_id
   1515 **
   1516 *******************************************************************************/
   1517 BOOLEAN GATT_GetConnectionInfor(UINT16 conn_id, tGATT_IF *p_gatt_if, BD_ADDR bd_addr,
   1518                                 tBT_TRANSPORT *p_transport)
   1519 {
   1520 
   1521     tGATT_IF        gatt_if = GATT_GET_GATT_IF(conn_id);
   1522     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
   1523     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
   1524     tGATT_TCB       *p_tcb= gatt_get_tcb_by_idx(tcb_idx);
   1525     BOOLEAN         status=FALSE;
   1526 
   1527     GATT_TRACE_API ("GATT_GetConnectionInfor conn_id=%d", conn_id);
   1528 
   1529     if (p_tcb && p_reg )
   1530     {
   1531         memcpy(bd_addr, p_tcb->peer_bda, BD_ADDR_LEN);
   1532         *p_gatt_if = gatt_if;
   1533         *p_transport = p_tcb->transport;
   1534         status = TRUE;
   1535     }
   1536     return status;
   1537 }
   1538 
   1539 
   1540 /*******************************************************************************
   1541 **
   1542 ** Function         GATT_GetConnIdIfConnected
   1543 **
   1544 ** Description      This function find the conn_id if the logical link for BD address
   1545 **                  and applciation interface is connected
   1546 **
   1547 ** Parameters        gatt_if: applicaiton interface (input)
   1548 **                   bd_addr: peer device address. (input)
   1549 **                   p_conn_id: connection id  (output)
   1550 **                   transport: transport option
   1551 **
   1552 ** Returns          TRUE the logical link is connected
   1553 **
   1554 *******************************************************************************/
   1555 BOOLEAN GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr, UINT16 *p_conn_id,
   1556                                   tBT_TRANSPORT transport)
   1557 {
   1558     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
   1559     tGATT_TCB       *p_tcb= gatt_find_tcb_by_addr(bd_addr, transport);
   1560     BOOLEAN         status=FALSE;
   1561 
   1562     if (p_reg && p_tcb && (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) )
   1563     {
   1564         *p_conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
   1565         status = TRUE;
   1566     }
   1567 
   1568     GATT_TRACE_API ("GATT_GetConnIdIfConnected status=%d", status);
   1569     return status;
   1570 }
   1571 
   1572 
   1573 /*******************************************************************************
   1574 **
   1575 ** Function         GATT_Listen
   1576 **
   1577 ** Description      This function start or stop LE advertisement and listen for
   1578 **                  connection.
   1579 **
   1580 ** Parameters       gatt_if: applicaiton interface
   1581 **                  p_bd_addr: listen for specific address connection, or NULL for
   1582 **                             listen to all device connection.
   1583 **                  start: start or stop listening.
   1584 **
   1585 ** Returns          TRUE if advertisement is started; FALSE if adv start failure.
   1586 **
   1587 *******************************************************************************/
   1588 BOOLEAN GATT_Listen (tGATT_IF gatt_if, BOOLEAN start, BD_ADDR_PTR bd_addr)
   1589 {
   1590     tGATT_REG    *p_reg;
   1591 
   1592     GATT_TRACE_API ("GATT_Listen gatt_if=%d", gatt_if);
   1593 
   1594     /* Make sure app is registered */
   1595     if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
   1596     {
   1597         GATT_TRACE_ERROR("GATT_Listen - gatt_if =%d is not registered", gatt_if);
   1598         return(FALSE);
   1599     }
   1600 
   1601     if (bd_addr != NULL)
   1602     {
   1603         gatt_update_auto_connect_dev(gatt_if,start, bd_addr, FALSE);
   1604     }
   1605     else
   1606     {
   1607         p_reg->listening = start ? GATT_LISTEN_TO_ALL : GATT_LISTEN_TO_NONE;
   1608     }
   1609 
   1610     return gatt_update_listen_mode();
   1611 }
   1612 
   1613 #endif
   1614 
   1615