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_API0 ("GATTS_CreateService" );
    155 
    156     if (p_reg == NULL)
    157     {
    158         GATT_TRACE_ERROR1 ("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_DEBUG0 ("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_ERROR2 ("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_ERROR0 ("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_ERROR0 ("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_DEBUG0 ("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_ERROR0 ("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_DEBUG6 ("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_DEBUG0("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_DEBUG0("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_DEBUG0("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_DEBUG2("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_DEBUG0("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     {
    371         GATT_TRACE_DEBUG0("Illegal parameter");
    372         return 0;
    373     }
    374 
    375     return gatts_add_char_descr(&p_decl->svc_db,
    376                                 perm,
    377                                 p_descr_uuid);
    378 
    379 }
    380 /*******************************************************************************
    381 **
    382 ** Function         GATTS_DeleteService
    383 **
    384 ** Description      This function is called to delete a service.
    385 **
    386 ** Parameter        gatt_if       : application interface
    387 **                  p_svc_uuid    : service UUID
    388 **                  svc_inst      : instance of the service inside the application
    389 **
    390 ** Returns          TRUE if operation succeed, FALSE if handle block was not found.
    391 **
    392 *******************************************************************************/
    393 BOOLEAN GATTS_DeleteService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, UINT16 svc_inst)
    394 {
    395 
    396     tGATT_HDL_LIST_INFO             *p_list_info= &gatt_cb.hdl_list_info;
    397     tGATT_HDL_LIST_ELEM             *p_list=NULL;
    398     UINT8                           i_sreg;
    399     tGATTS_PENDING_NEW_SRV_START    *p_buf;
    400     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
    401     tBT_UUID *p_app_uuid128;
    402 
    403     GATT_TRACE_DEBUG0 ("GATTS_DeleteService");
    404 
    405     if (p_reg == NULL)
    406     {
    407         GATT_TRACE_ERROR0 ("Applicaiton not foud");
    408         return(FALSE);
    409     }
    410     p_app_uuid128 = &p_reg->app_uuid128;
    411 
    412     if ((p_list = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst)) == NULL)
    413     {
    414         GATT_TRACE_ERROR0 ("No Service found");
    415         return(FALSE);
    416     }
    417 
    418     if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128,
    419                                          &p_list->asgn_range.svc_uuid,
    420                                          p_list->asgn_range.svc_inst)) != NULL)
    421     {
    422         GATT_TRACE_DEBUG0 ("Delete a new service changed item - the service has not yet started");
    423         GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf));
    424     }
    425     else
    426     {
    427         gatt_proc_srv_chg();
    428     }
    429 
    430     if ((i_sreg = gatt_sr_find_i_rcb_by_app_id (p_app_uuid128,
    431                                                 p_svc_uuid,
    432                                                 svc_inst)) != GATT_MAX_SR_PROFILES)
    433     {
    434         GATTS_StopService(gatt_cb.sr_reg[i_sreg].s_hdl);
    435     }
    436 
    437     GATT_TRACE_DEBUG2 ("released handles s_hdl=%u e_hdl=%u",
    438                        p_list->asgn_range.s_handle , p_list->asgn_range.e_handle  );
    439 
    440     if ( (p_list->asgn_range.s_handle >= gatt_cb.hdl_cfg.app_start_hdl)
    441          && gatt_cb.cb_info.p_nv_save_callback)
    442         (*gatt_cb.cb_info.p_nv_save_callback)(FALSE, &p_list->asgn_range);
    443 
    444     gatt_remove_an_item_from_list(p_list_info, p_list);
    445     gatt_free_hdl_buffer(p_list);
    446 
    447     return(TRUE);
    448 }
    449 
    450 /*******************************************************************************
    451 **
    452 ** Function         GATTS_StartService
    453 **
    454 ** Description      This function is called to start a service with GATT
    455 **
    456 ** Parameter        gatt_if : service handle.
    457 **                  p_cback       : application service callback functions.
    458 **                  sup_transport : supported transport(s) for this primary service
    459 **
    460 ** return           GATT_SUCCESS if sucessfully started; otherwise error code.
    461 **
    462 *******************************************************************************/
    463 tGATT_STATUS GATTS_StartService (tGATT_IF gatt_if, UINT16 service_handle,
    464                                  tGATT_TRANSPORT sup_transport)
    465 {
    466     tGATT_SR_REG            *p_sreg;
    467     tGATT_HDL_LIST_ELEM      *p_list=NULL;
    468     UINT8                    i_sreg;
    469     tBT_UUID                *p_uuid;
    470     tGATT_REG              *p_reg = gatt_get_regcb(gatt_if);
    471 
    472     tGATTS_PENDING_NEW_SRV_START *p_buf;
    473 
    474     GATT_TRACE_API0 ("GATTS_StartService");
    475 
    476     if (p_reg == NULL)
    477     {
    478         /* Not found  */
    479         GATT_TRACE_ERROR0 ("Applicaiton not found ");
    480         return GATT_NOT_FOUND;
    481     }
    482 
    483     if ((p_list = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL)
    484     {
    485         /* Not found  */
    486         GATT_TRACE_ERROR0 ("no service found");
    487         return GATT_NOT_FOUND;
    488     }
    489 
    490     if (gatt_sr_find_i_rcb_by_app_id (&p_list->asgn_range.app_uuid128,
    491                                       &p_list->asgn_range.svc_uuid,
    492                                       p_list->asgn_range.svc_inst) != GATT_MAX_SR_PROFILES)
    493     {
    494         GATT_TRACE_ERROR0 ("Duplicate Service start - Service already started");
    495         return GATT_SERVICE_STARTED;
    496     }
    497 
    498     /*this is a new application servoce start */
    499     if ((i_sreg = gatt_sr_alloc_rcb(p_list)) ==  GATT_MAX_SR_PROFILES)
    500     {
    501         GATT_TRACE_ERROR0 ("GATTS_StartService: no free server registration block");
    502         return GATT_NO_RESOURCES;
    503     }
    504 
    505     p_sreg = &gatt_cb.sr_reg[i_sreg];
    506     p_sreg->gatt_if = gatt_if;
    507 
    508     switch (sup_transport)
    509     {
    510         case GATT_TRANSPORT_BR_EDR:
    511         case GATT_TRANSPORT_LE_BR_EDR:
    512             if (p_sreg->type == GATT_UUID_PRI_SERVICE)
    513             {
    514                 p_uuid = gatts_get_service_uuid (p_sreg->p_db);
    515 
    516                 p_sreg->sdp_handle = gatt_add_sdp_record(p_uuid, p_sreg->s_hdl, p_sreg->e_hdl);
    517             }
    518             break;
    519         default:
    520             break;
    521     }
    522 
    523     gatts_update_srv_list_elem(i_sreg, p_sreg->s_hdl,
    524                                p_list->asgn_range.is_primary);
    525 
    526     gatt_add_a_srv_to_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[i_sreg]);
    527 
    528     GATT_TRACE_DEBUG1 ("allocated i_sreg=%d ",i_sreg);
    529 
    530     GATT_TRACE_DEBUG5 ("s_hdl=%d e_hdl=%d type=0x%x svc_inst=%d sdp_hdl=0x%x",
    531                        p_sreg->s_hdl,p_sreg->e_hdl,
    532                        p_sreg->type,  p_sreg->service_instance,
    533                        p_sreg->sdp_handle);
    534 
    535 
    536     if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128,
    537                                          &p_list->asgn_range.svc_uuid,
    538                                          p_list->asgn_range.svc_inst)) != NULL)
    539     {
    540         gatt_proc_srv_chg();
    541         /* remove the new service element after the srv changed processing is completed*/
    542 
    543         GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf));
    544     }
    545     return GATT_SUCCESS;
    546 }
    547 
    548 /*******************************************************************************
    549 **
    550 ** Function         GATTS_StopService
    551 **
    552 ** Description      This function is called to stop a service
    553 **
    554 ** Parameter         service_handle : this is the start handle of a service
    555 **
    556 ** Returns          None.
    557 **
    558 *******************************************************************************/
    559 void GATTS_StopService (UINT16 service_handle)
    560 {
    561     UINT8           ii = gatt_sr_find_i_rcb_by_handle(service_handle);
    562 
    563     GATT_TRACE_API1("GATTS_StopService %u", service_handle);
    564 
    565     /* Index 0 is reserved for GATT, and is never stopped */
    566     if ( (ii > 0) && (ii < GATT_MAX_SR_PROFILES) && (gatt_cb.sr_reg[ii].in_use) )
    567     {
    568         if (gatt_cb.sr_reg[ii].sdp_handle)
    569         {
    570             SDP_DeleteRecord(gatt_cb.sr_reg[ii].sdp_handle);
    571         }
    572         gatt_remove_a_srv_from_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[ii]);
    573         gatt_cb.srv_list[ii].in_use = FALSE;
    574         memset (&gatt_cb.sr_reg[ii], 0, sizeof(tGATT_SR_REG));
    575     }
    576     else
    577     {
    578         GATT_TRACE_ERROR1("GATTS_StopService service_handle: %u is not in use", service_handle);
    579     }
    580 }
    581 /*******************************************************************************
    582 **
    583 ** Function         GATTs_HandleValueIndication
    584 **
    585 ** Description      This function sends a handle value indication to a client.
    586 **
    587 ** Parameter        conn_id: connection identifier.
    588 **                  attr_handle: Attribute handle of this handle value indication.
    589 **                  val_len: Length of the indicated attribute value.
    590 **                  p_val: Pointer to the indicated attribute value data.
    591 **
    592 ** Returns          GATT_SUCCESS if sucessfully sent or queued; otherwise error code.
    593 **
    594 *******************************************************************************/
    595 tGATT_STATUS GATTS_HandleValueIndication (UINT16 conn_id,  UINT16 attr_handle, UINT16 val_len, UINT8 *p_val)
    596 {
    597     tGATT_STATUS    cmd_status = GATT_ILLEGAL_PARAMETER;
    598 
    599     tGATT_VALUE      indication;
    600     BT_HDR          *p_msg;
    601     tGATT_VALUE     *p_buf;
    602     tGATT_IF         gatt_if = GATT_GET_GATT_IF(conn_id);
    603     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
    604     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
    605     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
    606 
    607 
    608     GATT_TRACE_API0 ("GATTS_HandleValueIndication");
    609     if ( (p_reg == NULL) || (p_tcb == NULL))
    610     {
    611         GATT_TRACE_ERROR1 ("GATTS_HandleValueIndication Unknown  conn_id: %u ", conn_id);
    612         return(tGATT_STATUS) GATT_INVALID_CONN_ID;
    613     }
    614     indication.conn_id  = conn_id;
    615     indication.handle   = attr_handle;
    616     indication.len      = val_len;
    617     memcpy (indication.value, p_val, val_len);
    618     indication.auth_req = GATT_AUTH_REQ_NONE;
    619 
    620     if (GATT_HANDLE_IS_VALID (attr_handle)  )
    621     {
    622         if (GATT_HANDLE_IS_VALID(p_tcb->indicate_handle))
    623         {
    624             GATT_TRACE_DEBUG0 ("Add a pending indication");
    625             if ((p_buf = gatt_add_pending_ind(p_tcb, &indication)) !=NULL)
    626             {
    627                 cmd_status = GATT_SUCCESS;
    628             }
    629             else
    630             {
    631                 cmd_status = GATT_NO_RESOURCES;
    632             }
    633         }
    634         else
    635         {
    636 
    637             if ( (p_msg = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_IND, (tGATT_SR_MSG *)&indication)) != NULL)
    638             {
    639                 cmd_status = attp_send_sr_msg (p_tcb, p_msg);
    640 
    641                 if (cmd_status == GATT_SUCCESS)
    642                 {
    643                     p_tcb->indicate_handle = indication.handle;
    644                     gatt_start_conf_timer(p_tcb);
    645                 }
    646             }
    647         }
    648     }
    649     return cmd_status;
    650 }
    651 
    652 /*******************************************************************************
    653 **
    654 ** Function         GATTS_HandleValueNotification
    655 **
    656 ** Description      This function sends a handle value notification to a client.
    657 **
    658 ** Parameter        conn_id: connection identifier.
    659 **                  attr_handle: Attribute handle of this handle value indication.
    660 **                  val_len: Length of the indicated attribute value.
    661 **                  p_val: Pointer to the indicated attribute value data.
    662 **
    663 ** Returns          GATT_SUCCESS if sucessfully sent; otherwise error code.
    664 **
    665 *******************************************************************************/
    666 tGATT_STATUS GATTS_HandleValueNotification (UINT16 conn_id, UINT16 attr_handle,
    667                                             UINT16 val_len, UINT8 *p_val)
    668 {
    669     tGATT_STATUS    cmd_sent = GATT_ILLEGAL_PARAMETER;
    670     BT_HDR          *p_buf;
    671     tGATT_VALUE     notif;
    672     tGATT_IF         gatt_if = GATT_GET_GATT_IF(conn_id);
    673     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
    674     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
    675     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
    676 
    677     GATT_TRACE_API0 ("GATTS_HandleValueNotification");
    678 
    679     if ( (p_reg == NULL) || (p_tcb == NULL))
    680     {
    681         GATT_TRACE_ERROR1 ("GATTS_HandleValueNotification Unknown  conn_id: %u ", conn_id);
    682         return(tGATT_STATUS) GATT_INVALID_CONN_ID;
    683     }
    684 
    685     if (GATT_HANDLE_IS_VALID (attr_handle))
    686     {
    687         notif.handle    = attr_handle;
    688         notif.len       = val_len;
    689         memcpy (notif.value, p_val, val_len);
    690         notif.auth_req = GATT_AUTH_REQ_NONE;;
    691 
    692         p_buf = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_NOTIF, (tGATT_SR_MSG *)&notif);
    693         cmd_sent = attp_send_sr_msg (p_tcb, p_buf);
    694     }
    695     return cmd_sent;
    696 }
    697 
    698 /*******************************************************************************
    699 **
    700 ** Function         GATTS_SendRsp
    701 **
    702 ** Description      This function sends the server response to client.
    703 **
    704 ** Parameter        conn_id: connection identifier.
    705 **                  trans_id: transaction id
    706 **                  status: response status
    707 **                  p_msg: pointer to message parameters structure.
    708 **
    709 ** Returns          GATT_SUCCESS if sucessfully sent; otherwise error code.
    710 **
    711 *******************************************************************************/
    712 tGATT_STATUS GATTS_SendRsp (UINT16 conn_id,  UINT32 trans_id,
    713                             tGATT_STATUS status, tGATTS_RSP *p_msg)
    714 {
    715     tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER;
    716     tGATT_IF         gatt_if = GATT_GET_GATT_IF(conn_id);
    717     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
    718     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
    719     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
    720 
    721     GATT_TRACE_API3 ("GATTS_SendRsp: conn_id: %u  trans_id: %u  Status: 0x%04x",
    722                      conn_id, trans_id, status);
    723 
    724     if ( (p_reg == NULL) || (p_tcb == NULL))
    725     {
    726         GATT_TRACE_ERROR1 ("GATTS_SendRsp Unknown  conn_id: %u ", conn_id);
    727         return(tGATT_STATUS) GATT_INVALID_CONN_ID;
    728     }
    729 
    730     if (p_tcb->sr_cmd.trans_id != trans_id)
    731     {
    732         GATT_TRACE_ERROR2 ("GATTS_SendRsp conn_id: %u  waiting for op_code = %02x",
    733                            conn_id, p_tcb->sr_cmd.op_code);
    734 
    735         return(GATT_WRONG_STATE);
    736     }
    737     /* Process App response */
    738     cmd_sent = gatt_sr_process_app_rsp (p_tcb,  gatt_if, trans_id, p_tcb->sr_cmd.op_code, status, p_msg);
    739 
    740     return cmd_sent;
    741 }
    742 
    743 /*******************************************************************************/
    744 /* GATT Profile Srvr Functions */
    745 /*******************************************************************************/
    746 
    747 /*******************************************************************************/
    748 /*                                                                             */
    749 /*                   GATT CLIENT APIs                                          */
    750 /*                                                                             */
    751 /*******************************************************************************/
    752 
    753 
    754 /*******************************************************************************
    755 **
    756 ** Function         GATTC_ConfigureMTU
    757 **
    758 ** Description      This function is called to configure the ATT MTU size.
    759 **
    760 ** Parameters       conn_id: connection identifier.
    761 **                  mtu    - attribute MTU size..
    762 **
    763 ** Returns          GATT_SUCCESS if command started successfully.
    764 **
    765 *******************************************************************************/
    766 tGATT_STATUS GATTC_ConfigureMTU (UINT16 conn_id, UINT16 mtu)
    767 {
    768     UINT8           ret = GATT_NO_RESOURCES;
    769     tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
    770     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
    771     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
    772     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
    773 
    774     tGATT_CLCB    *p_clcb;
    775 
    776     GATT_TRACE_API2 ("GATTC_ConfigureMTU conn_id=%d mtu=%d", conn_id, mtu );
    777 
    778     // Validate that the link is BLE, not BR/EDR
    779     // ????
    780 
    781     if ( (p_tcb == NULL) || (p_reg==NULL) || (mtu < GATT_DEF_BLE_MTU_SIZE) || (mtu > GATT_MAX_MTU_SIZE))
    782     {
    783         return GATT_ILLEGAL_PARAMETER;
    784     }
    785 
    786     if (gatt_is_clcb_allocated(conn_id))
    787     {
    788         GATT_TRACE_ERROR1("GATTC_ConfigureMTU GATT_BUSY conn_id = %d", conn_id);
    789         return GATT_BUSY;
    790     }
    791 
    792     if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL)
    793     {
    794         p_clcb->p_tcb->payload_size = mtu;
    795         p_clcb->operation = GATTC_OPTYPE_CONFIG;
    796 
    797         ret = attp_send_cl_msg (p_clcb->p_tcb, p_clcb->clcb_idx, GATT_REQ_MTU, (tGATT_CL_MSG *)&mtu);
    798     }
    799 
    800     return ret;
    801 }
    802 
    803 /*******************************************************************************
    804 **
    805 ** Function         GATTC_Discover
    806 **
    807 ** Description      This function is called to do a discovery procedure on ATT server.
    808 **
    809 ** Parameters       conn_id: connection identifier.
    810 **                  disc_type:discovery type.
    811 **                  p_param: parameters of discovery requirement.
    812 **
    813 ** Returns          GATT_SUCCESS if command received/sent successfully.
    814 **
    815 *******************************************************************************/
    816 tGATT_STATUS GATTC_Discover (UINT16 conn_id, tGATT_DISC_TYPE disc_type,
    817                              tGATT_DISC_PARAM *p_param)
    818 {
    819     tGATT_STATUS    status = GATT_SUCCESS;
    820     tGATT_CLCB      *p_clcb;
    821     tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
    822     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
    823     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
    824     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
    825 
    826 
    827     GATT_TRACE_API2 ("GATTC_Discover conn_id=%d disc_type=%d",conn_id, disc_type);
    828 
    829     if ( (p_tcb == NULL) || (p_reg==NULL) ||(p_param == NULL) ||
    830          (disc_type >= GATT_DISC_MAX))
    831     {
    832         GATT_TRACE_ERROR2("GATTC_Discover Illegal param: disc_type %d conn_id = %d", disc_type, conn_id);
    833         return GATT_ILLEGAL_PARAMETER;
    834     }
    835 
    836 
    837     if (gatt_is_clcb_allocated(conn_id))
    838     {
    839         GATT_TRACE_ERROR1("GATTC_Discover GATT_BUSY conn_id = %d", conn_id);
    840         return GATT_BUSY;
    841     }
    842 
    843 
    844     if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
    845     {
    846         if (!GATT_HANDLE_IS_VALID(p_param->s_handle) ||
    847             !GATT_HANDLE_IS_VALID(p_param->e_handle) ||
    848             /* search by type does not have a valid UUID param */
    849             (disc_type == GATT_DISC_SRVC_BY_UUID &&
    850              p_param->service.len == 0))
    851         {
    852             return GATT_ILLEGAL_PARAMETER;
    853         }
    854 
    855         p_clcb->operation  = GATTC_OPTYPE_DISCOVERY;
    856         p_clcb->op_subtype = disc_type;
    857         p_clcb->s_handle   = p_param->s_handle;
    858         p_clcb->e_handle   = p_param->e_handle;
    859         p_clcb->uuid       = p_param->service;
    860 
    861         gatt_act_discovery(p_clcb);
    862     }
    863     else
    864     {
    865         status = GATT_NO_RESOURCES;
    866     }
    867     return status;
    868 }
    869 
    870 /*******************************************************************************
    871 **
    872 ** Function         GATTC_Read
    873 **
    874 ** Description      This function is called to read the value of an attribute from
    875 **                  the server.
    876 **
    877 ** Parameters       conn_id: connection identifier.
    878 **                  type    - attribute read type.
    879 **                  p_read  - read operation parameters.
    880 **
    881 ** Returns          GATT_SUCCESS if command started successfully.
    882 **
    883 *******************************************************************************/
    884 tGATT_STATUS GATTC_Read (UINT16 conn_id, tGATT_READ_TYPE type, tGATT_READ_PARAM *p_read)
    885 {
    886     tGATT_STATUS status = GATT_SUCCESS;
    887     tGATT_CLCB          *p_clcb;
    888     tGATT_READ_MULTI    *p_read_multi;
    889     tGATT_IF            gatt_if=GATT_GET_GATT_IF(conn_id);
    890     UINT8               tcb_idx = GATT_GET_TCB_IDX(conn_id);
    891     tGATT_TCB           *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
    892     tGATT_REG           *p_reg = gatt_get_regcb(gatt_if);
    893 
    894 
    895     GATT_TRACE_API2 ("GATTC_Read conn_id=%d type=%d", conn_id, type);
    896 
    897     if ( (p_tcb == NULL) || (p_reg==NULL) || (p_read == NULL) || ((type >= GATT_READ_MAX) || (type == 0)))
    898     {
    899         GATT_TRACE_ERROR2("GATT_Read Illegal param: conn_id %d, type 0%d,", conn_id, type);
    900         return GATT_ILLEGAL_PARAMETER;
    901     }
    902 
    903     if (gatt_is_clcb_allocated(conn_id))
    904     {
    905         GATT_TRACE_ERROR1("GATTC_Read GATT_BUSY conn_id = %d", conn_id);
    906         return GATT_BUSY;
    907     }
    908 
    909     if ( (p_clcb = gatt_clcb_alloc(conn_id)) != NULL  )
    910     {
    911         p_clcb->operation = GATTC_OPTYPE_READ;
    912         p_clcb->op_subtype = type;
    913         p_clcb->auth_req = p_read->by_handle.auth_req;
    914         p_clcb->counter = 0;
    915 
    916         switch (type)
    917         {
    918             case GATT_READ_BY_TYPE:
    919             case GATT_READ_CHAR_VALUE:
    920                 p_clcb->s_handle = p_read->service.s_handle;
    921                 p_clcb->e_handle = p_read->service.e_handle;
    922                 memcpy(&p_clcb->uuid, &p_read->service.uuid, sizeof(tBT_UUID));
    923                 break;
    924             case GATT_READ_MULTIPLE:
    925                 p_clcb->s_handle = 0;
    926                 /* copy multiple handles in CB */
    927                 p_read_multi = (tGATT_READ_MULTI *)GKI_getbuf(sizeof(tGATT_READ_MULTI));
    928                 p_clcb->p_attr_buf = (UINT8*)p_read_multi;
    929                 memcpy (p_read_multi, &p_read->read_multiple, sizeof(tGATT_READ_MULTI));
    930             case GATT_READ_BY_HANDLE:
    931             case GATT_READ_PARTIAL:
    932                 memset(&p_clcb->uuid, 0, sizeof(tBT_UUID));
    933                 p_clcb->s_handle = p_read->by_handle.handle;
    934 
    935                 if (type == GATT_READ_PARTIAL)
    936                 {
    937                     p_clcb->counter = p_read->partial.offset;
    938                 }
    939 
    940                 break;
    941             default:
    942                 break;
    943         }
    944         /* start security check */
    945         if (gatt_security_check_start(p_clcb) == FALSE)
    946         {
    947             status = GATT_NO_RESOURCES;
    948             gatt_clcb_dealloc(p_clcb);
    949         }
    950     }
    951     else
    952     {
    953         status = GATT_NO_RESOURCES;
    954     }
    955     return status;
    956 }
    957 
    958 /*******************************************************************************
    959 **
    960 ** Function         GATTC_Write
    961 **
    962 ** Description      This function is called to write the value of an attribute to
    963 **                  the server.
    964 **
    965 ** Parameters       conn_id: connection identifier.
    966 **                  type    - attribute write type.
    967 **                  p_write  - write operation parameters.
    968 **
    969 ** Returns          GATT_SUCCESS if command started successfully.
    970 **
    971 *******************************************************************************/
    972 tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write)
    973 {
    974     tGATT_STATUS status = GATT_SUCCESS;
    975     tGATT_CLCB      *p_clcb;
    976     tGATT_VALUE     *p;
    977     tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
    978     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
    979     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
    980     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
    981 
    982     if ( (p_tcb == NULL) || (p_reg==NULL) || (p_write == NULL) ||
    983          ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && (type != GATT_WRITE_NO_RSP)) )
    984     {
    985         GATT_TRACE_ERROR2("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id, type);
    986         return GATT_ILLEGAL_PARAMETER;
    987     }
    988 
    989     if (gatt_is_clcb_allocated(conn_id))
    990     {
    991         GATT_TRACE_ERROR1("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
    992         return GATT_BUSY;
    993     }
    994 
    995     if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
    996     {
    997         p_clcb->operation  = GATTC_OPTYPE_WRITE;
    998         p_clcb->op_subtype = type;
    999         p_clcb->auth_req = p_write->auth_req;
   1000 
   1001         if (( p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf((UINT16)sizeof(tGATT_VALUE))) != NULL)
   1002         {
   1003             memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE));
   1004 
   1005             p =  (tGATT_VALUE *)p_clcb->p_attr_buf;
   1006             if (type == GATT_WRITE_PREPARE)
   1007             {
   1008                 p_clcb->start_offset = p_write->offset;
   1009                 p->offset = 0;
   1010             }
   1011 
   1012             if (gatt_security_check_start(p_clcb) == FALSE)
   1013             {
   1014                 status = GATT_NO_RESOURCES;
   1015             }
   1016         }
   1017         else
   1018         {
   1019             status = GATT_NO_RESOURCES;
   1020         }
   1021 
   1022         if (status == GATT_NO_RESOURCES)
   1023             gatt_clcb_dealloc(p_clcb);
   1024     }
   1025     else
   1026     {
   1027         status = GATT_NO_RESOURCES;
   1028     }
   1029     return status;
   1030 }
   1031 
   1032 
   1033 /*******************************************************************************
   1034 **
   1035 ** Function         GATTC_ExecuteWrite
   1036 **
   1037 ** Description      This function is called to send an Execute write request to
   1038 **                  the server.
   1039 **
   1040 ** Parameters       conn_id: connection identifier.
   1041 **                  is_execute - to execute or cancel the prepare write requet(s)
   1042 **
   1043 ** Returns          GATT_SUCCESS if command started successfully.
   1044 **
   1045 *******************************************************************************/
   1046 tGATT_STATUS GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute)
   1047 {
   1048     tGATT_STATUS status = GATT_SUCCESS;
   1049     tGATT_CLCB      *p_clcb;
   1050     tGATT_EXEC_FLAG flag;
   1051     tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
   1052     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
   1053     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
   1054     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
   1055 
   1056     GATT_TRACE_API2 ("GATTC_ExecuteWrite conn_id=%d is_execute=%d", conn_id, is_execute);
   1057 
   1058     if ( (p_tcb == NULL) || (p_reg==NULL) )
   1059     {
   1060         GATT_TRACE_ERROR1("GATTC_ExecuteWrite Illegal param: conn_id %d", conn_id);
   1061         return GATT_ILLEGAL_PARAMETER;
   1062     }
   1063 
   1064     if (gatt_is_clcb_allocated(conn_id))
   1065     {
   1066         GATT_TRACE_ERROR1("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
   1067         return GATT_BUSY;
   1068     }
   1069 
   1070     if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL)
   1071     {
   1072         p_clcb->operation  = GATTC_OPTYPE_EXE_WRITE;
   1073         flag = is_execute ? GATT_PREP_WRITE_EXEC : GATT_PREP_WRITE_CANCEL;
   1074         gatt_send_queue_write_cancel (p_clcb->p_tcb, p_clcb, flag);
   1075     }
   1076     else
   1077     {
   1078         GATT_TRACE_ERROR1("Unable to allocate client CB for conn_id %d ", conn_id);
   1079         status = GATT_NO_RESOURCES;
   1080     }
   1081     return status;
   1082 }
   1083 
   1084 /*******************************************************************************
   1085 **
   1086 ** Function         GATTC_SendHandleValueConfirm
   1087 **
   1088 ** Description      This function is called to send a handle value confirmation
   1089 **                  as response to a handle value notification from server.
   1090 **
   1091 ** Parameters       conn_id: connection identifier.
   1092 **                  handle: the handle of the attribute confirmation.
   1093 **
   1094 ** Returns          GATT_SUCCESS if command started successfully.
   1095 **
   1096 *******************************************************************************/
   1097 tGATT_STATUS GATTC_SendHandleValueConfirm (UINT16 conn_id, UINT16 handle)
   1098 {
   1099     tGATT_STATUS    ret = GATT_ILLEGAL_PARAMETER;
   1100     tGATT_TCB     *p_tcb=gatt_get_tcb_by_idx(GATT_GET_TCB_IDX(conn_id));
   1101 
   1102     GATT_TRACE_API2 ("GATTC_SendHandleValueConfirm conn_id=%d handle=0x%x", conn_id, handle);
   1103 
   1104     if (p_tcb)
   1105     {
   1106         if (p_tcb->ind_count > 0 )
   1107         {
   1108             btu_stop_timer (&p_tcb->ind_ack_timer_ent);
   1109 
   1110             GATT_TRACE_DEBUG1 ("notif_count=%d ", p_tcb->ind_count);
   1111             /* send confirmation now */
   1112             ret = attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, (tGATT_CL_MSG *)&handle);
   1113 
   1114             p_tcb->ind_count = 0;
   1115 
   1116         }
   1117         else
   1118         {
   1119             GATT_TRACE_DEBUG1 ("GATTC_SendHandleValueConfirm - conn_id: %u - ignored not waiting for indicaiton ack", conn_id);
   1120             ret = GATT_SUCCESS;
   1121         }
   1122     }
   1123     else
   1124     {
   1125         GATT_TRACE_ERROR1 ("GATTC_SendHandleValueConfirm - Unknown conn_id: %u", conn_id);
   1126     }
   1127     return ret;
   1128 }
   1129 
   1130 
   1131 /*******************************************************************************/
   1132 /*                                                                             */
   1133 /*                   GATT  APIs                                                */
   1134 /*                                                                             */
   1135 /*******************************************************************************/
   1136 /*******************************************************************************
   1137 **
   1138 ** Function         GATT_SetIdleTimeout
   1139 **
   1140 ** Description      This function (common to both client and server) sets the idle
   1141 **                  timeout for a tansport connection
   1142 **
   1143 ** Parameter        bd_addr:   target device bd address.
   1144 **                  idle_tout: timeout value in seconds.
   1145 **
   1146 ** Returns          void
   1147 **
   1148 *******************************************************************************/
   1149 void GATT_SetIdleTimeout (BD_ADDR bd_addr, UINT16 idle_tout)
   1150 {
   1151     tGATT_TCB       *p_tcb;
   1152     BOOLEAN         status = FALSE;
   1153 
   1154     if ((p_tcb = gatt_find_tcb_by_addr (bd_addr)) != NULL)
   1155     {
   1156         if (p_tcb->att_lcid == L2CAP_ATT_CID)
   1157         {
   1158             status = L2CA_SetFixedChannelTout (bd_addr, L2CAP_ATT_CID, idle_tout);
   1159         }
   1160         else
   1161         {
   1162             status = L2CA_SetIdleTimeout (p_tcb->att_lcid, idle_tout, FALSE);
   1163         }
   1164     }
   1165 
   1166     GATT_TRACE_API2 ("GATT_SetIdleTimeout idle_tout=%d status=%d(1-OK 0-not performed)",
   1167                     idle_tout, status);
   1168 }
   1169 
   1170 
   1171 /*******************************************************************************
   1172 **
   1173 ** Function         GATT_Register
   1174 **
   1175 ** Description      This function is called to register an  application
   1176 **                  with GATT
   1177 **
   1178 ** Parameter        p_app_uuid128: Application UUID
   1179 **                  p_cb_info: callback functions.
   1180 **
   1181 ** Returns          0 for error, otherwise the index of the client registered with GATT
   1182 **
   1183 *******************************************************************************/
   1184 tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info)
   1185 {
   1186     tGATT_REG    *p_reg;
   1187     UINT8        i_gatt_if=0;
   1188     tGATT_IF     gatt_if=0;
   1189 
   1190     GATT_TRACE_API0 ("GATT_Register");
   1191     gatt_dbg_display_uuid(*p_app_uuid128);
   1192 
   1193     for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
   1194     {
   1195         if (p_reg->in_use  && !memcmp(p_app_uuid128->uu.uuid128, p_reg->app_uuid128.uu.uuid128, LEN_UUID_128))
   1196         {
   1197             GATT_TRACE_ERROR0("application already registered.");
   1198             return 0;
   1199         }
   1200     }
   1201 
   1202     for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
   1203     {
   1204         if (!p_reg->in_use)
   1205         {
   1206             memset(p_reg, 0 , sizeof(tGATT_REG));
   1207             i_gatt_if++;              /* one based number */
   1208             p_reg->app_uuid128 =  *p_app_uuid128;
   1209             gatt_if            =
   1210             p_reg->gatt_if     = (tGATT_IF)i_gatt_if;
   1211             p_reg->app_cb      = *p_cb_info;
   1212             p_reg->in_use      = TRUE;
   1213 
   1214             break;
   1215         }
   1216     }
   1217     GATT_TRACE_API1 ("allocated gatt_if=%d", gatt_if);
   1218     return gatt_if;
   1219 }
   1220 
   1221 
   1222 /*******************************************************************************
   1223 **
   1224 ** Function         GATT_Deregister
   1225 **
   1226 ** Description      This function deregistered the application from GATT.
   1227 **
   1228 ** Parameters       gatt_if: applicaiton interface.
   1229 **
   1230 ** Returns          None.
   1231 **
   1232 *******************************************************************************/
   1233 void GATT_Deregister (tGATT_IF gatt_if)
   1234 {
   1235     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
   1236     tGATT_TCB       *p_tcb;
   1237     tGATT_CLCB       *p_clcb;
   1238     UINT8           i, ii, j;
   1239     tGATT_SR_REG    *p_sreg;
   1240 
   1241     GATT_TRACE_API1 ("GATT_Deregister gatt_if=%d", gatt_if);
   1242     /* Index 0 is GAP and is never deregistered */
   1243     if ( (gatt_if == 0) || (p_reg == NULL) )
   1244     {
   1245         GATT_TRACE_ERROR1 ("GATT_Deregister with invalid gatt_if: %u", gatt_if);
   1246         return;
   1247     }
   1248 
   1249     /* stop all services  */
   1250     /* todo an applcaiton can not be deregistered if its services is also used by other application
   1251       deregisteration need to bed performed in an orderly fashion
   1252       no check for now */
   1253 
   1254     for (ii = 0, p_sreg = gatt_cb.sr_reg; ii < GATT_MAX_SR_PROFILES; ii++, p_sreg++)
   1255     {
   1256         if (p_sreg->in_use && (p_sreg->gatt_if == gatt_if))
   1257         {
   1258             GATTS_StopService(p_sreg->s_hdl);
   1259         }
   1260     }
   1261 
   1262     /* free all services db buffers if owned by this application */
   1263     gatt_free_srvc_db_buffer_app_id(&p_reg->app_uuid128);
   1264 
   1265     /* When an application deregisters, check remove the link associated with the app */
   1266 
   1267     for (i=0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++)
   1268     {
   1269         if (p_tcb->in_use)
   1270         {
   1271             if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE)
   1272             {
   1273                 gatt_update_app_use_link_flag(gatt_if, p_tcb,  FALSE, FALSE);
   1274                 if (!gatt_num_apps_hold_link(p_tcb))
   1275                 {
   1276                     /* this will disconnect the link or cancel the pending connect request at lower layer*/
   1277                     gatt_disconnect(p_tcb->peer_bda);
   1278                 }
   1279             }
   1280 
   1281             for (j = 0, p_clcb= &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB; j++, p_clcb++)
   1282             {
   1283                 if (p_clcb->in_use &&
   1284                     (p_clcb->p_reg->gatt_if == gatt_if) &&
   1285                     (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx))
   1286                 {
   1287                     gatt_clcb_dealloc (p_clcb);
   1288                     break;
   1289                 }
   1290             }
   1291         }
   1292     }
   1293 
   1294     gatt_deregister_bgdev_list(gatt_if);
   1295     memset (p_reg, 0, sizeof(tGATT_REG));
   1296 }
   1297 
   1298 
   1299 /*******************************************************************************
   1300 **
   1301 ** Function         GATT_StartIf
   1302 **
   1303 ** Description      This function is called after registration to start receiving
   1304 **                  callbacks for registered interface.  Function may call back
   1305 **                  with connection status and queued notifications
   1306 **
   1307 ** Parameter        gatt_if: applicaiton interface.
   1308 **
   1309 ** Returns          0 for error, otherwise the index of the client registered with GATT
   1310 **
   1311 *******************************************************************************/
   1312 void GATT_StartIf (tGATT_IF gatt_if)
   1313 {
   1314     tGATT_REG   *p_reg;
   1315     tGATT_TCB   *p_tcb;
   1316     //tGATT_CLCB   *p_clcb;
   1317     BD_ADDR     bda;
   1318     UINT8       start_idx, found_idx;
   1319     UINT16      conn_id;
   1320 
   1321     GATT_TRACE_API1 ("GATT_StartIf gatt_if=%d", gatt_if);
   1322     if ((p_reg = gatt_get_regcb(gatt_if)) != NULL)
   1323     {
   1324         p_reg = &gatt_cb.cl_rcb[gatt_if - 1];
   1325         start_idx = 0;
   1326         while (gatt_find_the_connected_bda(start_idx, bda, &found_idx))
   1327         {
   1328             p_tcb = gatt_find_tcb_by_addr(bda);
   1329             if (p_reg->app_cb.p_conn_cb)
   1330             {
   1331                 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
   1332                 (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, TRUE, 0);
   1333             }
   1334             start_idx = ++found_idx;
   1335         }
   1336     }
   1337 }
   1338 
   1339 
   1340 /*******************************************************************************
   1341 **
   1342 ** Function         GATT_Connect
   1343 **
   1344 ** Description      This function initiate a connecttion to a ATT server.
   1345 **
   1346 ** Parameters       gatt_if: applicaiton interface
   1347 **                  bd_addr: peer device address.
   1348 **                  is_direct: is a direct conenection or a background auto connection
   1349 **
   1350 ** Returns          TRUE if connection started; FALSE if connection start failure.
   1351 **
   1352 *******************************************************************************/
   1353 BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){
   1354     tGATT_REG    *p_reg;
   1355     BOOLEAN status;
   1356 
   1357     GATT_TRACE_API1 ("GATT_Connect gatt_if=%d", gatt_if);
   1358 
   1359     /* Make sure app is registered */
   1360     if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
   1361     {
   1362         GATT_TRACE_ERROR1("GATT_Connect - gatt_if =%d is not registered", gatt_if);
   1363         return(FALSE);
   1364     }
   1365 
   1366     if (is_direct)
   1367         status = gatt_act_connect (p_reg, bd_addr);
   1368     else
   1369         status = gatt_update_auto_connect_dev(gatt_if,TRUE, bd_addr);
   1370 
   1371     return status;
   1372 
   1373 }
   1374 
   1375 /*******************************************************************************
   1376 **
   1377 ** Function         GATT_CancelConnect
   1378 **
   1379 ** Description      This function initiate a connecttion to a ATT server.
   1380 **
   1381 ** Parameters       gatt_if: client interface. If 0 used as unconditionally disconnect,
   1382 **                          typically used for direct connection cancellation.
   1383 **                  bd_addr: peer device address.
   1384 **
   1385 ** Returns          TRUE if connection started; FALSE if connection start failure.
   1386 **
   1387 *******************************************************************************/
   1388 BOOLEAN GATT_CancelConnect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){
   1389     tGATT_REG     *p_reg;
   1390     tGATT_TCB     *p_tcb;
   1391     BOOLEAN       status = TRUE;
   1392     tGATT_IF      temp_gatt_if;
   1393     UINT8         start_idx, found_idx;
   1394 
   1395     GATT_TRACE_API1 ("GATT_CancelConnect gatt_if=%d", gatt_if);
   1396 
   1397     if ((gatt_if != 0) && ((p_reg = gatt_get_regcb(gatt_if)) == NULL))
   1398     {
   1399         GATT_TRACE_ERROR1("GATT_CancelConnect - gatt_if =%d is not registered", gatt_if);
   1400         return(FALSE);
   1401     }
   1402 
   1403     if (is_direct)
   1404     {
   1405         if (!gatt_if)
   1406         {
   1407             GATT_TRACE_DEBUG0("GATT_CancelConnect - unconditional");
   1408             start_idx = 0;
   1409             p_tcb = gatt_find_tcb_by_addr(bd_addr);
   1410             if (p_tcb && gatt_num_apps_hold_link(p_tcb))
   1411             {
   1412                 while (status && gatt_find_app_hold_link(p_tcb, start_idx, &found_idx, &temp_gatt_if))
   1413                 {
   1414                     status = gatt_cancel_open(temp_gatt_if, bd_addr);
   1415                     start_idx = ++found_idx;
   1416                 }
   1417             }
   1418             else
   1419             {
   1420                 GATT_TRACE_ERROR0("GATT_CancelConnect - no app found");
   1421                 status = FALSE;
   1422             }
   1423         }
   1424         else
   1425         {
   1426             status = gatt_cancel_open(gatt_if, bd_addr);
   1427         }
   1428     }
   1429     else
   1430     {
   1431         if (!gatt_if)
   1432         {
   1433             if (gatt_get_num_apps_for_bg_dev(bd_addr))
   1434             {
   1435                 while (gatt_find_app_for_bg_dev(bd_addr, &temp_gatt_if))
   1436                     gatt_remove_bg_dev_for_app(temp_gatt_if, bd_addr);
   1437             }
   1438             else
   1439             {
   1440                 GATT_TRACE_ERROR0("GATT_CancelConnect -no app associated with the bg device for unconditional removal");
   1441                 status = FALSE;
   1442             }
   1443         }
   1444         else
   1445         {
   1446             status = gatt_remove_bg_dev_for_app(gatt_if, bd_addr);
   1447         }
   1448     }
   1449 
   1450     return status;
   1451 }
   1452 
   1453 /*******************************************************************************
   1454 **
   1455 ** Function         GATT_Disconnect
   1456 **
   1457 ** Description      This function disconnect a logic channel.
   1458 **
   1459 ** Parameters       conn_id: connection identifier.
   1460 **
   1461 ** Returns          GATT_SUCCESS if disconnected.
   1462 **
   1463 *******************************************************************************/
   1464 tGATT_STATUS GATT_Disconnect (UINT16 conn_id)
   1465 {
   1466     tGATT_STATUS    ret = GATT_ILLEGAL_PARAMETER;
   1467     tGATT_TCB       *p_tcb=NULL;
   1468     tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
   1469     UINT8          tcb_idx = GATT_GET_TCB_IDX(conn_id);
   1470 
   1471     GATT_TRACE_API1 ("GATT_Disconnect conn_id=%d ", conn_id);
   1472 
   1473     p_tcb = gatt_get_tcb_by_idx(tcb_idx);
   1474 
   1475     if (p_tcb)
   1476     {
   1477         gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE);
   1478         if (!gatt_num_apps_hold_link(p_tcb))
   1479         {
   1480             gatt_disconnect(p_tcb->peer_bda);
   1481         }
   1482         ret = GATT_SUCCESS;
   1483     }
   1484     return ret;
   1485 }
   1486 
   1487 
   1488 /*******************************************************************************
   1489 **
   1490 ** Function         GATT_GetConnectionInfor
   1491 **
   1492 ** Description      This function use conn_id to find its associated BD address and applciation
   1493 **                  interface
   1494 **
   1495 ** Parameters        conn_id: connection id  (input)
   1496 **                   p_gatt_if: applicaiton interface (output)
   1497 **                   bd_addr: peer device address. (output)
   1498 **
   1499 ** Returns          TRUE the ligical link information is found for conn_id
   1500 **
   1501 *******************************************************************************/
   1502 BOOLEAN GATT_GetConnectionInfor(UINT16 conn_id, tGATT_IF *p_gatt_if, BD_ADDR bd_addr)
   1503 {
   1504 
   1505     tGATT_IF        gatt_if = GATT_GET_GATT_IF(conn_id);
   1506     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
   1507     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
   1508     tGATT_TCB       *p_tcb= gatt_get_tcb_by_idx(tcb_idx);
   1509     BOOLEAN         status=FALSE;
   1510 
   1511     GATT_TRACE_API1 ("GATT_GetConnectionInfor conn_id=%d", conn_id);
   1512 
   1513     if (p_tcb && p_reg )
   1514     {
   1515         memcpy(bd_addr, p_tcb->peer_bda, BD_ADDR_LEN);
   1516         *p_gatt_if = gatt_if;
   1517         status = TRUE;
   1518     }
   1519     return status;
   1520 }
   1521 
   1522 
   1523 /*******************************************************************************
   1524 **
   1525 ** Function         GATT_GetConnIdIfConnected
   1526 **
   1527 ** Description      This function find the conn_id if the logical link for BD address
   1528 **                  and applciation interface is connected
   1529 **
   1530 ** Parameters        gatt_if: applicaiton interface (input)
   1531 **                   bd_addr: peer device address. (input)
   1532 **                   p_conn_id: connection id  (output)
   1533 **
   1534 ** Returns          TRUE the ligical link is connected
   1535 **
   1536 *******************************************************************************/
   1537 BOOLEAN GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr, UINT16 *p_conn_id)
   1538 {
   1539     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
   1540     tGATT_TCB       *p_tcb= gatt_find_tcb_by_addr(bd_addr);
   1541     BOOLEAN         status=FALSE;
   1542 
   1543     if (p_reg && p_tcb && (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) )
   1544     {
   1545         *p_conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
   1546         status = TRUE;
   1547     }
   1548 
   1549     GATT_TRACE_API1 ("GATT_GetConnIdIfConnected status=%d", status);
   1550     return status;
   1551 }
   1552 
   1553 #endif
   1554 
   1555 
   1556