summaryrefslogtreecommitdiffstats
path: root/stack/gatt/gatt_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'stack/gatt/gatt_api.c')
-rw-r--r--stack/gatt/gatt_api.c1555
1 files changed, 1555 insertions, 0 deletions
diff --git a/stack/gatt/gatt_api.c b/stack/gatt/gatt_api.c
new file mode 100644
index 0000000..7845f3c
--- /dev/null
+++ b/stack/gatt/gatt_api.c
@@ -0,0 +1,1555 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains GATT interface functions
+ *
+ ******************************************************************************/
+#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 *)&notif);
+ 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
+
+