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