diff options
Diffstat (limited to 'stack/gatt/gatt_api.c')
-rw-r--r-- | stack/gatt/gatt_api.c | 1542 |
1 files changed, 1542 insertions, 0 deletions
diff --git a/stack/gatt/gatt_api.c b/stack/gatt/gatt_api.c new file mode 100644 index 0000000..c01d617 --- /dev/null +++ b/stack/gatt/gatt_api.c @@ -0,0 +1,1542 @@ +/***************************************************************************** +** +** Name: gatt_api.c +** +** Description: this file contains GATT interface functions +** +** +** Copyright (c) 1999-2011, Broadcom Corp, All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +******************************************************************************/ +#include "bt_target.h" + + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include "gki.h" +#include <stdio.h> +#include <string.h> +#include "gatt_api.h" +#include "gatt_int.h" +#include "l2c_api.h" +#include "btm_int.h" + + +/******************************************************************************* +** +** Function GATT_SetTraceLevel +** +** Description This function sets the trace level. If called with +** a value of 0xFF, it simply returns the current trace level. +** +** Input Parameters: +** level: The level to set the GATT tracing to: +** 0xff-returns the current setting. +** 0-turns off tracing. +** >= 1-Errors. +** >= 2-Warnings. +** >= 3-APIs. +** >= 4-Events. +** >= 5-Debug. +** +** Returns The new or current trace level +** +*******************************************************************************/ +UINT8 GATT_SetTraceLevel (UINT8 new_level) +{ + if (new_level != 0xFF) + gatt_cb.trace_level = new_level; + + return(gatt_cb.trace_level); +} + +/***************************************************************************** +** +** GATT SERVER API +** +******************************************************************************/ +/******************************************************************************* +** +** Function GATTS_AddHandleRange +** +** Description This function add the allocated handles range for the specifed +** application UUID, service UUID and service instance +** +** Parameter p_hndl_range: pointer to allocated handles information +** +** Returns TRUE if handle range is added sucessfully; otherwise FALSE. +** +*******************************************************************************/ + +BOOLEAN GATTS_AddHandleRange(tGATTS_HNDL_RANGE *p_hndl_range) +{ + tGATT_HDL_LIST_ELEM *p_buf; + BOOLEAN status= FALSE; + + if ((p_buf = gatt_alloc_hdl_buffer()) != NULL) + { + p_buf->asgn_range = *p_hndl_range; + status = gatt_add_an_item_to_list(&gatt_cb.hdl_list_info, p_buf); + } + return status; +} + + +/******************************************************************************* +** +** Function GATTS_NVRegister +** +** Description Application manager calls this function to register for +** NV save callback function. There can be one and only one +** NV save callback function. +** +** Parameter p_cb_info : callback informaiton +** +** Returns TRUE if registered OK, else FALSE +** +*******************************************************************************/ +BOOLEAN GATTS_NVRegister (tGATT_APPL_INFO *p_cb_info) +{ + BOOLEAN status= FALSE; + if (p_cb_info) + { + gatt_cb.cb_info = *p_cb_info; + status = TRUE; + gatt_init_srv_chg(); + } + + return status; +} + +/******************************************************************************* +** +** Function GATTS_CreateService +** +** Description This function is called to reserve a block of handles for a service. +** +** *** It should be called only once per service instance *** +** +** Parameter gatt_if : application if +** p_svc_uuid : service UUID +** svc_inst : instance of the service inside the application +** num_handles : number of handles needed by the service. +** is_pri : is a primary service or not. +** +** Returns service handle if sucessful, otherwise 0. +** +*******************************************************************************/ +UINT16 GATTS_CreateService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, + UINT16 svc_inst, UINT16 num_handles, BOOLEAN is_pri) +{ + + tGATT_HDL_LIST_INFO *p_list_info= &gatt_cb.hdl_list_info; + tGATT_HDL_LIST_ELEM *p_list=NULL; + UINT16 s_hdl=0; + BOOLEAN save_hdl=FALSE; + tGATTS_PENDING_NEW_SRV_START *p_buf=NULL; + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + tBT_UUID *p_app_uuid128; + + + GATT_TRACE_API0 ("GATTS_CreateService" ); + + if (p_reg == NULL) + { + GATT_TRACE_ERROR1 ("Inavlid gatt_if=%d", gatt_if); + return(0); + } + + p_app_uuid128 = &p_reg->app_uuid128; + + if ((p_list = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst)) != NULL) + { + s_hdl = p_list->asgn_range.s_handle; + GATT_TRACE_DEBUG0 ("Service already been created!!"); + } + else + { + if ( (p_svc_uuid->len == LEN_UUID_16) && (p_svc_uuid->uu.uuid16 == UUID_SERVCLASS_GATT_SERVER)) + { + s_hdl= gatt_cb.hdl_cfg.gatt_start_hdl; + } + else if ((p_svc_uuid->len == LEN_UUID_16) && (p_svc_uuid->uu.uuid16 == UUID_SERVCLASS_GAP_SERVER)) + { + s_hdl= gatt_cb.hdl_cfg.gap_start_hdl; + } + else + { + p_list = p_list_info->p_first; + + if (p_list) + { + s_hdl = p_list->asgn_range.e_handle + 1; + } + + if (s_hdl < gatt_cb.hdl_cfg.app_start_hdl) + { + + s_hdl= gatt_cb.hdl_cfg.app_start_hdl; + } + save_hdl = TRUE; + } + + /* check for space */ + if (num_handles > (0xFFFF - s_hdl + 1)) + { + GATT_TRACE_ERROR2 ("GATTS_ReserveHandles: no handles, s_hdl: %u needed: %u", s_hdl, num_handles); + return(0); + } + + if ( (p_list = gatt_alloc_hdl_buffer()) == NULL) + { + /* No free entry */ + GATT_TRACE_ERROR0 ("GATTS_ReserveHandles: no free handle blocks"); + return(0); + } + + p_list->asgn_range.app_uuid128 = *p_app_uuid128; + p_list->asgn_range.svc_uuid = *p_svc_uuid; + p_list->asgn_range.svc_inst = svc_inst; + p_list->asgn_range.s_handle = s_hdl; + p_list->asgn_range.e_handle = s_hdl+num_handles-1; + p_list->asgn_range.is_primary = is_pri; + + gatt_add_an_item_to_list(p_list_info, p_list); + + if (save_hdl) + { + if (gatt_cb.cb_info.p_nv_save_callback) + (*gatt_cb.cb_info.p_nv_save_callback)(TRUE, &p_list->asgn_range); + /* add a pending new service change item to the list */ + if ( (p_buf = gatt_add_pending_new_srv_start(&p_list->asgn_range)) == NULL) + { + /* No free entry */ + GATT_TRACE_ERROR0 ("gatt_add_pending_new_srv_start: no free blocks"); + + if (p_list) + { + gatt_remove_an_item_from_list(p_list_info, p_list); + gatt_free_hdl_buffer(p_list); + } + return(0); + } + + GATT_TRACE_DEBUG0 ("Add a new srv chg item"); + } + } + + if (!gatts_init_service_db(&p_list->svc_db, *p_svc_uuid, is_pri, s_hdl , num_handles)) + { + GATT_TRACE_ERROR0 ("GATTS_ReserveHandles: service DB initialization failed"); + if (p_list) + { + gatt_remove_an_item_from_list(p_list_info, p_list); + gatt_free_hdl_buffer(p_list); + } + + if (p_buf) + GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf)); + return(0); + } + + GATT_TRACE_DEBUG6 ("GATTS_CreateService(success): handles needed:%u s_hdl=%u e_hdl=%u %s[%x] is_primary=%d", + num_handles, p_list->asgn_range.s_handle , p_list->asgn_range.e_handle, + ((p_list->asgn_range.svc_uuid.len == 2) ? "uuid16": "uuid128" ), + p_list->asgn_range.svc_uuid.uu.uuid16, + p_list->asgn_range.is_primary); + + return(s_hdl); +} + +/******************************************************************************* +** +** Function GATTS_AddIncludeService +** +** Description This function is called to add an included service. +** +** Parameter service_handle : To which service this included service is added to. +** include_svc_handle : included service handle. +** +** Returns included service attribute handle. If 0, add included service +** fail. +** +*******************************************************************************/ +UINT16 GATTS_AddIncludeService (UINT16 service_handle, UINT16 include_svc_handle) + +{ + tGATT_HDL_LIST_ELEM *p_decl, *p_incl_decl; + + if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL) + { + GATT_TRACE_DEBUG0("Service not created"); + return 0; + } + if ((p_incl_decl = gatt_find_hdl_buffer_by_handle(include_svc_handle)) == NULL) + { + GATT_TRACE_DEBUG0("Included Service not created"); + return 0; + } + + return gatts_add_included_service(&p_decl->svc_db, + p_incl_decl->asgn_range.s_handle, + p_incl_decl->asgn_range.e_handle, + p_incl_decl->asgn_range.svc_uuid); +} +/******************************************************************************* +** +** Function GATTS_AddCharacteristic +** +** Description This function is called to add a characteristic into a service. +** It will add a characteristic declaration and characteristic +** value declaration into the service database identified by the +** service handle. +** +** Parameter service_handle : To which service this included service is added to. +** char_uuid : Characteristic UUID. +** perm : Characteristic value declaration attribute permission. +** property : Characteristic Properties +** +** Returns Characteristic value declaration attribute handle. 0 if failed. +** +*******************************************************************************/ +UINT16 GATTS_AddCharacteristic (UINT16 service_handle, tBT_UUID *p_char_uuid, + tGATT_PERM perm,tGATT_CHAR_PROP property) +{ + tGATT_HDL_LIST_ELEM *p_decl; + + if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL) + { + GATT_TRACE_DEBUG0("Service not created"); + return 0; + } + /* data validity checking */ + if ( ((property & GATT_CHAR_PROP_BIT_AUTH) && !(perm & GATT_WRITE_SIGNED_PERM)) || + ((perm & GATT_WRITE_SIGNED_PERM) && !(property & GATT_CHAR_PROP_BIT_AUTH)) ) + { + GATT_TRACE_DEBUG2("Invalid configuration property=0x%x perm=0x%x ", property, perm); + return 0; + } + + return gatts_add_characteristic(&p_decl->svc_db, + perm, + property, + p_char_uuid); +} +/******************************************************************************* +** +** Function GATTS_AddCharDescriptor +** +** Description This function is called to add a characteristic descriptor +** into a service database. Add descriptor should follow add char +** to which it belongs, and next add char should be done only +** after all add descriptors for the previous char. +** +** Parameter service_handle : To which service this characteristic descriptor +** is added to. +** perm : Characteristic value declaration attribute +** permission. +** p_descr_uuid : Characteristic descriptor UUID +** +** Returns Characteristic descriptor attribute handle. 0 if add +** characteristic descriptor failed. +** +*******************************************************************************/ +UINT16 GATTS_AddCharDescriptor (UINT16 service_handle, + tGATT_PERM perm, + tBT_UUID * p_descr_uuid) +{ + tGATT_HDL_LIST_ELEM *p_decl; + + if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL) + { + GATT_TRACE_DEBUG0("Service not created"); + return 0; + } + if (p_descr_uuid == NULL || + (p_descr_uuid->len != LEN_UUID_128 && p_descr_uuid->len != LEN_UUID_16)) + { + GATT_TRACE_DEBUG0("Illegal parameter"); + return 0; + } + + return gatts_add_char_descr(&p_decl->svc_db, + perm, + p_descr_uuid); + +} +/******************************************************************************* +** +** Function GATTS_DeleteService +** +** Description This function is called to delete a service. +** +** Parameter gatt_if : application interface +** p_svc_uuid : service UUID +** svc_inst : instance of the service inside the application +** +** Returns TRUE if operation succeed, FALSE if handle block was not found. +** +*******************************************************************************/ +BOOLEAN GATTS_DeleteService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, UINT16 svc_inst) +{ + + tGATT_HDL_LIST_INFO *p_list_info= &gatt_cb.hdl_list_info; + tGATT_HDL_LIST_ELEM *p_list=NULL; + UINT8 i_sreg; + tGATTS_PENDING_NEW_SRV_START *p_buf; + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + tBT_UUID *p_app_uuid128; + + GATT_TRACE_DEBUG0 ("GATTS_DeleteService"); + + if (p_reg == NULL) + { + GATT_TRACE_ERROR0 ("Applicaiton not foud"); + return(FALSE); + } + p_app_uuid128 = &p_reg->app_uuid128; + + if ((p_list = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst)) == NULL) + { + GATT_TRACE_ERROR0 ("No Service found"); + return(FALSE); + } + + if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128, + &p_list->asgn_range.svc_uuid, + p_list->asgn_range.svc_inst)) != NULL) + { + GATT_TRACE_DEBUG0 ("Delete a new service changed item - the service has not yet started"); + GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf)); + } + else + { + gatt_proc_srv_chg(); + } + + if ((i_sreg = gatt_sr_find_i_rcb_by_app_id (p_app_uuid128, + p_svc_uuid, + svc_inst)) != GATT_MAX_SR_PROFILES) + { + GATTS_StopService(gatt_cb.sr_reg[i_sreg].s_hdl); + } + + GATT_TRACE_DEBUG2 ("released handles s_hdl=%u e_hdl=%u", + p_list->asgn_range.s_handle , p_list->asgn_range.e_handle ); + + if ( (p_list->asgn_range.s_handle >= gatt_cb.hdl_cfg.app_start_hdl) + && gatt_cb.cb_info.p_nv_save_callback) + (*gatt_cb.cb_info.p_nv_save_callback)(FALSE, &p_list->asgn_range); + + gatt_remove_an_item_from_list(p_list_info, p_list); + gatt_free_hdl_buffer(p_list); + + return(TRUE); +} + +/******************************************************************************* +** +** Function GATTS_StartService +** +** Description This function is called to start a service with GATT +** +** Parameter gatt_if : service handle. +** p_cback : application service callback functions. +** sup_transport : supported transport(s) for this primary service +** +** return GATT_SUCCESS if sucessfully started; otherwise error code. +** +*******************************************************************************/ +tGATT_STATUS GATTS_StartService (tGATT_IF gatt_if, UINT16 service_handle, + tGATT_TRANSPORT sup_transport) +{ + tGATT_SR_REG *p_sreg; + tGATT_HDL_LIST_ELEM *p_list=NULL; + UINT8 i_sreg; + tBT_UUID *p_uuid; + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + + tGATTS_PENDING_NEW_SRV_START *p_buf; + + GATT_TRACE_API0 ("GATTS_StartService"); + + if (p_reg == NULL) + { + /* Not found */ + GATT_TRACE_ERROR0 ("Applicaiton not found "); + return GATT_NOT_FOUND; + } + + if ((p_list = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL) + { + /* Not found */ + GATT_TRACE_ERROR0 ("no service found"); + return GATT_NOT_FOUND; + } + + if (gatt_sr_find_i_rcb_by_app_id (&p_list->asgn_range.app_uuid128, + &p_list->asgn_range.svc_uuid, + p_list->asgn_range.svc_inst) != GATT_MAX_SR_PROFILES) + { + GATT_TRACE_ERROR0 ("Duplicate Service start - Service already started"); + return GATT_SERVICE_STARTED; + } + + /*this is a new application servoce start */ + if ((i_sreg = gatt_sr_alloc_rcb(p_list)) == GATT_MAX_SR_PROFILES) + { + GATT_TRACE_ERROR0 ("GATTS_StartService: no free server registration block"); + return GATT_NO_RESOURCES; + } + + p_sreg = &gatt_cb.sr_reg[i_sreg]; + p_sreg->gatt_if = gatt_if; + + switch (sup_transport) + { + case GATT_TRANSPORT_BR_EDR: + case GATT_TRANSPORT_LE_BR_EDR: + if (p_sreg->type == GATT_UUID_PRI_SERVICE) + { + p_uuid = gatts_get_service_uuid (p_sreg->p_db); + + p_sreg->sdp_handle = gatt_add_sdp_record(p_uuid, p_sreg->s_hdl, p_sreg->e_hdl); + } + break; + default: + break; + } + + gatts_update_srv_list_elem(i_sreg, p_sreg->s_hdl, + p_list->asgn_range.is_primary); + + gatt_add_a_srv_to_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[i_sreg]); + + GATT_TRACE_DEBUG1 ("allocated i_sreg=%d ",i_sreg); + + GATT_TRACE_DEBUG5 ("s_hdl=%d e_hdl=%d type=0x%x svc_inst=%d sdp_hdl=0x%x", + p_sreg->s_hdl,p_sreg->e_hdl, + p_sreg->type, p_sreg->service_instance, + p_sreg->sdp_handle); + + + if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128, + &p_list->asgn_range.svc_uuid, + p_list->asgn_range.svc_inst)) != NULL) + { + gatt_proc_srv_chg(); + /* remove the new service element after the srv changed processing is completed*/ + + GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf)); + } + return GATT_SUCCESS; +} + +/******************************************************************************* +** +** Function GATTS_StopService +** +** Description This function is called to stop a service +** +** Parameter service_handle : this is the start handle of a service +** +** Returns None. +** +*******************************************************************************/ +void GATTS_StopService (UINT16 service_handle) +{ + UINT8 ii = gatt_sr_find_i_rcb_by_handle(service_handle); + + GATT_TRACE_API1("GATTS_StopService %u", service_handle); + + /* Index 0 is reserved for GATT, and is never stopped */ + if ( (ii > 0) && (ii < GATT_MAX_SR_PROFILES) && (gatt_cb.sr_reg[ii].in_use) ) + { + if (gatt_cb.sr_reg[ii].sdp_handle) + { + SDP_DeleteRecord(gatt_cb.sr_reg[ii].sdp_handle); + } + gatt_remove_a_srv_from_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[ii]); + gatt_cb.srv_list[ii].in_use = FALSE; + memset (&gatt_cb.sr_reg[ii], 0, sizeof(tGATT_SR_REG)); + } + else + { + GATT_TRACE_ERROR1("GATTS_StopService service_handle: %u is not in use", service_handle); + } +} +/******************************************************************************* +** +** Function GATTs_HandleValueIndication +** +** Description This function sends a handle value indication to a client. +** +** Parameter conn_id: connection identifier. +** attr_handle: Attribute handle of this handle value indication. +** val_len: Length of the indicated attribute value. +** p_val: Pointer to the indicated attribute value data. +** +** Returns GATT_SUCCESS if sucessfully sent or queued; otherwise error code. +** +*******************************************************************************/ +tGATT_STATUS GATTS_HandleValueIndication (UINT16 conn_id, UINT16 attr_handle, UINT16 val_len, UINT8 *p_val) +{ + tGATT_STATUS cmd_status = GATT_ILLEGAL_PARAMETER; + + tGATT_VALUE indication; + BT_HDR *p_msg; + tGATT_VALUE *p_buf; + tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + + + GATT_TRACE_API0 ("GATTS_HandleValueIndication"); + if ( (p_reg == NULL) || (p_tcb == NULL)) + { + GATT_TRACE_ERROR1 ("GATTS_HandleValueIndication Unknown conn_id: %u ", conn_id); + return(tGATT_STATUS) GATT_INVALID_CONN_ID; + } + indication.conn_id = conn_id; + indication.handle = attr_handle; + indication.len = val_len; + memcpy (indication.value, p_val, val_len); + indication.auth_req = GATT_AUTH_REQ_NONE; + + if (GATT_HANDLE_IS_VALID (attr_handle) ) + { + if (GATT_HANDLE_IS_VALID(p_tcb->indicate_handle)) + { + GATT_TRACE_DEBUG0 ("Add a pending indication"); + if ((p_buf = gatt_add_pending_ind(p_tcb, &indication)) !=NULL) + { + cmd_status = GATT_SUCCESS; + } + else + { + cmd_status = GATT_NO_RESOURCES; + } + } + else + { + + if ( (p_msg = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_IND, (tGATT_SR_MSG *)&indication)) != NULL) + { + cmd_status = attp_send_sr_msg (p_tcb, p_msg); + + if (cmd_status == GATT_SUCCESS) + { + p_tcb->indicate_handle = indication.handle; + gatt_start_conf_timer(p_tcb); + } + } + } + } + return cmd_status; +} + +/******************************************************************************* +** +** Function GATTS_HandleValueNotification +** +** Description This function sends a handle value notification to a client. +** +** Parameter conn_id: connection identifier. +** attr_handle: Attribute handle of this handle value indication. +** val_len: Length of the indicated attribute value. +** p_val: Pointer to the indicated attribute value data. +** +** Returns GATT_SUCCESS if sucessfully sent; otherwise error code. +** +*******************************************************************************/ +tGATT_STATUS GATTS_HandleValueNotification (UINT16 conn_id, UINT16 attr_handle, + UINT16 val_len, UINT8 *p_val) +{ + tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER; + BT_HDR *p_buf; + tGATT_VALUE notif; + tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + + GATT_TRACE_API0 ("GATTS_HandleValueNotification"); + + if ( (p_reg == NULL) || (p_tcb == NULL)) + { + GATT_TRACE_ERROR1 ("GATTS_HandleValueNotification Unknown conn_id: %u ", conn_id); + return(tGATT_STATUS) GATT_INVALID_CONN_ID; + } + + if (GATT_HANDLE_IS_VALID (attr_handle)) + { + notif.handle = attr_handle; + notif.len = val_len; + memcpy (notif.value, p_val, val_len); + notif.auth_req = GATT_AUTH_REQ_NONE;; + + p_buf = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_NOTIF, (tGATT_SR_MSG *)¬if); + cmd_sent = attp_send_sr_msg (p_tcb, p_buf); + } + return cmd_sent; +} + +/******************************************************************************* +** +** Function GATTS_SendRsp +** +** Description This function sends the server response to client. +** +** Parameter conn_id: connection identifier. +** trans_id: transaction id +** status: response status +** p_msg: pointer to message parameters structure. +** +** Returns GATT_SUCCESS if sucessfully sent; otherwise error code. +** +*******************************************************************************/ +tGATT_STATUS GATTS_SendRsp (UINT16 conn_id, UINT32 trans_id, + tGATT_STATUS status, tGATTS_RSP *p_msg) +{ + tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER; + tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + + GATT_TRACE_API3 ("GATTS_SendRsp: conn_id: %u trans_id: %u Status: 0x%04x", + conn_id, trans_id, status); + + if ( (p_reg == NULL) || (p_tcb == NULL)) + { + GATT_TRACE_ERROR1 ("GATTS_SendRsp Unknown conn_id: %u ", conn_id); + return(tGATT_STATUS) GATT_INVALID_CONN_ID; + } + + if (p_tcb->sr_cmd.trans_id != trans_id) + { + GATT_TRACE_ERROR2 ("GATTS_SendRsp conn_id: %u waiting for op_code = %02x", + conn_id, p_tcb->sr_cmd.op_code); + + return(GATT_WRONG_STATE); + } + /* Process App response */ + cmd_sent = gatt_sr_process_app_rsp (p_tcb, gatt_if, trans_id, p_tcb->sr_cmd.op_code, status, p_msg); + + return cmd_sent; +} + +/*******************************************************************************/ +/* GATT Profile Srvr Functions */ +/*******************************************************************************/ + +/*******************************************************************************/ +/* */ +/* GATT CLIENT APIs */ +/* */ +/*******************************************************************************/ + + +/******************************************************************************* +** +** Function GATTC_ConfigureMTU +** +** Description This function is called to configure the ATT MTU size. +** +** Parameters conn_id: connection identifier. +** mtu - attribute MTU size.. +** +** Returns GATT_SUCCESS if command started successfully. +** +*******************************************************************************/ +tGATT_STATUS GATTC_ConfigureMTU (UINT16 conn_id, UINT16 mtu) +{ + UINT8 ret = GATT_NO_RESOURCES; + tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + + tGATT_CLCB *p_clcb; + + GATT_TRACE_API2 ("GATTC_ConfigureMTU conn_id=%d mtu=%d", conn_id, mtu ); + + // Validate that the link is BLE, not BR/EDR + // ???? + + if ( (p_tcb == NULL) || (p_reg==NULL) || (mtu < GATT_DEF_BLE_MTU_SIZE) || (mtu > GATT_MAX_MTU_SIZE)) + { + return GATT_ILLEGAL_PARAMETER; + } + + if (gatt_is_clcb_allocated(conn_id)) + { + GATT_TRACE_ERROR1("GATTC_ConfigureMTU GATT_BUSY conn_id = %d", conn_id); + return GATT_BUSY; + } + + if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL) + { + p_clcb->p_tcb->payload_size = mtu; + p_clcb->operation = GATTC_OPTYPE_CONFIG; + + ret = attp_send_cl_msg (p_clcb->p_tcb, p_clcb->clcb_idx, GATT_REQ_MTU, (tGATT_CL_MSG *)&mtu); + } + + return ret; +} + +/******************************************************************************* +** +** Function GATTC_Discover +** +** Description This function is called to do a discovery procedure on ATT server. +** +** Parameters conn_id: connection identifier. +** disc_type:discovery type. +** p_param: parameters of discovery requirement. +** +** Returns GATT_SUCCESS if command received/sent successfully. +** +*******************************************************************************/ +tGATT_STATUS GATTC_Discover (UINT16 conn_id, tGATT_DISC_TYPE disc_type, + tGATT_DISC_PARAM *p_param) +{ + tGATT_STATUS status = GATT_SUCCESS; + tGATT_CLCB *p_clcb; + tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + + + GATT_TRACE_API2 ("GATTC_Discover conn_id=%d disc_type=%d",conn_id, disc_type); + + if ( (p_tcb == NULL) || (p_reg==NULL) ||(p_param == NULL) || + (disc_type >= GATT_DISC_MAX)) + { + GATT_TRACE_ERROR2("GATTC_Discover Illegal param: disc_type %d conn_id = %d", disc_type, conn_id); + return GATT_ILLEGAL_PARAMETER; + } + + + if (gatt_is_clcb_allocated(conn_id)) + { + GATT_TRACE_ERROR1("GATTC_Discover GATT_BUSY conn_id = %d", conn_id); + return GATT_BUSY; + } + + + if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL ) + { + if (!GATT_HANDLE_IS_VALID(p_param->s_handle) || + !GATT_HANDLE_IS_VALID(p_param->e_handle) || + /* search by type does not have a valid UUID param */ + (disc_type == GATT_DISC_SRVC_BY_UUID && + p_param->service.len == 0)) + { + return GATT_ILLEGAL_PARAMETER; + } + + p_clcb->operation = GATTC_OPTYPE_DISCOVERY; + p_clcb->op_subtype = disc_type; + p_clcb->s_handle = p_param->s_handle; + p_clcb->e_handle = p_param->e_handle; + p_clcb->uuid = p_param->service; + + gatt_act_discovery(p_clcb); + } + else + { + status = GATT_NO_RESOURCES; + } + return status; +} + +/******************************************************************************* +** +** Function GATTC_Read +** +** Description This function is called to read the value of an attribute from +** the server. +** +** Parameters conn_id: connection identifier. +** type - attribute read type. +** p_read - read operation parameters. +** +** Returns GATT_SUCCESS if command started successfully. +** +*******************************************************************************/ +tGATT_STATUS GATTC_Read (UINT16 conn_id, tGATT_READ_TYPE type, tGATT_READ_PARAM *p_read) +{ + tGATT_STATUS status = GATT_SUCCESS; + tGATT_CLCB *p_clcb; + tGATT_READ_MULTI *p_read_multi; + tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + + + GATT_TRACE_API2 ("GATTC_Read conn_id=%d type=%d", conn_id, type); + + if ( (p_tcb == NULL) || (p_reg==NULL) || (p_read == NULL) || ((type >= GATT_READ_MAX) || (type == 0))) + { + GATT_TRACE_ERROR2("GATT_Read Illegal param: conn_id %d, type 0%d,", conn_id, type); + return GATT_ILLEGAL_PARAMETER; + } + + if (gatt_is_clcb_allocated(conn_id)) + { + GATT_TRACE_ERROR1("GATTC_Read GATT_BUSY conn_id = %d", conn_id); + return GATT_BUSY; + } + + if ( (p_clcb = gatt_clcb_alloc(conn_id)) != NULL ) + { + p_clcb->operation = GATTC_OPTYPE_READ; + p_clcb->op_subtype = type; + p_clcb->auth_req = p_read->by_handle.auth_req; + p_clcb->counter = 0; + + switch (type) + { + case GATT_READ_BY_TYPE: + case GATT_READ_CHAR_VALUE: + p_clcb->s_handle = p_read->service.s_handle; + p_clcb->e_handle = p_read->service.e_handle; + memcpy(&p_clcb->uuid, &p_read->service.uuid, sizeof(tBT_UUID)); + break; + case GATT_READ_MULTIPLE: + p_clcb->s_handle = 0; + /* copy multiple handles in CB */ + p_read_multi = (tGATT_READ_MULTI *)GKI_getbuf(sizeof(tGATT_READ_MULTI)); + p_clcb->p_attr_buf = (UINT8*)p_read_multi; + memcpy (p_read_multi, &p_read->read_multiple, sizeof(tGATT_READ_MULTI)); + case GATT_READ_BY_HANDLE: + case GATT_READ_PARTIAL: + memset(&p_clcb->uuid, 0, sizeof(tBT_UUID)); + p_clcb->s_handle = p_read->by_handle.handle; + + if (type == GATT_READ_PARTIAL) + { + p_clcb->counter = p_read->partial.offset; + } + + break; + default: + break; + } + /* start security check */ + if (gatt_security_check_start(p_clcb) == FALSE) + { + status = GATT_NO_RESOURCES; + gatt_clcb_dealloc(p_clcb); + } + } + else + { + status = GATT_NO_RESOURCES; + } + return status; +} + +/******************************************************************************* +** +** Function GATTC_Write +** +** Description This function is called to write the value of an attribute to +** the server. +** +** Parameters conn_id: connection identifier. +** type - attribute write type. +** p_write - write operation parameters. +** +** Returns GATT_SUCCESS if command started successfully. +** +*******************************************************************************/ +tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write) +{ + tGATT_STATUS status = GATT_SUCCESS; + tGATT_CLCB *p_clcb; + tGATT_VALUE *p; + tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + + if ( (p_tcb == NULL) || (p_reg==NULL) || (p_write == NULL) || + ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && (type != GATT_WRITE_NO_RSP)) ) + { + GATT_TRACE_ERROR2("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id, type); + return GATT_ILLEGAL_PARAMETER; + } + + if (gatt_is_clcb_allocated(conn_id)) + { + GATT_TRACE_ERROR1("GATTC_Write GATT_BUSY conn_id = %d", conn_id); + return GATT_BUSY; + } + + if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL ) + { + p_clcb->operation = GATTC_OPTYPE_WRITE; + p_clcb->op_subtype = type; + p_clcb->auth_req = p_write->auth_req; + + if (( p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf((UINT16)sizeof(tGATT_VALUE))) != NULL) + { + memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE)); + + p = (tGATT_VALUE *)p_clcb->p_attr_buf; + if (type == GATT_WRITE_PREPARE) + { + p_clcb->start_offset = p_write->offset; + p->offset = 0; + } + + if (gatt_security_check_start(p_clcb) == FALSE) + { + status = GATT_NO_RESOURCES; + } + } + else + { + status = GATT_NO_RESOURCES; + } + + if (status == GATT_NO_RESOURCES) + gatt_clcb_dealloc(p_clcb); + } + else + { + status = GATT_NO_RESOURCES; + } + return status; +} + + +/******************************************************************************* +** +** Function GATTC_ExecuteWrite +** +** Description This function is called to send an Execute write request to +** the server. +** +** Parameters conn_id: connection identifier. +** is_execute - to execute or cancel the prepare write requet(s) +** +** Returns GATT_SUCCESS if command started successfully. +** +*******************************************************************************/ +tGATT_STATUS GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute) +{ + tGATT_STATUS status = GATT_SUCCESS; + tGATT_CLCB *p_clcb; + tGATT_EXEC_FLAG flag; + tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + + GATT_TRACE_API2 ("GATTC_ExecuteWrite conn_id=%d is_execute=%d", conn_id, is_execute); + + if ( (p_tcb == NULL) || (p_reg==NULL) ) + { + GATT_TRACE_ERROR1("GATTC_ExecuteWrite Illegal param: conn_id %d", conn_id); + return GATT_ILLEGAL_PARAMETER; + } + + if (gatt_is_clcb_allocated(conn_id)) + { + GATT_TRACE_ERROR1("GATTC_Write GATT_BUSY conn_id = %d", conn_id); + return GATT_BUSY; + } + + if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL) + { + p_clcb->operation = GATTC_OPTYPE_EXE_WRITE; + flag = is_execute ? GATT_PREP_WRITE_EXEC : GATT_PREP_WRITE_CANCEL; + gatt_send_queue_write_cancel (p_clcb->p_tcb, p_clcb, flag); + } + else + { + GATT_TRACE_ERROR1("Unable to allocate client CB for conn_id %d ", conn_id); + status = GATT_NO_RESOURCES; + } + return status; +} + +/******************************************************************************* +** +** Function GATTC_SendHandleValueConfirm +** +** Description This function is called to send a handle value confirmation +** as response to a handle value notification from server. +** +** Parameters conn_id: connection identifier. +** handle: the handle of the attribute confirmation. +** +** Returns GATT_SUCCESS if command started successfully. +** +*******************************************************************************/ +tGATT_STATUS GATTC_SendHandleValueConfirm (UINT16 conn_id, UINT16 handle) +{ + tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER; + tGATT_TCB *p_tcb=gatt_get_tcb_by_idx(GATT_GET_TCB_IDX(conn_id)); + + GATT_TRACE_API2 ("GATTC_SendHandleValueConfirm conn_id=%d handle=0x%x", conn_id, handle); + + if (p_tcb) + { + if (p_tcb->ind_count > 0 ) + { + btu_stop_timer (&p_tcb->ind_ack_timer_ent); + + GATT_TRACE_DEBUG1 ("notif_count=%d ", p_tcb->ind_count); + /* send confirmation now */ + ret = attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, (tGATT_CL_MSG *)&handle); + + p_tcb->ind_count = 0; + + } + else + { + GATT_TRACE_DEBUG1 ("GATTC_SendHandleValueConfirm - conn_id: %u - ignored not waiting for indicaiton ack", conn_id); + ret = GATT_SUCCESS; + } + } + else + { + GATT_TRACE_ERROR1 ("GATTC_SendHandleValueConfirm - Unknown conn_id: %u", conn_id); + } + return ret; +} + + +/*******************************************************************************/ +/* */ +/* GATT APIs */ +/* */ +/*******************************************************************************/ +/******************************************************************************* +** +** Function GATT_SetIdleTimeout +** +** Description This function (common to both client and server) sets the idle +** timeout for a tansport connection +** +** Parameter bd_addr: target device bd address. +** idle_tout: timeout value in seconds. +** +** Returns void +** +*******************************************************************************/ +void GATT_SetIdleTimeout (BD_ADDR bd_addr, UINT16 idle_tout) +{ + tGATT_TCB *p_tcb; + BOOLEAN status = FALSE; + + if ((p_tcb = gatt_find_tcb_by_addr (bd_addr)) != NULL) + { + if (p_tcb->att_lcid == L2CAP_ATT_CID) + { + status = L2CA_SetFixedChannelTout (bd_addr, L2CAP_ATT_CID, idle_tout); + } + else + { + status = L2CA_SetIdleTimeout (p_tcb->att_lcid, idle_tout, FALSE); + } + } + + GATT_TRACE_API2 ("GATT_SetIdleTimeout idle_tout=%d status=%d(1-OK 0-not performed)", + idle_tout, status); +} + + +/******************************************************************************* +** +** Function GATT_Register +** +** Description This function is called to register an application +** with GATT +** +** Parameter p_app_uuid128: Application UUID +** p_cb_info: callback functions. +** +** Returns 0 for error, otherwise the index of the client registered with GATT +** +*******************************************************************************/ +tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info) +{ + tGATT_REG *p_reg; + UINT8 i_gatt_if=0; + tGATT_IF gatt_if=0; + + GATT_TRACE_API0 ("GATT_Register"); + gatt_dbg_display_uuid(*p_app_uuid128); + + for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++) + { + if (p_reg->in_use && !memcmp(p_app_uuid128->uu.uuid128, p_reg->app_uuid128.uu.uuid128, LEN_UUID_128)) + { + GATT_TRACE_ERROR0("application already registered."); + return 0; + } + } + + for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++) + { + if (!p_reg->in_use) + { + memset(p_reg, 0 , sizeof(tGATT_REG)); + i_gatt_if++; /* one based number */ + p_reg->app_uuid128 = *p_app_uuid128; + gatt_if = + p_reg->gatt_if = (tGATT_IF)i_gatt_if; + p_reg->app_cb = *p_cb_info; + p_reg->in_use = TRUE; + + break; + } + } + GATT_TRACE_API1 ("allocated gatt_if=%d", gatt_if); + return gatt_if; +} + + +/******************************************************************************* +** +** Function GATT_Deregister +** +** Description This function deregistered the application from GATT. +** +** Parameters gatt_if: applicaiton interface. +** +** Returns None. +** +*******************************************************************************/ +void GATT_Deregister (tGATT_IF gatt_if) +{ + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + tGATT_TCB *p_tcb; + tGATT_CLCB *p_clcb; + UINT8 i, ii, j; + tGATT_SR_REG *p_sreg; + + GATT_TRACE_API1 ("GATT_Deregister gatt_if=%d", gatt_if); + /* Index 0 is GAP and is never deregistered */ + if ( (gatt_if == 0) || (p_reg == NULL) ) + { + GATT_TRACE_ERROR1 ("GATT_Deregister with invalid gatt_if: %u", gatt_if); + return; + } + + /* stop all services */ + /* todo an applcaiton can not be deregistered if its services is also used by other application + deregisteration need to bed performed in an orderly fashion + no check for now */ + + for (ii = 0, p_sreg = gatt_cb.sr_reg; ii < GATT_MAX_SR_PROFILES; ii++, p_sreg++) + { + if (p_sreg->in_use && (p_sreg->gatt_if == gatt_if)) + { + GATTS_StopService(p_sreg->s_hdl); + } + } + + /* free all services db buffers if owned by this application */ + gatt_free_srvc_db_buffer_app_id(&p_reg->app_uuid128); + + /* When an application deregisters, check remove the link associated with the app */ + + for (i=0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++) + { + if (p_tcb->in_use) + { + if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE) + { + gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE); + if (!gatt_num_apps_hold_link(p_tcb)) + { + /* this will disconnect the link or cancel the pending connect request at lower layer*/ + gatt_disconnect(p_tcb->peer_bda); + } + } + + for (j = 0, p_clcb= &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB; j++, p_clcb++) + { + if (p_clcb->in_use && + (p_clcb->p_reg->gatt_if == gatt_if) && + (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx)) + { + gatt_clcb_dealloc (p_clcb); + break; + } + } + } + } + + gatt_deregister_bgdev_list(gatt_if); + memset (p_reg, 0, sizeof(tGATT_REG)); +} + + +/******************************************************************************* +** +** Function GATT_StartIf +** +** Description This function is called after registration to start receiving +** callbacks for registered interface. Function may call back +** with connection status and queued notifications +** +** Parameter gatt_if: applicaiton interface. +** +** Returns 0 for error, otherwise the index of the client registered with GATT +** +*******************************************************************************/ +void GATT_StartIf (tGATT_IF gatt_if) +{ + tGATT_REG *p_reg; + tGATT_TCB *p_tcb; + //tGATT_CLCB *p_clcb; + BD_ADDR bda; + UINT8 start_idx, found_idx; + UINT16 conn_id; + + GATT_TRACE_API1 ("GATT_StartIf gatt_if=%d", gatt_if); + if ((p_reg = gatt_get_regcb(gatt_if)) != NULL) + { + p_reg = &gatt_cb.cl_rcb[gatt_if - 1]; + start_idx = 0; + while (gatt_find_the_connected_bda(start_idx, bda, &found_idx)) + { + p_tcb = gatt_find_tcb_by_addr(bda); + if (p_reg->app_cb.p_conn_cb) + { + conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if); + (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, TRUE, 0); + } + start_idx = ++found_idx; + } + } +} + + +/******************************************************************************* +** +** Function GATT_Connect +** +** Description This function initiate a connecttion to a ATT server. +** +** Parameters gatt_if: applicaiton interface +** bd_addr: peer device address. +** is_direct: is a direct conenection or a background auto connection +** +** Returns TRUE if connection started; FALSE if connection start failure. +** +*******************************************************************************/ +BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){ + tGATT_REG *p_reg; + BOOLEAN status; + + GATT_TRACE_API1 ("GATT_Connect gatt_if=%d", gatt_if); + + /* Make sure app is registered */ + if ((p_reg = gatt_get_regcb(gatt_if)) == NULL) + { + GATT_TRACE_ERROR1("GATT_Connect - gatt_if =%d is not registered", gatt_if); + return(FALSE); + } + + if (is_direct) + status = gatt_act_connect (p_reg, bd_addr); + else + status = gatt_update_auto_connect_dev(gatt_if,TRUE, bd_addr); + + return status; + +} + +/******************************************************************************* +** +** Function GATT_CancelConnect +** +** Description This function initiate a connecttion to a ATT server. +** +** Parameters gatt_if: client interface. If 0 used as unconditionally disconnect, +** typically used for direct connection cancellation. +** bd_addr: peer device address. +** +** Returns TRUE if connection started; FALSE if connection start failure. +** +*******************************************************************************/ +BOOLEAN GATT_CancelConnect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){ + tGATT_REG *p_reg; + tGATT_TCB *p_tcb; + BOOLEAN status = TRUE; + tGATT_IF temp_gatt_if; + UINT8 start_idx, found_idx; + + GATT_TRACE_API1 ("GATT_CancelConnect gatt_if=%d", gatt_if); + + if ((gatt_if != 0) && ((p_reg = gatt_get_regcb(gatt_if)) == NULL)) + { + GATT_TRACE_ERROR1("GATT_CancelConnect - gatt_if =%d is not registered", gatt_if); + return(FALSE); + } + + if (is_direct) + { + if (!gatt_if) + { + GATT_TRACE_DEBUG0("GATT_CancelConnect - unconditional"); + start_idx = 0; + p_tcb = gatt_find_tcb_by_addr(bd_addr); + if (p_tcb && gatt_num_apps_hold_link(p_tcb)) + { + while (status && gatt_find_app_hold_link(p_tcb, start_idx, &found_idx, &temp_gatt_if)) + { + status = gatt_cancel_open(temp_gatt_if, bd_addr); + start_idx = ++found_idx; + } + } + else + { + GATT_TRACE_ERROR0("GATT_CancelConnect - no app found"); + status = FALSE; + } + } + else + { + status = gatt_cancel_open(gatt_if, bd_addr); + } + } + else + { + if (!gatt_if) + { + if (gatt_get_num_apps_for_bg_dev(bd_addr)) + { + while (gatt_find_app_for_bg_dev(bd_addr, &temp_gatt_if)) + gatt_remove_bg_dev_for_app(temp_gatt_if, bd_addr); + } + else + { + GATT_TRACE_ERROR0("GATT_CancelConnect -no app associated with the bg device for unconditional removal"); + status = FALSE; + } + } + else + { + status = gatt_remove_bg_dev_for_app(gatt_if, bd_addr); + } + } + + return status; +} + +/******************************************************************************* +** +** Function GATT_Disconnect +** +** Description This function disconnect a logic channel. +** +** Parameters conn_id: connection identifier. +** +** Returns GATT_SUCCESS if disconnected. +** +*******************************************************************************/ +tGATT_STATUS GATT_Disconnect (UINT16 conn_id) +{ + tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER; + tGATT_TCB *p_tcb=NULL; + tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + + GATT_TRACE_API1 ("GATT_Disconnect conn_id=%d ", conn_id); + + p_tcb = gatt_get_tcb_by_idx(tcb_idx); + + if (p_tcb) + { + gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE); + if (!gatt_num_apps_hold_link(p_tcb)) + { + gatt_disconnect(p_tcb->peer_bda); + } + ret = GATT_SUCCESS; + } + return ret; +} + + +/******************************************************************************* +** +** Function GATT_GetConnectionInfor +** +** Description This function use conn_id to find its associated BD address and applciation +** interface +** +** Parameters conn_id: connection id (input) +** p_gatt_if: applicaiton interface (output) +** bd_addr: peer device address. (output) +** +** Returns TRUE the ligical link information is found for conn_id +** +*******************************************************************************/ +BOOLEAN GATT_GetConnectionInfor(UINT16 conn_id, tGATT_IF *p_gatt_if, BD_ADDR bd_addr) +{ + + tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); + tGATT_TCB *p_tcb= gatt_get_tcb_by_idx(tcb_idx); + BOOLEAN status=FALSE; + + GATT_TRACE_API1 ("GATT_GetConnectionInfor conn_id=%d", conn_id); + + if (p_tcb && p_reg ) + { + memcpy(bd_addr, p_tcb->peer_bda, BD_ADDR_LEN); + *p_gatt_if = gatt_if; + status = TRUE; + } + return status; +} + + +/******************************************************************************* +** +** Function GATT_GetConnIdIfConnected +** +** Description This function find the conn_id if the logical link for BD address +** and applciation interface is connected +** +** Parameters gatt_if: applicaiton interface (input) +** bd_addr: peer device address. (input) +** p_conn_id: connection id (output) +** +** Returns TRUE the ligical link is connected +** +*******************************************************************************/ +BOOLEAN GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr, UINT16 *p_conn_id) +{ + tGATT_REG *p_reg = gatt_get_regcb(gatt_if); + tGATT_TCB *p_tcb= gatt_find_tcb_by_addr(bd_addr); + BOOLEAN status=FALSE; + + if (p_reg && p_tcb && (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) ) + { + *p_conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if); + status = TRUE; + } + + GATT_TRACE_API1 ("GATT_GetConnIdIfConnected status=%d", status); + return status; +} + +#endif + + |