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         else
   1172         {
   1173             status = L2CA_SetIdleTimeout (p_tcb->att_lcid, idle_tout, FALSE);
   1174         }
   1175     }
   1176 
   1177     GATT_TRACE_API ("GATT_SetIdleTimeout idle_tout=%d status=%d(1-OK 0-not performed)",
   1178                     idle_tout, status);
   1179 }
   1180 
   1181 
   1182 /*******************************************************************************
   1183 **
   1184 ** Function         GATT_Register
   1185 **
   1186 ** Description      This function is called to register an  application
   1187 **                  with GATT
   1188 **
   1189 ** Parameter        p_app_uuid128: Application UUID
   1190 **                  p_cb_info: callback functions.
   1191 **
   1192 ** Returns          0 for error, otherwise the index of the client registered with GATT
   1193 **
   1194 *******************************************************************************/
   1195 tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info)
   1196 {
   1197     tGATT_REG    *p_reg;
   1198     UINT8        i_gatt_if=0;
   1199     tGATT_IF     gatt_if=0;
   1200 
   1201     GATT_TRACE_API ("GATT_Register");
   1202     gatt_dbg_display_uuid(*p_app_uuid128);
   1203 
   1204     for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
   1205     {
   1206         if (p_reg->in_use  && !memcmp(p_app_uuid128->uu.uuid128, p_reg->app_uuid128.uu.uuid128, LEN_UUID_128))
   1207         {
   1208             GATT_TRACE_ERROR("application already registered.");
   1209             return 0;
   1210         }
   1211     }
   1212 
   1213     for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
   1214     {
   1215         if (!p_reg->in_use)
   1216         {
   1217             memset(p_reg, 0 , sizeof(tGATT_REG));
   1218             i_gatt_if++;              /* one based number */
   1219             p_reg->app_uuid128 =  *p_app_uuid128;
   1220             gatt_if            =
   1221             p_reg->gatt_if     = (tGATT_IF)i_gatt_if;
   1222             p_reg->app_cb      = *p_cb_info;
   1223             p_reg->in_use      = TRUE;
   1224 
   1225             break;
   1226         }
   1227     }
   1228     GATT_TRACE_API ("allocated gatt_if=%d", gatt_if);
   1229     return gatt_if;
   1230 }
   1231 
   1232 
   1233 /*******************************************************************************
   1234 **
   1235 ** Function         GATT_Deregister
   1236 **
   1237 ** Description      This function deregistered the application from GATT.
   1238 **
   1239 ** Parameters       gatt_if: applicaiton interface.
   1240 **
   1241 ** Returns          None.
   1242 **
   1243 *******************************************************************************/
   1244 void GATT_Deregister (tGATT_IF gatt_if)
   1245 {
   1246     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
   1247     tGATT_TCB       *p_tcb;
   1248     tGATT_CLCB       *p_clcb;
   1249     UINT8           i, ii, j;
   1250     tGATT_SR_REG    *p_sreg;
   1251 
   1252     GATT_TRACE_API ("GATT_Deregister gatt_if=%d", gatt_if);
   1253     /* Index 0 is GAP and is never deregistered */
   1254     if ( (gatt_if == 0) || (p_reg == NULL) )
   1255     {
   1256         GATT_TRACE_ERROR ("GATT_Deregister with invalid gatt_if: %u", gatt_if);
   1257         return;
   1258     }
   1259 
   1260     /* stop all services  */
   1261     /* todo an applcaiton can not be deregistered if its services is also used by other application
   1262       deregisteration need to bed performed in an orderly fashion
   1263       no check for now */
   1264 
   1265     for (ii = 0, p_sreg = gatt_cb.sr_reg; ii < GATT_MAX_SR_PROFILES; ii++, p_sreg++)
   1266     {
   1267         if (p_sreg->in_use && (p_sreg->gatt_if == gatt_if))
   1268         {
   1269             GATTS_StopService(p_sreg->s_hdl);
   1270         }
   1271     }
   1272 
   1273     /* free all services db buffers if owned by this application */
   1274     gatt_free_srvc_db_buffer_app_id(&p_reg->app_uuid128);
   1275 
   1276     /* When an application deregisters, check remove the link associated with the app */
   1277 
   1278     for (i=0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++)
   1279     {
   1280         if (p_tcb->in_use)
   1281         {
   1282             if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE)
   1283             {
   1284                 gatt_update_app_use_link_flag(gatt_if, p_tcb,  FALSE, FALSE);
   1285                 if (!gatt_num_apps_hold_link(p_tcb))
   1286                 {
   1287                     /* this will disconnect the link or cancel the pending connect request at lower layer*/
   1288                     gatt_disconnect(p_tcb);
   1289                 }
   1290             }
   1291 
   1292             for (j = 0, p_clcb= &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB; j++, p_clcb++)
   1293             {
   1294                 if (p_clcb->in_use &&
   1295                     (p_clcb->p_reg->gatt_if == gatt_if) &&
   1296                     (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx))
   1297                 {
   1298                     btu_stop_timer(&p_clcb->rsp_timer_ent);
   1299                     gatt_clcb_dealloc (p_clcb);
   1300                     break;
   1301                 }
   1302             }
   1303         }
   1304     }
   1305 
   1306     gatt_deregister_bgdev_list(gatt_if);
   1307     /* update the listen mode */
   1308 #if (defined(BLE_PERIPHERAL_MODE_SUPPORT) && (BLE_PERIPHERAL_MODE_SUPPORT == TRUE))
   1309     GATT_Listen(gatt_if, FALSE, NULL);
   1310 #endif
   1311 
   1312     memset (p_reg, 0, sizeof(tGATT_REG));
   1313 }
   1314 
   1315 
   1316 /*******************************************************************************
   1317 **
   1318 ** Function         GATT_StartIf
   1319 **
   1320 ** Description      This function is called after registration to start receiving
   1321 **                  callbacks for registered interface.  Function may call back
   1322 **                  with connection status and queued notifications
   1323 **
   1324 ** Parameter        gatt_if: applicaiton interface.
   1325 **
   1326 ** Returns          0 for error, otherwise the index of the client registered with GATT
   1327 **
   1328 *******************************************************************************/
   1329 void GATT_StartIf (tGATT_IF gatt_if)
   1330 {
   1331     tGATT_REG   *p_reg;
   1332     tGATT_TCB   *p_tcb;
   1333     BD_ADDR     bda;
   1334     UINT8       start_idx, found_idx;
   1335     UINT16      conn_id;
   1336     tGATT_TRANSPORT transport ;
   1337 
   1338     GATT_TRACE_API ("GATT_StartIf gatt_if=%d", gatt_if);
   1339     if ((p_reg = gatt_get_regcb(gatt_if)) != NULL)
   1340     {
   1341         p_reg = &gatt_cb.cl_rcb[gatt_if - 1];
   1342         start_idx = 0;
   1343         while (gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport))
   1344         {
   1345             p_tcb = gatt_find_tcb_by_addr(bda, transport);
   1346             if (p_reg->app_cb.p_conn_cb && p_tcb)
   1347             {
   1348                 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
   1349                 (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, TRUE, 0, transport);
   1350             }
   1351             start_idx = ++found_idx;
   1352         }
   1353     }
   1354 }
   1355 
   1356 
   1357 /*******************************************************************************
   1358 **
   1359 ** Function         GATT_Connect
   1360 **
   1361 ** Description      This function initiate a connecttion to a remote device on GATT
   1362 **                  channel.
   1363 **
   1364 ** Parameters       gatt_if: applicaiton interface
   1365 **                  bd_addr: peer device address.
   1366 **                  is_direct: is a direct conenection or a background auto connection
   1367 **
   1368 ** Returns          TRUE if connection started; FALSE if connection start failure.
   1369 **
   1370 *******************************************************************************/
   1371 BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct, tBT_TRANSPORT transport)
   1372 {
   1373     tGATT_REG    *p_reg;
   1374     BOOLEAN status = FALSE;
   1375 
   1376     GATT_TRACE_API ("GATT_Connect gatt_if=%d", gatt_if);
   1377 
   1378     /* Make sure app is registered */
   1379     if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
   1380     {
   1381         GATT_TRACE_ERROR("GATT_Connect - gatt_if =%d is not registered", gatt_if);
   1382         return(FALSE);
   1383     }
   1384 
   1385     if (is_direct)
   1386         status = gatt_act_connect (p_reg, bd_addr, transport);
   1387     else
   1388     {
   1389         if (transport == BT_TRANSPORT_LE)
   1390         status = gatt_update_auto_connect_dev(gatt_if,TRUE, bd_addr, TRUE);
   1391         else
   1392         {
   1393             GATT_TRACE_ERROR("Unsupported transport for background connection");
   1394         }
   1395     }
   1396 
   1397     return status;
   1398 
   1399 }
   1400 
   1401 /*******************************************************************************
   1402 **
   1403 ** Function         GATT_CancelConnect
   1404 **
   1405 ** Description      This function terminate the connection initaition to a remote
   1406 **                  device on GATT channel.
   1407 **
   1408 ** Parameters       gatt_if: client interface. If 0 used as unconditionally disconnect,
   1409 **                          typically used for direct connection cancellation.
   1410 **                  bd_addr: peer device address.
   1411 **
   1412 ** Returns          TRUE if connection started; FALSE if connection start failure.
   1413 **
   1414 *******************************************************************************/
   1415 BOOLEAN GATT_CancelConnect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){
   1416     tGATT_REG     *p_reg;
   1417     tGATT_TCB     *p_tcb;
   1418     BOOLEAN       status = TRUE;
   1419     tGATT_IF      temp_gatt_if;
   1420     UINT8         start_idx, found_idx;
   1421 
   1422     GATT_TRACE_API ("GATT_CancelConnect gatt_if=%d", gatt_if);
   1423 
   1424     if ((gatt_if != 0) && ((p_reg = gatt_get_regcb(gatt_if)) == NULL))
   1425     {
   1426         GATT_TRACE_ERROR("GATT_CancelConnect - gatt_if =%d is not registered", gatt_if);
   1427         return(FALSE);
   1428     }
   1429 
   1430     if (is_direct)
   1431     {
   1432         if (!gatt_if)
   1433         {
   1434             GATT_TRACE_DEBUG("GATT_CancelConnect - unconditional");
   1435             start_idx = 0;
   1436             /* only LE connection can be cancelled */
   1437             p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
   1438             if (p_tcb && gatt_num_apps_hold_link(p_tcb))
   1439             {
   1440                 while (status && gatt_find_app_hold_link(p_tcb, start_idx, &found_idx, &temp_gatt_if))
   1441                 {
   1442                     status = gatt_cancel_open(temp_gatt_if, bd_addr);
   1443                     start_idx = ++found_idx;
   1444                 }
   1445             }
   1446             else
   1447             {
   1448                 GATT_TRACE_ERROR("GATT_CancelConnect - no app found");
   1449                 status = FALSE;
   1450             }
   1451         }
   1452         else
   1453         {
   1454             status = gatt_cancel_open(gatt_if, bd_addr);
   1455         }
   1456     }
   1457     else
   1458     {
   1459         if (!gatt_if)
   1460         {
   1461             if (gatt_get_num_apps_for_bg_dev(bd_addr))
   1462             {
   1463                 while (gatt_find_app_for_bg_dev(bd_addr, &temp_gatt_if))
   1464                     gatt_remove_bg_dev_for_app(temp_gatt_if, bd_addr);
   1465             }
   1466             else
   1467             {
   1468                 GATT_TRACE_ERROR("GATT_CancelConnect -no app associated with the bg device for unconditional removal");
   1469                 status = FALSE;
   1470             }
   1471         }
   1472         else
   1473         {
   1474             status = gatt_remove_bg_dev_for_app(gatt_if, bd_addr);
   1475         }
   1476     }
   1477 
   1478     return status;
   1479 }
   1480 
   1481 /*******************************************************************************
   1482 **
   1483 ** Function         GATT_Disconnect
   1484 **
   1485 ** Description      This function disconnect the GATT channel for this registered
   1486 **                  application.
   1487 **
   1488 ** Parameters       conn_id: connection identifier.
   1489 **
   1490 ** Returns          GATT_SUCCESS if disconnected.
   1491 **
   1492 *******************************************************************************/
   1493 tGATT_STATUS GATT_Disconnect (UINT16 conn_id)
   1494 {
   1495     tGATT_STATUS    ret = GATT_ILLEGAL_PARAMETER;
   1496     tGATT_TCB       *p_tcb=NULL;
   1497     tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
   1498     UINT8          tcb_idx = GATT_GET_TCB_IDX(conn_id);
   1499 
   1500     GATT_TRACE_API ("GATT_Disconnect conn_id=%d ", conn_id);
   1501 
   1502     p_tcb = gatt_get_tcb_by_idx(tcb_idx);
   1503 
   1504     if (p_tcb)
   1505     {
   1506         gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE);
   1507         if (!gatt_num_apps_hold_link(p_tcb))
   1508         {
   1509             gatt_disconnect(p_tcb);
   1510         }
   1511         ret = GATT_SUCCESS;
   1512     }
   1513     return ret;
   1514 }
   1515 
   1516 
   1517 /*******************************************************************************
   1518 **
   1519 ** Function         GATT_GetConnectionInfor
   1520 **
   1521 ** Description      This function use conn_id to find its associated BD address and applciation
   1522 **                  interface
   1523 **
   1524 ** Parameters        conn_id: connection id  (input)
   1525 **                   p_gatt_if: applicaiton interface (output)
   1526 **                   bd_addr: peer device address. (output)
   1527 **
   1528 ** Returns          TRUE the ligical link information is found for conn_id
   1529 **
   1530 *******************************************************************************/
   1531 BOOLEAN GATT_GetConnectionInfor(UINT16 conn_id, tGATT_IF *p_gatt_if, BD_ADDR bd_addr,
   1532                                 tBT_TRANSPORT *p_transport)
   1533 {
   1534 
   1535     tGATT_IF        gatt_if = GATT_GET_GATT_IF(conn_id);
   1536     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
   1537     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
   1538     tGATT_TCB       *p_tcb= gatt_get_tcb_by_idx(tcb_idx);
   1539     BOOLEAN         status=FALSE;
   1540 
   1541     GATT_TRACE_API ("GATT_GetConnectionInfor conn_id=%d", conn_id);
   1542 
   1543     if (p_tcb && p_reg )
   1544     {
   1545         memcpy(bd_addr, p_tcb->peer_bda, BD_ADDR_LEN);
   1546         *p_gatt_if = gatt_if;
   1547         *p_transport = p_tcb->transport;
   1548         status = TRUE;
   1549     }
   1550     return status;
   1551 }
   1552 
   1553 
   1554 /*******************************************************************************
   1555 **
   1556 ** Function         GATT_GetConnIdIfConnected
   1557 **
   1558 ** Description      This function find the conn_id if the logical link for BD address
   1559 **                  and applciation interface is connected
   1560 **
   1561 ** Parameters        gatt_if: applicaiton interface (input)
   1562 **                   bd_addr: peer device address. (input)
   1563 **                   p_conn_id: connection id  (output)
   1564 **                   transport: transport option
   1565 **
   1566 ** Returns          TRUE the logical link is connected
   1567 **
   1568 *******************************************************************************/
   1569 BOOLEAN GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr, UINT16 *p_conn_id,
   1570                                   tBT_TRANSPORT transport)
   1571 {
   1572     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
   1573     tGATT_TCB       *p_tcb= gatt_find_tcb_by_addr(bd_addr, transport);
   1574     BOOLEAN         status=FALSE;
   1575 
   1576     if (p_reg && p_tcb && (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) )
   1577     {
   1578         *p_conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
   1579         status = TRUE;
   1580     }
   1581 
   1582     GATT_TRACE_API ("GATT_GetConnIdIfConnected status=%d", status);
   1583     return status;
   1584 }
   1585 
   1586 
   1587 /*******************************************************************************
   1588 **
   1589 ** Function         GATT_Listen
   1590 **
   1591 ** Description      This function start or stop LE advertisement and listen for
   1592 **                  connection.
   1593 **
   1594 ** Parameters       gatt_if: applicaiton interface
   1595 **                  p_bd_addr: listen for specific address connection, or NULL for
   1596 **                             listen to all device connection.
   1597 **                  start: start or stop listening.
   1598 **
   1599 ** Returns          TRUE if advertisement is started; FALSE if adv start failure.
   1600 **
   1601 *******************************************************************************/
   1602 BOOLEAN GATT_Listen (tGATT_IF gatt_if, BOOLEAN start, BD_ADDR_PTR bd_addr)
   1603 {
   1604     tGATT_REG    *p_reg;
   1605     BOOLEAN status = TRUE;
   1606 
   1607     GATT_TRACE_API ("GATT_Listen gatt_if=%d", gatt_if);
   1608 
   1609     /* Make sure app is registered */
   1610     if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
   1611     {
   1612         GATT_TRACE_ERROR("GATT_Listen - gatt_if =%d is not registered", gatt_if);
   1613         return(FALSE);
   1614     }
   1615 
   1616     if (bd_addr != NULL)
   1617     {
   1618         status = gatt_update_auto_connect_dev(gatt_if,start, bd_addr, FALSE);
   1619     }
   1620     else
   1621     {
   1622         p_reg->listening = start ? GATT_LISTEN_TO_ALL : GATT_LISTEN_TO_NONE;
   1623     }
   1624 
   1625     return gatt_update_listen_mode();
   1626 }
   1627 
   1628 #endif
   1629 
   1630