summaryrefslogtreecommitdiff
path: root/lib/bt/host/bluedroid/stack/gap
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2024-03-28 14:32:49 +1100
committerjacqueline <me@jacqueline.id.au>2024-03-28 14:32:49 +1100
commitee29c25b29eaa4fac4e897442634b69ecc8d8125 (patch)
tree8c5f1a140463f20f104316fa3492984e191154e9 /lib/bt/host/bluedroid/stack/gap
parent239e6d89507a24c849385f4bfa93ac4ad58e5de5 (diff)
downloadtangara-fw-ee29c25b29eaa4fac4e897442634b69ecc8d8125.tar.gz
Fork ESP-IDF's bluetooth component
i want better sbc encoding, and no cla will stop me
Diffstat (limited to 'lib/bt/host/bluedroid/stack/gap')
-rw-r--r--lib/bt/host/bluedroid/stack/gap/gap_api.c109
-rw-r--r--lib/bt/host/bluedroid/stack/gap/gap_ble.c823
-rw-r--r--lib/bt/host/bluedroid/stack/gap/gap_conn.c1211
-rw-r--r--lib/bt/host/bluedroid/stack/gap/gap_utils.c141
-rw-r--r--lib/bt/host/bluedroid/stack/gap/include/gap_int.h159
5 files changed, 2443 insertions, 0 deletions
diff --git a/lib/bt/host/bluedroid/stack/gap/gap_api.c b/lib/bt/host/bluedroid/stack/gap/gap_api.c
new file mode 100644
index 00000000..75d5b5d1
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/gap/gap_api.c
@@ -0,0 +1,109 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "common/bt_target.h"
+//#include "bt_utils.h"
+#include "gap_int.h"
+#include "osi/allocator.h"
+
+#if GAP_DYNAMIC_MEMORY == FALSE
+tGAP_CB gap_cb;
+#else
+tGAP_CB *gap_cb_ptr;
+#endif
+
+/*******************************************************************************
+**
+** Function GAP_SetTraceLevel
+**
+** Description This function sets the trace level for GAP. If called with
+** a value of 0xFF, it simply returns the current trace level.
+**
+** Returns The new or current trace level
+**
+*******************************************************************************/
+UINT8 GAP_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF) {
+ gap_cb.trace_level = new_level;
+ }
+
+ return (gap_cb.trace_level);
+}
+
+/*******************************************************************************
+**
+** Function GAP_Init
+**
+** Description Initializes the control blocks used by GAP.
+**
+** This routine should not be called except once per
+** stack invocation.
+**
+** Returns status
+**
+*******************************************************************************/
+bt_status_t GAP_Init(void)
+{
+#if GAP_DYNAMIC_MEMORY == TRUE
+ gap_cb_ptr = (tGAP_CB *)osi_malloc(sizeof(tGAP_CB));
+ if (!gap_cb_ptr) {
+ return BT_STATUS_NOMEM;
+ }
+#endif
+
+ memset (&gap_cb, 0, sizeof (tGAP_CB));
+
+#if defined(GAP_INITIAL_TRACE_LEVEL)
+ gap_cb.trace_level = GAP_INITIAL_TRACE_LEVEL;
+#else
+ gap_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+
+#if GAP_CONN_INCLUDED == TRUE
+ gap_conn_init();
+#endif
+
+#if BLE_INCLUDED == TRUE && GATTS_INCLUDED == TRUE
+ gap_attr_db_init();
+#endif
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function GAP_Deinit
+**
+** Description This function is called to deinitialize the control block
+** for this layer.
+**
+** Returns void
+**
+*******************************************************************************/
+void GAP_Deinit(void)
+{
+#if GAP_DYNAMIC_MEMORY == TRUE
+ if (gap_cb_ptr) {
+ osi_free(gap_cb_ptr);
+ gap_cb_ptr = NULL;
+ }
+#endif
+}
diff --git a/lib/bt/host/bluedroid/stack/gap/gap_ble.c b/lib/bt/host/bluedroid/stack/gap/gap_ble.c
new file mode 100644
index 00000000..5bac86f0
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/gap/gap_ble.c
@@ -0,0 +1,823 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+#include "common/bt_target.h"
+
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE && GATTS_INCLUDED == TRUE)
+
+#include "common/bt_defs.h"
+#include "osi/allocator.h"
+#include <string.h>
+#include "gap_int.h"
+#include "stack/gap_api.h"
+#include "stack/gattdefs.h"
+#include "stack/gatt_api.h"
+#include "gatt_int.h"
+#include "btm_int.h"
+#include "stack/hcimsgs.h"
+#include "stack/sdpdefs.h"
+
+#define GAP_CHAR_ICON_SIZE 2
+#define GAP_CHAR_DEV_NAME_SIZE 248
+#define GAP_MAX_NUM_INC_SVR 0
+#define GAP_MAX_ATTR_NUM (2 * GAP_MAX_CHAR_NUM + GAP_MAX_NUM_INC_SVR + 1)
+#define GAP_MAX_CHAR_VALUE_SIZE (30 + GAP_CHAR_DEV_NAME_SIZE)
+
+
+#ifndef GAP_ATTR_DB_SIZE
+#define GAP_ATTR_DB_SIZE GATT_DB_MEM_SIZE(GAP_MAX_NUM_INC_SVR, GAP_MAX_CHAR_NUM, GAP_MAX_CHAR_VALUE_SIZE)
+#endif
+
+static void gap_ble_s_attr_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE op_code, tGATTS_DATA *p_data);
+
+/* client connection callback */
+static void gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected,
+ tGATT_DISCONN_REASON reason, tGATT_TRANSPORT transport);
+static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data);
+
+static const tGATT_CBACK gap_cback = {
+ gap_ble_c_connect_cback,
+ gap_ble_c_cmpl_cback,
+ NULL,
+ NULL,
+ gap_ble_s_attr_request_cback,
+ NULL,
+ NULL
+};
+
+
+
+/*******************************************************************************
+**
+** Function gap_find_clcb_by_bd_addr
+**
+** Description The function searches all LCB with macthing bd address
+**
+** Returns total number of clcb found.
+**
+*******************************************************************************/
+tGAP_CLCB *gap_find_clcb_by_bd_addr(BD_ADDR bda)
+{
+ UINT8 i_clcb;
+ tGAP_CLCB *p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb = gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++) {
+ if (p_clcb->in_use && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN)) {
+ return p_clcb;
+ }
+ }
+
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function gap_ble_find_clcb_by_conn_id
+**
+** Description The function searches all LCB with macthing connection ID
+**
+** Returns total number of clcb found.
+**
+*******************************************************************************/
+tGAP_CLCB *gap_ble_find_clcb_by_conn_id(UINT16 conn_id)
+{
+ UINT8 i_clcb;
+ tGAP_CLCB *p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb = gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++) {
+ if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id) {
+ return p_clcb;
+ }
+ }
+
+ return p_clcb;
+}
+
+/*******************************************************************************
+**
+** Function gap_clcb_alloc
+**
+** Description The function allocates a GAP connection link control block
+**
+** Returns NULL if not found. Otherwise pointer to the connection link block.
+**
+*******************************************************************************/
+tGAP_CLCB *gap_clcb_alloc (BD_ADDR bda)
+{
+ UINT8 i_clcb = 0;
+ tGAP_CLCB *p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb = gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++) {
+ if (!p_clcb->in_use) {
+ memset(p_clcb, 0, sizeof(tGAP_CLCB));
+ p_clcb->in_use = TRUE;
+ memcpy (p_clcb->bda, bda, BD_ADDR_LEN);
+ break;
+ }
+ }
+ return p_clcb;
+}
+
+/*******************************************************************************
+**
+** Function gap_ble_dealloc_clcb
+**
+** Description The function clean up the pending request queue in GAP
+**
+** Returns none
+**
+*******************************************************************************/
+void gap_ble_dealloc_clcb(tGAP_CLCB *p_clcb)
+{
+ tGAP_BLE_REQ *p_q;
+
+ while ((p_q = (tGAP_BLE_REQ *)fixed_queue_dequeue(p_clcb->pending_req_q, 0)) != NULL) {
+ /* send callback to all pending requests if being removed*/
+ if (p_q->p_cback != NULL) {
+ (*p_q->p_cback)(FALSE, p_clcb->bda, 0, NULL);
+ }
+
+ osi_free (p_q);
+ }
+
+ memset(p_clcb, 0, sizeof(tGAP_CLCB));
+}
+
+/*******************************************************************************
+**
+** Function gap_ble_enqueue_request
+**
+** Description The function enqueue a GAP client request
+**
+** Returns TRUE is successul; FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN gap_ble_enqueue_request (tGAP_CLCB *p_clcb, UINT16 uuid, tGAP_BLE_CMPL_CBACK *p_cback)
+{
+ tGAP_BLE_REQ *p_q = (tGAP_BLE_REQ *)osi_malloc(sizeof(tGAP_BLE_REQ));
+
+ if (p_q != NULL) {
+ p_q->p_cback = p_cback;
+ p_q->uuid = uuid;
+ fixed_queue_enqueue(p_clcb->pending_req_q, p_q, FIXED_QUEUE_MAX_TIMEOUT);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+/*******************************************************************************
+**
+** Function gap_ble_dequeue_request
+**
+** Description The function dequeue a GAP client request if any
+**
+** Returns TRUE is successul; FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN gap_ble_dequeue_request (tGAP_CLCB *p_clcb, UINT16 *p_uuid, tGAP_BLE_CMPL_CBACK **p_cback)
+{
+ tGAP_BLE_REQ *p_q = (tGAP_BLE_REQ *)fixed_queue_dequeue(p_clcb->pending_req_q, 0);;
+
+ if (p_q != NULL) {
+ *p_cback = p_q->p_cback;
+ *p_uuid = p_q->uuid;
+ osi_free((void *)p_q);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+** GAP Attributes Database Request callback
+*******************************************************************************/
+tGATT_STATUS gap_read_attr_value (UINT16 handle, tGATT_VALUE *p_value, BOOLEAN is_long)
+{
+ tGAP_ATTR *p_db_attr = gap_cb.gap_attr;
+ UINT8 *p = p_value->value, i;
+ UINT16 offset = p_value->offset;
+ UINT8 *p_dev_name = NULL;
+
+ for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++) {
+ if (handle == p_db_attr->handle) {
+ if (p_db_attr->uuid != GATT_UUID_GAP_DEVICE_NAME &&
+ is_long == TRUE) {
+ return GATT_NOT_LONG;
+ }
+
+ switch (p_db_attr->uuid) {
+ case GATT_UUID_GAP_DEVICE_NAME:
+ BTM_ReadLocalDeviceName((char **)&p_dev_name);
+ if (strlen ((char *)p_dev_name) > GATT_MAX_ATTR_LEN) {
+ p_value->len = GATT_MAX_ATTR_LEN;
+ } else {
+ p_value->len = (UINT16)strlen ((char *)p_dev_name);
+ }
+
+ if (offset > p_value->len) {
+ return GATT_INVALID_OFFSET;
+ } else {
+ p_value->len -= offset;
+ p_dev_name += offset;
+ ARRAY_TO_STREAM(p, p_dev_name, p_value->len);
+ GAP_TRACE_EVENT("GATT_UUID_GAP_DEVICE_NAME len=0x%04x", p_value->len);
+ }
+ break;
+
+ case GATT_UUID_GAP_ICON:
+ UINT16_TO_STREAM(p, p_db_attr->attr_value.icon);
+ p_value->len = 2;
+ break;
+
+ case GATT_UUID_GAP_PREF_CONN_PARAM:
+ UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.int_min); /* int_min */
+ UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.int_max); /* int_max */
+ UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.latency); /* latency */
+ UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.sp_tout); /* sp_tout */
+ p_value->len = 8;
+ break;
+
+ /* address resolution */
+ case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
+ UINT8_TO_STREAM(p, p_db_attr->attr_value.addr_resolution);
+ p_value->len = 1;
+ break;
+ }
+ return GATT_SUCCESS;
+ }
+ }
+ return GATT_NOT_FOUND;
+}
+
+/*******************************************************************************
+** GAP Attributes Database Read/Read Blob Request process
+*******************************************************************************/
+tGATT_STATUS gap_proc_read (tGATTS_REQ_TYPE type, tGATT_READ_REQ *p_data, tGATTS_RSP *p_rsp)
+{
+ tGATT_STATUS status = GATT_NO_RESOURCES;
+ UNUSED(type);
+
+ if (p_data->is_long) {
+ p_rsp->attr_value.offset = p_data->offset;
+ }
+
+ p_rsp->attr_value.handle = p_data->handle;
+
+ status = gap_read_attr_value(p_data->handle, &p_rsp->attr_value, p_data->is_long);
+
+ return status;
+}
+
+/******************************************************************************
+**
+** Function gap_proc_write_req
+**
+** Description GAP ATT server process a write request.
+**
+** Returns void.
+**
+*******************************************************************************/
+UINT8 gap_proc_write_req( tGATTS_REQ_TYPE type, tGATT_WRITE_REQ *p_data)
+{
+ tGAP_ATTR *p_db_attr = gap_cb.gap_attr;
+ UINT8 i;
+ UNUSED(type);
+
+ for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++) {
+ if (p_data->handle == p_db_attr->handle) {
+ switch (p_db_attr->uuid) {
+ #if (GATTS_DEVICE_NAME_WRITABLE == TRUE)
+ case GATT_UUID_GAP_DEVICE_NAME: {
+ UINT8 *p_val = p_data->value;
+ p_val[p_data->len] = '\0';
+ BTM_SetLocalDeviceName((char *)p_val);
+ return GATT_SUCCESS;
+ }
+ #endif
+ #if (GATTS_APPEARANCE_WRITABLE == TRUE)
+ case GATT_UUID_GAP_ICON: {
+ UINT8 *p_val = p_data->value;
+ if (p_data->len != sizeof(UINT16)) {
+ return GATT_INVALID_ATTR_LEN;
+ }
+ STREAM_TO_UINT16(p_db_attr->attr_value.icon, p_val);
+ return GATT_SUCCESS;
+ }
+ #endif
+ default:
+ break;
+ }
+ return GATT_WRITE_NOT_PERMIT;
+ }
+ }
+
+ return GATT_NOT_FOUND;
+}
+
+/******************************************************************************
+**
+** Function gap_ble_s_attr_request_cback
+**
+** Description GAP ATT server attribute access request callback.
+**
+** Returns void.
+**
+*******************************************************************************/
+void gap_ble_s_attr_request_cback (UINT16 conn_id, UINT32 trans_id,
+ tGATTS_REQ_TYPE type, tGATTS_DATA *p_data)
+{
+ UINT8 status = GATT_INVALID_PDU;
+ tGATTS_RSP rsp_msg;
+ BOOLEAN ignore = FALSE;
+
+ GAP_TRACE_EVENT("gap_ble_s_attr_request_cback : recv type (0x%02x)", type);
+
+ memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
+
+ switch (type) {
+ case GATTS_REQ_TYPE_READ:
+ status = gap_proc_read(type, &p_data->read_req, &rsp_msg);
+ break;
+
+ case GATTS_REQ_TYPE_WRITE:
+ if (!p_data->write_req.need_rsp) {
+ ignore = TRUE;
+ }
+
+ status = gap_proc_write_req(type, &p_data->write_req);
+ break;
+
+ case GATTS_REQ_TYPE_WRITE_EXEC:
+ ignore = TRUE;
+ GAP_TRACE_EVENT("Ignore GATTS_REQ_TYPE_WRITE_EXEC" );
+ break;
+
+ case GATTS_REQ_TYPE_MTU:
+ GAP_TRACE_EVENT("Get MTU exchange new mtu size: %d", p_data->mtu);
+ ignore = TRUE;
+ break;
+
+ default:
+ GAP_TRACE_EVENT("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
+ break;
+ }
+
+ if (!ignore) {
+ GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_att_db_init
+**
+** Description GAP ATT database initalization.
+**
+** Returns void.
+**
+*******************************************************************************/
+void gap_attr_db_init(void)
+{
+ tBT_UUID app_uuid = {LEN_UUID_128, {0}};
+ tBT_UUID uuid = {LEN_UUID_16, {UUID_SERVCLASS_GAP_SERVER}};
+ UINT16 service_handle;
+ tGAP_ATTR *p_db_attr = &gap_cb.gap_attr[0];
+ tGATT_STATUS status;
+
+ /* Fill our internal UUID with a fixed pattern 0x82 */
+ memset (&app_uuid.uu.uuid128, 0x82, LEN_UUID_128);
+ memset(gap_cb.gap_attr, 0, sizeof(tGAP_ATTR) *GAP_MAX_CHAR_NUM);
+
+ gap_cb.gatt_if = GATT_Register(&app_uuid, &gap_cback);
+
+ GATT_StartIf(gap_cb.gatt_if);
+
+ /* Create a GAP service */
+ service_handle = GATTS_CreateService (gap_cb.gatt_if, &uuid, 0, GAP_MAX_ATTR_NUM, TRUE);
+
+ GAP_TRACE_EVENT ("gap_attr_db_init service_handle = %d", service_handle);
+
+ /* add Device Name Characteristic
+ */
+ uuid.len = LEN_UUID_16;
+ uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_DEVICE_NAME;
+ p_db_attr->handle = GATTS_AddCharacteristic(service_handle, &uuid,
+ #if (GATTS_DEVICE_NAME_WRITABLE == TRUE)
+ GATT_PERM_READ | GATT_PERM_WRITE,
+ GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE_NR,
+ #else
+ GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ,
+ #endif
+ NULL, NULL);
+ p_db_attr ++;
+
+ /* add Icon characteristic
+ */
+ uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_ICON;
+ p_db_attr->handle = GATTS_AddCharacteristic(service_handle, &uuid,
+ #if (GATTS_APPEARANCE_WRITABLE == TRUE)
+ GATT_PERM_READ | GATT_PERM_WRITE,
+ GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE_NR,
+ #else
+ GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ,
+ #endif
+ NULL, NULL);
+ p_db_attr ++;
+
+#if ((defined BTM_PERIPHERAL_ENABLED) && (BTM_PERIPHERAL_ENABLED == TRUE))
+ /* Only needed for peripheral testing */
+ /* add preferred connection parameter characteristic
+ */
+ uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_PREF_CONN_PARAM;
+ p_db_attr->attr_value.conn_param.int_max = GAP_PREFER_CONN_INT_MAX; /* 6 */
+ p_db_attr->attr_value.conn_param.int_min = GAP_PREFER_CONN_INT_MIN; /* 0 */
+ p_db_attr->attr_value.conn_param.latency = GAP_PREFER_CONN_LATENCY; /* 0 */
+ p_db_attr->attr_value.conn_param.sp_tout = GAP_PREFER_CONN_SP_TOUT; /* 2000 */
+ p_db_attr->handle = GATTS_AddCharacteristic(service_handle,
+ &uuid,
+ GATT_PERM_READ,
+ GATT_CHAR_PROP_BIT_READ,
+ NULL, NULL);
+ p_db_attr ++;
+#endif
+
+ /* add Central address resolution Characteristic */
+ uuid.len = LEN_UUID_16;
+ uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_CENTRAL_ADDR_RESOL;
+ p_db_attr->handle = GATTS_AddCharacteristic(service_handle, &uuid,
+ GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ,
+ NULL, NULL);
+ p_db_attr->attr_value.addr_resolution = 0;
+ p_db_attr++;
+
+ /* start service now */
+ memset (&app_uuid.uu.uuid128, 0x81, LEN_UUID_128);
+
+ status = GATTS_StartService(gap_cb.gatt_if, service_handle, GAP_TRANSPORT_SUPPORTED );
+#if (CONFIG_BT_STACK_NO_LOG)
+ (void) status;
+#endif
+
+ GAP_TRACE_EVENT ("GAP App gatt_if: %d s_hdl = %d start_status=%d",
+ gap_cb.gatt_if, service_handle, status);
+
+
+
+}
+
+/*******************************************************************************
+**
+** Function GAP_BleAttrDBUpdate
+**
+** Description GAP ATT database update.
+**
+** Returns void.
+**
+*******************************************************************************/
+void GAP_BleAttrDBUpdate(UINT16 attr_uuid, tGAP_BLE_ATTR_VALUE *p_value)
+{
+ tGAP_ATTR *p_db_attr = gap_cb.gap_attr;
+ UINT8 i = 0;
+
+ GAP_TRACE_EVENT("GAP_BleAttrDBUpdate attr_uuid=0x%04x\n", attr_uuid);
+
+ for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++) {
+ if (p_db_attr->uuid == attr_uuid) {
+ GAP_TRACE_EVENT("Found attr_uuid=0x%04x\n", attr_uuid);
+
+ switch (attr_uuid) {
+ case GATT_UUID_GAP_ICON:
+ p_db_attr->attr_value.icon = p_value->icon;
+ break;
+
+ case GATT_UUID_GAP_PREF_CONN_PARAM:
+ memcpy((void *)&p_db_attr->attr_value.conn_param,
+ (const void *)&p_value->conn_param, sizeof(tGAP_BLE_PREF_PARAM));
+ break;
+
+ case GATT_UUID_GAP_DEVICE_NAME:
+ BTM_SetLocalDeviceName((char *)p_value->p_dev_name);
+ break;
+
+ case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
+ p_db_attr->attr_value.addr_resolution = p_value->addr_resolution;
+ break;
+
+ }
+ break;
+ }
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function gap_ble_send_cl_read_request
+**
+** Description utility function to send a read request for a GAP charactersitic
+**
+** Returns TRUE if read started, else FALSE if GAP is busy
+**
+*******************************************************************************/
+BOOLEAN gap_ble_send_cl_read_request(tGAP_CLCB *p_clcb)
+{
+ tGATT_READ_PARAM param;
+ UINT16 uuid = 0;
+ BOOLEAN started = FALSE;
+
+ if (gap_ble_dequeue_request(p_clcb, &uuid, &p_clcb->p_cback)) {
+ memset(&param, 0, sizeof(tGATT_READ_PARAM));
+
+ param.service.uuid.len = LEN_UUID_16;
+ param.service.uuid.uu.uuid16 = uuid;
+ param.service.s_handle = 1;
+ param.service.e_handle = 0xFFFF;
+ param.service.auth_req = 0;
+#if (GATTC_INCLUDED == TRUE)
+ if (GATTC_Read(p_clcb->conn_id, GATT_READ_BY_TYPE, &param) == GATT_SUCCESS) {
+ p_clcb->cl_op_uuid = uuid;
+ started = TRUE;
+ }
+#endif ///GATTC_INCLUDED == TRUE
+ }
+
+ return started;
+}
+
+/*******************************************************************************
+**
+** Function gap_ble_cl_op_cmpl
+**
+** Description GAP client operation complete callback
+**
+** Returns void
+**
+*******************************************************************************/
+void gap_ble_cl_op_cmpl(tGAP_CLCB *p_clcb, BOOLEAN status, UINT16 len, UINT8 *p_name)
+{
+ tGAP_BLE_CMPL_CBACK *p_cback = p_clcb->p_cback;
+ UINT16 op = p_clcb->cl_op_uuid;
+
+ GAP_TRACE_EVENT("gap_ble_cl_op_cmpl status: %d", status);
+
+ p_clcb->cl_op_uuid = 0;
+ p_clcb->p_cback = NULL;
+
+ if (p_cback && op) {
+ GAP_TRACE_EVENT("calling gap_ble_cl_op_cmpl");
+ (* p_cback)(status, p_clcb->bda, len, (char *)p_name);
+ }
+
+ /* if no further activity is requested in callback, drop the link */
+ if (p_clcb->connected) {
+ if (!gap_ble_send_cl_read_request(p_clcb)) {
+ GATT_Disconnect(p_clcb->conn_id);
+ gap_ble_dealloc_clcb(p_clcb);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function gap_ble_c_connect_cback
+**
+** Description Client connection callback.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id,
+ BOOLEAN connected, tGATT_DISCONN_REASON reason,
+ tGATT_TRANSPORT transport)
+{
+ tGAP_CLCB *p_clcb = gap_find_clcb_by_bd_addr (bda);
+
+ UNUSED(gatt_if);
+ UNUSED(transport);
+
+ if (p_clcb != NULL) {
+ if (connected) {
+ p_clcb->conn_id = conn_id;
+ p_clcb->connected = TRUE;
+ /* start operation is pending */
+ gap_ble_send_cl_read_request(p_clcb);
+ } else {
+ p_clcb->connected = FALSE;
+ gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
+ /* clean up clcb */
+ gap_ble_dealloc_clcb(p_clcb);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function gap_ble_c_cmpl_cback
+**
+** Description Client operation complete callback.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
+
+{
+ tGAP_CLCB *p_clcb = gap_ble_find_clcb_by_conn_id(conn_id);
+ UINT16 op_type;
+ UINT16 min, max, latency, tout;
+ UINT16 len;
+ UINT8 *pp;
+
+ if (p_clcb == NULL) {
+ return;
+ }
+
+ op_type = p_clcb->cl_op_uuid;
+
+ GAP_TRACE_EVENT ("gap_ble_c_cmpl_cback() - op_code: 0x%02x status: 0x%02x read_type: 0x%04x\n", op, status, op_type);
+ /* Currently we only issue read commands */
+ if (op != GATTC_OPTYPE_READ) {
+ return;
+ }
+
+ if (status != GATT_SUCCESS) {
+ gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
+ return;
+ }
+
+ pp = p_data->att_value.value;
+
+ switch (op_type) {
+ case GATT_UUID_GAP_PREF_CONN_PARAM:
+ GAP_TRACE_EVENT ("GATT_UUID_GAP_PREF_CONN_PARAM");
+ /* Extract the peripheral preferred connection parameters and save them */
+
+ STREAM_TO_UINT16 (min, pp);
+ STREAM_TO_UINT16 (max, pp);
+ STREAM_TO_UINT16 (latency, pp);
+ STREAM_TO_UINT16 (tout, pp);
+
+ BTM_BleSetPrefConnParams (p_clcb->bda, min, max, latency, tout);
+ /* release the connection here */
+ gap_ble_cl_op_cmpl(p_clcb, TRUE, 0, NULL);
+ break;
+
+ case GATT_UUID_GAP_DEVICE_NAME:
+ GAP_TRACE_EVENT ("GATT_UUID_GAP_DEVICE_NAME\n");
+ len = (UINT16)strlen((char *)pp);
+ if (len > GAP_CHAR_DEV_NAME_SIZE) {
+ len = GAP_CHAR_DEV_NAME_SIZE;
+ }
+ gap_ble_cl_op_cmpl(p_clcb, TRUE, len, pp);
+ break;
+
+ case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
+ gap_ble_cl_op_cmpl(p_clcb, TRUE, 1, pp);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function gap_ble_accept_cl_operation
+**
+** Description Start a process to read peer address resolution capability
+**
+** Returns TRUE if request accepted
+**
+*******************************************************************************/
+BOOLEAN gap_ble_accept_cl_operation(BD_ADDR peer_bda, UINT16 uuid, tGAP_BLE_CMPL_CBACK *p_cback)
+{
+ tGAP_CLCB *p_clcb;
+ BOOLEAN started = FALSE;
+
+ if (p_cback == NULL && uuid != GATT_UUID_GAP_PREF_CONN_PARAM) {
+ return (started);
+ }
+
+ if ((p_clcb = gap_find_clcb_by_bd_addr (peer_bda)) == NULL) {
+ if ((p_clcb = gap_clcb_alloc(peer_bda)) == NULL) {
+ GAP_TRACE_ERROR("gap_ble_accept_cl_operation max connection reached");
+ return started;
+ }
+ }
+
+ GAP_TRACE_EVENT ("%s() - BDA: %08x%04x cl_op_uuid: 0x%04x",
+ __FUNCTION__,
+ (peer_bda[0] << 24) + (peer_bda[1] << 16) + (peer_bda[2] << 8) + peer_bda[3],
+ (peer_bda[4] << 8) + peer_bda[5], uuid);
+
+ if (GATT_GetConnIdIfConnected(gap_cb.gatt_if, peer_bda, &p_clcb->conn_id, BT_TRANSPORT_LE)) {
+ p_clcb->connected = TRUE;
+ }
+
+ /* hold the link here */
+ if (!GATT_Connect(gap_cb.gatt_if, p_clcb->bda, BLE_ADDR_UNKNOWN_TYPE, TRUE, BT_TRANSPORT_LE, FALSE)) {
+ return started;
+ }
+
+ /* enqueue the request */
+ gap_ble_enqueue_request(p_clcb, uuid, p_cback);
+
+ if (p_clcb->connected && p_clcb->cl_op_uuid == 0) {
+ started = gap_ble_send_cl_read_request(p_clcb);
+ } else { /* wait for connection up or pending operation to finish */
+ started = TRUE;
+ }
+
+ return started;
+}
+/*******************************************************************************
+**
+** Function GAP_BleReadPeerPrefConnParams
+**
+** Description Start a process to read a connected peripheral's preferred
+** connection parameters
+**
+** Returns TRUE if read started, else FALSE if GAP is busy
+**
+*******************************************************************************/
+BOOLEAN GAP_BleReadPeerPrefConnParams (BD_ADDR peer_bda)
+{
+ return gap_ble_accept_cl_operation (peer_bda, GATT_UUID_GAP_PREF_CONN_PARAM, NULL);
+}
+
+/*******************************************************************************
+**
+** Function GAP_BleReadPeerDevName
+**
+** Description Start a process to read a connected peripheral's device name.
+**
+** Returns TRUE if request accepted
+**
+*******************************************************************************/
+BOOLEAN GAP_BleReadPeerDevName (BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK *p_cback)
+{
+ return gap_ble_accept_cl_operation (peer_bda, GATT_UUID_GAP_DEVICE_NAME, p_cback);
+}
+
+/*******************************************************************************
+**
+** Function GAP_BleReadPeerAddressResolutionCap
+**
+** Description Start a process to read peer address resolution capability
+**
+** Returns TRUE if request accepted
+**
+*******************************************************************************/
+BOOLEAN GAP_BleReadPeerAddressResolutionCap (BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK *p_cback)
+{
+ return gap_ble_accept_cl_operation(peer_bda, GATT_UUID_GAP_CENTRAL_ADDR_RESOL, p_cback);
+}
+
+/*******************************************************************************
+**
+** Function GAP_BleCancelReadPeerDevName
+**
+** Description Cancel reading a peripheral's device name.
+**
+** Returns TRUE if request accepted
+**
+*******************************************************************************/
+BOOLEAN GAP_BleCancelReadPeerDevName (BD_ADDR peer_bda)
+{
+ tGAP_CLCB *p_clcb = gap_find_clcb_by_bd_addr (peer_bda);
+
+ GAP_TRACE_EVENT ("GAP_BleCancelReadPeerDevName() - BDA: %08x%04x cl_op_uuid: 0x%04x",
+ (peer_bda[0] << 24) + (peer_bda[1] << 16) + (peer_bda[2] << 8) + peer_bda[3],
+ (peer_bda[4] << 8) + peer_bda[5], (p_clcb == NULL) ? 0 : p_clcb->cl_op_uuid);
+
+ if (p_clcb == NULL) {
+ GAP_TRACE_ERROR ("Cannot cancel current op is not get dev name");
+ return FALSE;
+ }
+
+ if (!p_clcb->connected) {
+ if (!GATT_CancelConnect(gap_cb.gatt_if, peer_bda, TRUE)) {
+ GAP_TRACE_ERROR ("Cannot cancel where No connection id");
+ return FALSE;
+ }
+ }
+
+ gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
+
+ return (TRUE);
+}
+
+#endif /* BLE_INCLUDED == TRUE && GATTS_INCLUDED == TRUE*/
diff --git a/lib/bt/host/bluedroid/stack/gap/gap_conn.c b/lib/bt/host/bluedroid/stack/gap/gap_conn.c
new file mode 100644
index 00000000..db9065de
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/gap/gap_conn.c
@@ -0,0 +1,1211 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+
+#include "common/bt_target.h"
+#include "common/bt_defs.h"
+#include "stack/btu.h"
+#include "gap_int.h"
+#include "stack/l2cdefs.h"
+#include "l2c_int.h"
+#include <string.h>
+#include "osi/mutex.h"
+#include "osi/allocator.h"
+
+#if GAP_CONN_INCLUDED == TRUE
+#include "btm_int.h"
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static void gap_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id);
+static void gap_connect_cfm (UINT16 l2cap_cid, UINT16 result);
+static void gap_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void gap_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void gap_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed);
+static void gap_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg);
+static void gap_congestion_ind (UINT16 lcid, BOOLEAN is_congested);
+
+static tGAP_CCB *gap_find_ccb_by_cid (UINT16 cid);
+static tGAP_CCB *gap_find_ccb_by_handle (UINT16 handle);
+static tGAP_CCB *gap_allocate_ccb (void);
+static void gap_release_ccb (tGAP_CCB *p_ccb);
+
+/*******************************************************************************
+**
+** Function gap_conn_init
+**
+** Description This function is called to initialize GAP connection management
+**
+** Returns void
+**
+*******************************************************************************/
+void gap_conn_init (void)
+{
+#if ((defined AMP_INCLUDED) && (AMP_INCLUDED == TRUE))
+ gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = gap_connect_ind;
+ gap_cb.conn.reg_info.pAMP_ConnectCfm_Cb = gap_connect_cfm;
+ gap_cb.conn.reg_info.pAMP_ConnectPnd_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_ConfigInd_Cb = gap_config_ind;
+ gap_cb.conn.reg_info.pAMP_ConfigCfm_Cb = gap_config_cfm;
+ gap_cb.conn.reg_info.pAMP_DisconnectInd_Cb = gap_disconnect_ind;
+ gap_cb.conn.reg_info.pAMP_DisconnectCfm_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_QoSViolationInd_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_DataInd_Cb = gap_data_ind;
+ gap_cb.conn.reg_info.pAMP_CongestionStatus_Cb = gap_congestion_ind;
+ gap_cb.conn.reg_info.pAMP_TxComplete_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_MoveInd_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_MoveRsp_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_MoveCfm_Cb = NULL; //gap_move_cfm
+ gap_cb.conn.reg_info.pAMP_MoveCfmRsp_Cb = NULL; //gap_move_cfm_rsp
+
+#else
+ gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind;
+ gap_cb.conn.reg_info.pL2CA_ConnectCfm_Cb = gap_connect_cfm;
+ gap_cb.conn.reg_info.pL2CA_ConnectPnd_Cb = NULL;
+ gap_cb.conn.reg_info.pL2CA_ConfigInd_Cb = gap_config_ind;
+ gap_cb.conn.reg_info.pL2CA_ConfigCfm_Cb = gap_config_cfm;
+ gap_cb.conn.reg_info.pL2CA_DisconnectInd_Cb = gap_disconnect_ind;
+ gap_cb.conn.reg_info.pL2CA_DisconnectCfm_Cb = NULL;
+ gap_cb.conn.reg_info.pL2CA_QoSViolationInd_Cb = NULL;
+ gap_cb.conn.reg_info.pL2CA_DataInd_Cb = gap_data_ind;
+ gap_cb.conn.reg_info.pL2CA_CongestionStatus_Cb = gap_congestion_ind;
+ gap_cb.conn.reg_info.pL2CA_TxComplete_Cb = NULL;
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function GAP_ConnOpen
+**
+** Description This function is called to open an L2CAP connection.
+**
+** Parameters: is_server - If TRUE, the connection is not created
+** but put into a "listen" mode waiting for
+** the remote side to connect.
+**
+** service_id - Unique service ID from
+** BTM_SEC_SERVICE_FIRST_EMPTY (6)
+** to BTM_SEC_MAX_SERVICE_RECORDS (32)
+**
+** p_rem_bda - Pointer to remote BD Address.
+** If a server, and we don't care about the
+** remote BD Address, then NULL should be passed.
+**
+** psm - the PSM used for the connection
+**
+** p_config - Optional pointer to configuration structure.
+** If NULL, the default GAP configuration will
+** be used.
+**
+** security - security flags
+** chan_mode_mask - (GAP_FCR_CHAN_OPT_BASIC, GAP_FCR_CHAN_OPT_ERTM,
+** GAP_FCR_CHAN_OPT_STREAM)
+**
+** p_cb - Pointer to callback function for events.
+**
+** Returns handle of the connection if successful, else GAP_INVALID_HANDLE
+**
+*******************************************************************************/
+UINT16 GAP_ConnOpen (const char *p_serv_name, UINT8 service_id, BOOLEAN is_server,
+ BD_ADDR p_rem_bda, UINT16 psm, tL2CAP_CFG_INFO *p_cfg,
+ tL2CAP_ERTM_INFO *ertm_info, UINT16 security, UINT8 chan_mode_mask,
+ tGAP_CONN_CALLBACK *p_cb)
+{
+ tGAP_CCB *p_ccb;
+ UINT16 cid;
+ //tBT_UUID bt_uuid = {2, {GAP_PROTOCOL_ID}};
+
+ GAP_TRACE_EVENT ("GAP_CONN - Open Request");
+
+ /* Allocate a new CCB. Return if none available. */
+ if ((p_ccb = gap_allocate_ccb()) == NULL) {
+ return (GAP_INVALID_HANDLE);
+ }
+
+ /* If caller specified a BD address, save it */
+ if (p_rem_bda) {
+ /* the bd addr is not BT_BD_ANY, then a bd address was specified */
+ if (memcmp (p_rem_bda, BT_BD_ANY, BD_ADDR_LEN)) {
+ p_ccb->rem_addr_specified = TRUE;
+ }
+
+ memcpy (&p_ccb->rem_dev_address[0], p_rem_bda, BD_ADDR_LEN);
+ } else if (!is_server) {
+ /* remore addr is not specified and is not a server -> bad */
+ return (GAP_INVALID_HANDLE);
+ }
+
+ /* A client MUST have specified a bd addr to connect with */
+ if (!p_ccb->rem_addr_specified && !is_server) {
+ gap_release_ccb (p_ccb);
+ GAP_TRACE_ERROR ("GAP ERROR: Client must specify a remote BD ADDR to connect to!");
+ return (GAP_INVALID_HANDLE);
+ }
+
+ /* Check if configuration was specified */
+ if (p_cfg) {
+ p_ccb->cfg = *p_cfg;
+ }
+
+ p_ccb->p_callback = p_cb;
+
+ /* If originator, use a dynamic PSM */
+#if ((defined AMP_INCLUDED) && (AMP_INCLUDED == TRUE))
+ if (!is_server) {
+ gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = NULL;
+ } else {
+ gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = gap_connect_ind;
+ }
+#else
+ if (!is_server) {
+ gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = NULL;
+ } else {
+ gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind;
+ }
+#endif
+
+ /* Register the PSM with L2CAP */
+ if ((p_ccb->psm = L2CA_REGISTER (psm, &gap_cb.conn.reg_info,
+ AMP_AUTOSWITCH_ALLOWED | AMP_USE_AMP_IF_POSSIBLE)) == 0) {
+ GAP_TRACE_ERROR ("GAP_ConnOpen: Failure registering PSM 0x%04x", psm);
+ gap_release_ccb (p_ccb);
+ return (GAP_INVALID_HANDLE);
+ }
+
+ /* Register with Security Manager for the specific security level */
+ p_ccb->service_id = service_id;
+ if (!BTM_SetSecurityLevel ((UINT8)!is_server, p_serv_name,
+ p_ccb->service_id, security, p_ccb->psm, 0, 0)) {
+ GAP_TRACE_ERROR ("GAP_CONN - Security Error");
+ gap_release_ccb (p_ccb);
+ return (GAP_INVALID_HANDLE);
+ }
+
+ /* Fill in eL2CAP parameter data */
+ if ( p_ccb->cfg.fcr_present ) {
+ if (ertm_info == NULL) {
+ p_ccb->ertm_info.preferred_mode = p_ccb->cfg.fcr.mode;
+ p_ccb->ertm_info.user_rx_buf_size = GAP_DATA_BUF_SIZE;
+ p_ccb->ertm_info.user_tx_buf_size = GAP_DATA_BUF_SIZE;
+ p_ccb->ertm_info.fcr_rx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
+ p_ccb->ertm_info.fcr_tx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
+ } else {
+ p_ccb->ertm_info = *ertm_info;
+ }
+ }
+
+ /* optional FCR channel modes */
+ if (ertm_info != NULL) {
+ p_ccb->ertm_info.allowed_modes =
+ (chan_mode_mask) ? chan_mode_mask : (UINT8)L2CAP_FCR_CHAN_OPT_BASIC;
+ }
+
+ if (is_server) {
+ p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE; /* assume btm/l2cap would handle it */
+ p_ccb->con_state = GAP_CCB_STATE_LISTENING;
+ return (p_ccb->gap_handle);
+ } else {
+ /* We are the originator of this connection */
+ p_ccb->con_flags = GAP_CCB_FLAGS_IS_ORIG;
+
+ /* Transition to the next appropriate state, waiting for connection confirm. */
+ p_ccb->con_state = GAP_CCB_STATE_CONN_SETUP;
+
+ /* mark security done flag, when security is not required */
+ if ((security & (BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT) ) == 0) {
+ p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE;
+ }
+
+ /* Check if L2CAP started the connection process */
+ if (p_rem_bda && ((cid = L2CA_CONNECT_REQ (p_ccb->psm, p_rem_bda, &p_ccb->ertm_info, &bt_uuid)) != 0)) {
+ p_ccb->connection_id = cid;
+ return (p_ccb->gap_handle);
+ } else {
+ gap_release_ccb (p_ccb);
+ return (GAP_INVALID_HANDLE);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function GAP_ConnClose
+**
+** Description This function is called to close a connection.
+**
+** Parameters: handle - Handle of the connection returned by GAP_ConnOpen
+**
+** Returns BT_PASS - closed OK
+** GAP_ERR_BAD_HANDLE - invalid handle
+**
+*******************************************************************************/
+UINT16 GAP_ConnClose (UINT16 gap_handle)
+{
+ tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle);
+
+ GAP_TRACE_EVENT ("GAP_CONN - close handle: 0x%x", gap_handle);
+
+ if (p_ccb) {
+ /* Check if we have a connection ID */
+ if (p_ccb->con_state != GAP_CCB_STATE_LISTENING) {
+ L2CA_DISCONNECT_REQ (p_ccb->connection_id);
+ }
+
+ gap_release_ccb (p_ccb);
+
+ return (BT_PASS);
+ }
+
+ return (GAP_ERR_BAD_HANDLE);
+}
+
+
+
+/*******************************************************************************
+**
+** Function GAP_ConnReadData
+**
+** Description Normally not GKI aware application will call this function
+** after receiving GAP_EVT_RXDATA event.
+**
+** Parameters: handle - Handle of the connection returned in the Open
+** p_data - Data area
+** max_len - Byte count requested
+** p_len - Byte count received
+**
+** Returns BT_PASS - data read
+** GAP_ERR_BAD_HANDLE - invalid handle
+** GAP_NO_DATA_AVAIL - no data available
+**
+*******************************************************************************/
+UINT16 GAP_ConnReadData (UINT16 gap_handle, UINT8 *p_data, UINT16 max_len, UINT16 *p_len)
+{
+ tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle);
+ UINT16 copy_len;
+
+ if (!p_ccb) {
+ return (GAP_ERR_BAD_HANDLE);
+ }
+
+ *p_len = 0;
+
+ if (fixed_queue_is_empty(p_ccb->rx_queue)) {
+ return (GAP_NO_DATA_AVAIL);
+ }
+
+ osi_mutex_global_lock();
+
+ while (max_len) {
+ BT_HDR *p_buf = fixed_queue_try_peek_first(p_ccb->rx_queue);
+ if (p_buf == NULL) {
+ break;
+ }
+
+ copy_len = (p_buf->len > max_len)?max_len:p_buf->len;
+ max_len -= copy_len;
+ *p_len += copy_len;
+ if (p_data) {
+ memcpy (p_data, (UINT8 *)(p_buf + 1) + p_buf->offset, copy_len);
+ p_data += copy_len;
+ }
+
+ if (p_buf->len > copy_len) {
+ p_buf->offset += copy_len;
+ p_buf->len -= copy_len;
+ break;
+ }
+ osi_free(fixed_queue_dequeue(p_ccb->rx_queue, 0));
+ }
+
+ p_ccb->rx_queue_size -= *p_len;
+
+ osi_mutex_global_unlock();
+
+ GAP_TRACE_EVENT ("GAP_ConnReadData - rx_queue_size left=%d, *p_len=%d",
+ p_ccb->rx_queue_size, *p_len);
+
+ return (BT_PASS);
+}
+
+/*******************************************************************************
+**
+** Function GAP_GetRxQueueCnt
+**
+** Description This function return number of bytes on the rx queue.
+**
+** Parameters: handle - Handle returned in the GAP_ConnOpen
+** p_rx_queue_count - Pointer to return queue count in.
+**
+**
+*******************************************************************************/
+int GAP_GetRxQueueCnt (UINT16 handle, UINT32 *p_rx_queue_count)
+{
+ tGAP_CCB *p_ccb;
+ int rc = BT_PASS;
+
+ /* Check that handle is valid */
+ if (handle < GAP_MAX_CONNECTIONS) {
+ p_ccb = &gap_cb.conn.ccb_pool[handle];
+
+ if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) {
+ *p_rx_queue_count = p_ccb->rx_queue_size;
+ } else {
+ rc = GAP_INVALID_HANDLE;
+ }
+ } else {
+ rc = GAP_INVALID_HANDLE;
+ }
+
+ GAP_TRACE_EVENT ("GAP_GetRxQueueCnt - rc = 0x%04x, rx_queue_count=%d",
+ rc , *p_rx_queue_count);
+
+ return (rc);
+}
+
+/*******************************************************************************
+**
+** Function GAP_ConnBTRead
+**
+** Description Bluetooth aware applications will call this function after receiving
+** GAP_EVT_RXDATA event.
+**
+** Parameters: handle - Handle of the connection returned in the Open
+** pp_buf - pointer to address of buffer with data,
+**
+** Returns BT_PASS - data read
+** GAP_ERR_BAD_HANDLE - invalid handle
+** GAP_NO_DATA_AVAIL - no data available
+**
+*******************************************************************************/
+UINT16 GAP_ConnBTRead (UINT16 gap_handle, BT_HDR **pp_buf)
+{
+ tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle);
+ BT_HDR *p_buf;
+
+ if (!p_ccb) {
+ return (GAP_ERR_BAD_HANDLE);
+ }
+
+ p_buf = (BT_HDR *)fixed_queue_dequeue(p_ccb->rx_queue, 0);
+
+ if (p_buf) {
+ *pp_buf = p_buf;
+
+ p_ccb->rx_queue_size -= p_buf->len;
+ return (BT_PASS);
+ } else {
+ *pp_buf = NULL;
+ return (GAP_NO_DATA_AVAIL);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function GAP_ConnBTWrite
+**
+** Description Bluetooth Aware applications can call this function to write data.
+**
+** Parameters: handle - Handle of the connection returned in the Open
+** p_buf - pointer to address of buffer with data,
+**
+** Returns BT_PASS - data read
+** GAP_ERR_BAD_HANDLE - invalid handle
+** GAP_ERR_BAD_STATE - connection not established
+** GAP_INVALID_BUF_OFFSET - buffer offset is invalid
+*******************************************************************************/
+UINT16 GAP_ConnBTWrite (UINT16 gap_handle, BT_HDR *p_buf)
+{
+ tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle);
+
+ if (!p_ccb) {
+ osi_free (p_buf);
+ return (GAP_ERR_BAD_HANDLE);
+ }
+
+ if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED) {
+ osi_free (p_buf);
+ return (GAP_ERR_BAD_STATE);
+ }
+
+ if (p_buf->offset < L2CAP_MIN_OFFSET) {
+ osi_free (p_buf);
+ return (GAP_ERR_BUF_OFFSET);
+ }
+
+ fixed_queue_enqueue(p_ccb->tx_queue, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
+
+ if (p_ccb->is_congested) {
+ return (BT_PASS);
+ }
+
+ /* Send the buffer through L2CAP */
+#if (GAP_CONN_POST_EVT_INCLUDED == TRUE)
+ gap_send_event (gap_handle);
+#else
+ while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_ccb->tx_queue, 0)) != NULL) {
+ UINT8 status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf);
+
+ if (status == L2CAP_DW_CONGESTED) {
+ p_ccb->is_congested = TRUE;
+ break;
+ } else if (status != L2CAP_DW_SUCCESS) {
+ return (GAP_ERR_BAD_STATE);
+ }
+ }
+#endif
+ return (BT_PASS);
+}
+
+
+/*******************************************************************************
+**
+** Function GAP_ConnWriteData
+**
+** Description Normally not GKI aware application will call this function
+** to send data to the connection.
+**
+** Parameters: handle - Handle of the connection returned in the Open
+** p_data - Data area
+** max_len - Byte count requested
+** p_len - Byte count received
+**
+** Returns BT_PASS - data read
+** GAP_ERR_BAD_HANDLE - invalid handle
+** GAP_ERR_BAD_STATE - connection not established
+** GAP_CONGESTION - system is congested
+**
+*******************************************************************************/
+UINT16 GAP_ConnWriteData (UINT16 gap_handle, UINT8 *p_data, UINT16 max_len, UINT16 *p_len)
+{
+ tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle);
+ BT_HDR *p_buf;
+
+ *p_len = 0;
+
+ if (!p_ccb) {
+ return (GAP_ERR_BAD_HANDLE);
+ }
+
+ if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED) {
+ return (GAP_ERR_BAD_STATE);
+ }
+
+ while (max_len) {
+ if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
+ if ((p_buf = (BT_HDR *)osi_malloc(L2CAP_FCR_ERTM_BUF_SIZE)) == NULL) {
+ return (GAP_ERR_CONGESTED);
+ }
+ } else {
+ if ((p_buf = (BT_HDR *)osi_malloc(GAP_DATA_BUF_SIZE)) == NULL) {
+ return (GAP_ERR_CONGESTED);
+ }
+ }
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = (p_ccb->rem_mtu_size < max_len) ? p_ccb->rem_mtu_size : max_len;
+ p_buf->event = BT_EVT_TO_BTU_SP_DATA;
+
+ memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, p_buf->len);
+
+ *p_len += p_buf->len;
+ max_len -= p_buf->len;
+ p_data += p_buf->len;
+
+ GAP_TRACE_EVENT ("GAP_WriteData %d bytes", p_buf->len);
+
+ fixed_queue_enqueue(p_ccb->tx_queue, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
+ }
+
+ if (p_ccb->is_congested) {
+ return (BT_PASS);
+ }
+
+ /* Send the buffer through L2CAP */
+#if (GAP_CONN_POST_EVT_INCLUDED == TRUE)
+ gap_send_event (gap_handle);
+#else
+ while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_ccb->tx_queue, 0)) != NULL)
+ {
+ UINT8 status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf);
+
+ if (status == L2CAP_DW_CONGESTED) {
+ p_ccb->is_congested = TRUE;
+ break;
+ } else if (status != L2CAP_DW_SUCCESS) {
+ return (GAP_ERR_BAD_STATE);
+ }
+ }
+#endif
+ return (BT_PASS);
+}
+
+/*******************************************************************************
+**
+** Function GAP_ConnReconfig
+**
+** Description Applications can call this function to reconfigure the connection.
+**
+** Parameters: handle - Handle of the connection
+** p_cfg - Pointer to new configuration
+**
+** Returns BT_PASS - config process started
+** GAP_ERR_BAD_HANDLE - invalid handle
+**
+*******************************************************************************/
+UINT16 GAP_ConnReconfig (UINT16 gap_handle, tL2CAP_CFG_INFO *p_cfg)
+{
+ tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle);
+
+ if (!p_ccb) {
+ return (GAP_ERR_BAD_HANDLE);
+ }
+
+ p_ccb->cfg = *p_cfg;
+
+ if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) {
+ L2CA_CONFIG_REQ (p_ccb->connection_id, p_cfg);
+ }
+
+ return (BT_PASS);
+}
+
+
+
+/*******************************************************************************
+**
+** Function GAP_ConnSetIdleTimeout
+**
+** Description Higher layers call this function to set the idle timeout for
+** a connection, or for all future connections. The "idle timeout"
+** is the amount of time that a connection can remain up with
+** no L2CAP channels on it. A timeout of zero means that the
+** connection will be torn down immediately when the last channel
+** is removed. A timeout of 0xFFFF means no timeout. Values are
+** in seconds.
+**
+** Parameters: handle - Handle of the connection
+** timeout - in secs
+** 0 = immediate disconnect when last channel is removed
+** 0xFFFF = no idle timeout
+**
+** Returns BT_PASS - config process started
+** GAP_ERR_BAD_HANDLE - invalid handle
+**
+*******************************************************************************/
+UINT16 GAP_ConnSetIdleTimeout (UINT16 gap_handle, UINT16 timeout)
+{
+ tGAP_CCB *p_ccb;
+
+ if ((p_ccb = gap_find_ccb_by_handle (gap_handle)) == NULL) {
+ return (GAP_ERR_BAD_HANDLE);
+ }
+
+ if (L2CA_SetIdleTimeout (p_ccb->connection_id, timeout, FALSE)) {
+ return (BT_PASS);
+ } else {
+ return (GAP_ERR_BAD_HANDLE);
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function GAP_ConnGetRemoteAddr
+**
+** Description This function is called to get the remote BD address
+** of a connection.
+**
+** Parameters: handle - Handle of the connection returned by GAP_ConnOpen
+**
+** Returns BT_PASS - closed OK
+** GAP_ERR_BAD_HANDLE - invalid handle
+**
+*******************************************************************************/
+UINT8 *GAP_ConnGetRemoteAddr (UINT16 gap_handle)
+{
+ tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle);
+
+ GAP_TRACE_EVENT ("GAP_ConnGetRemoteAddr gap_handle = %d", gap_handle);
+
+ if ((p_ccb) && (p_ccb->con_state > GAP_CCB_STATE_LISTENING)) {
+ GAP_TRACE_EVENT("GAP_ConnGetRemoteAddr bda :0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", \
+ p_ccb->rem_dev_address[0], p_ccb->rem_dev_address[1], p_ccb->rem_dev_address[2],
+ p_ccb->rem_dev_address[3], p_ccb->rem_dev_address[4], p_ccb->rem_dev_address[5]);
+ return (p_ccb->rem_dev_address);
+ } else {
+ GAP_TRACE_EVENT ("GAP_ConnGetRemoteAddr return Error ");
+ return (NULL);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function GAP_ConnGetRemMtuSize
+**
+** Description Returns the remote device's MTU size
+**
+** Parameters: handle - Handle of the connection
+**
+** Returns UINT16 - maximum size buffer that can be transmitted to the peer
+**
+*******************************************************************************/
+UINT16 GAP_ConnGetRemMtuSize (UINT16 gap_handle)
+{
+ tGAP_CCB *p_ccb;
+
+ if ((p_ccb = gap_find_ccb_by_handle (gap_handle)) == NULL) {
+ return (0);
+ }
+
+ return (p_ccb->rem_mtu_size);
+}
+
+/*******************************************************************************
+**
+** Function GAP_ConnGetL2CAPCid
+**
+** Description Returns the L2CAP channel id
+**
+** Parameters: handle - Handle of the connection
+**
+** Returns UINT16 - The L2CAP channel id
+** 0, if error
+**
+*******************************************************************************/
+UINT16 GAP_ConnGetL2CAPCid (UINT16 gap_handle)
+{
+ tGAP_CCB *p_ccb;
+
+ if ((p_ccb = gap_find_ccb_by_handle (gap_handle)) == NULL) {
+ return (0);
+ }
+
+ return (p_ccb->connection_id);
+}
+
+
+/*******************************************************************************
+**
+** Function gap_connect_ind
+**
+** Description This function handles an inbound connection indication
+** from L2CAP. This is the case where we are acting as a
+** server.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id)
+{
+ UINT16 xx;
+ tGAP_CCB *p_ccb;
+ //tBT_UUID bt_uuid = {2, {GAP_PROTOCOL_ID}};
+
+ /* See if we have a CCB listening for the connection */
+ for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++) {
+ if ((p_ccb->con_state == GAP_CCB_STATE_LISTENING)
+ && (p_ccb->psm == psm)
+ && ((p_ccb->rem_addr_specified == FALSE)
+ || (!memcmp (bd_addr, p_ccb->rem_dev_address, BD_ADDR_LEN)))) {
+ break;
+ }
+ }
+
+ if (xx == GAP_MAX_CONNECTIONS) {
+ GAP_TRACE_WARNING("*******");
+ GAP_TRACE_WARNING("WARNING: GAP Conn Indication for Unexpected Bd Addr...Disconnecting");
+ GAP_TRACE_WARNING("*******");
+
+ /* Disconnect because it is an unexpected connection */
+ L2CA_DISCONNECT_REQ (l2cap_cid);
+ return;
+ }
+
+ /* Transition to the next appropriate state, waiting for config setup. */
+ p_ccb->con_state = GAP_CCB_STATE_CFG_SETUP;
+
+ /* Save the BD Address and Channel ID. */
+ memcpy (&p_ccb->rem_dev_address[0], bd_addr, BD_ADDR_LEN);
+ p_ccb->connection_id = l2cap_cid;
+
+ /* Send response to the L2CAP layer. */
+ L2CA_CONNECT_RSP (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK, &p_ccb->ertm_info, &bt_uuid);
+
+ GAP_TRACE_EVENT("GAP_CONN - Rcvd L2CAP conn ind, CID: 0x%x", p_ccb->connection_id);
+
+ /* Send a Configuration Request. */
+ L2CA_CONFIG_REQ (l2cap_cid, &p_ccb->cfg);
+}
+
+/*******************************************************************************
+**
+** Function gap_checks_con_flags
+**
+** Description This function processes the L2CAP configuration indication
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_checks_con_flags (tGAP_CCB *p_ccb)
+{
+ GAP_TRACE_EVENT ("gap_checks_con_flags conn_flags:0x%x, ", p_ccb->con_flags);
+ /* if all the required con_flags are set, report the OPEN event now */
+ if ((p_ccb->con_flags & GAP_CCB_FLAGS_CONN_DONE) == GAP_CCB_FLAGS_CONN_DONE) {
+ p_ccb->con_state = GAP_CCB_STATE_CONNECTED;
+
+ p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_OPENED);
+ }
+}
+
+/*******************************************************************************
+**
+** Function gap_sec_check_complete
+**
+** Description The function called when Security Manager finishes
+** verification of the service side connection
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_sec_check_complete (BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, UINT8 res)
+{
+ tGAP_CCB *p_ccb = (tGAP_CCB *)p_ref_data;
+ UNUSED(bd_addr);
+ UNUSED (transport);
+
+ GAP_TRACE_EVENT ("gap_sec_check_complete conn_state:%d, conn_flags:0x%x, status:%d",
+ p_ccb->con_state, p_ccb->con_flags, res);
+ if (p_ccb->con_state == GAP_CCB_STATE_IDLE) {
+ return;
+ }
+
+ if (res == BTM_SUCCESS) {
+ p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE;
+ gap_checks_con_flags (p_ccb);
+ } else {
+ /* security failed - disconnect the channel */
+ L2CA_DISCONNECT_REQ (p_ccb->connection_id);
+ }
+}
+
+/*******************************************************************************
+**
+** Function gap_connect_cfm
+**
+** Description This function handles the connect confirm events
+** from L2CAP. This is the case when we are acting as a
+** client and have sent a connect request.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_connect_cfm (UINT16 l2cap_cid, UINT16 result)
+{
+ tGAP_CCB *p_ccb;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL) {
+ return;
+ }
+
+ /* initiate security process, if needed */
+ if ( (p_ccb->con_flags & GAP_CCB_FLAGS_SEC_DONE) == 0) {
+ btm_sec_mx_access_request (p_ccb->rem_dev_address, p_ccb->psm, TRUE,
+ 0, 0, &gap_sec_check_complete, p_ccb);
+ }
+
+ /* If the connection response contains success status, then */
+ /* Transition to the next state and startup the timer. */
+ if ((result == L2CAP_CONN_OK) && (p_ccb->con_state == GAP_CCB_STATE_CONN_SETUP)) {
+ p_ccb->con_state = GAP_CCB_STATE_CFG_SETUP;
+
+ /* Send a Configuration Request. */
+ L2CA_CONFIG_REQ (l2cap_cid, &p_ccb->cfg);
+ } else {
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_callback) {
+ (*p_ccb->p_callback) (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
+ }
+
+ gap_release_ccb (p_ccb);
+ }
+}
+
+/*******************************************************************************
+**
+** Function gap_config_ind
+**
+** Description This function processes the L2CAP configuration indication
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tGAP_CCB *p_ccb;
+ UINT16 local_mtu_size;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL) {
+ return;
+ }
+
+ /* Remember the remote MTU size */
+
+ if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
+ local_mtu_size = p_ccb->ertm_info.user_tx_buf_size
+ - sizeof(BT_HDR) - L2CAP_MIN_OFFSET;
+ } else {
+ local_mtu_size = L2CAP_MTU_SIZE;
+ }
+
+ if ((!p_cfg->mtu_present) || (p_cfg->mtu > local_mtu_size)) {
+ p_ccb->rem_mtu_size = local_mtu_size;
+ } else {
+ p_ccb->rem_mtu_size = p_cfg->mtu;
+ }
+
+ /* For now, always accept configuration from the other side */
+ p_cfg->flush_to_present = FALSE;
+ p_cfg->mtu_present = FALSE;
+ p_cfg->result = L2CAP_CFG_OK;
+ p_cfg->fcs_present = FALSE;
+
+ L2CA_CONFIG_RSP (l2cap_cid, p_cfg);
+
+ p_ccb->con_flags |= GAP_CCB_FLAGS_HIS_CFG_DONE;
+
+ gap_checks_con_flags (p_ccb);
+}
+
+
+/*******************************************************************************
+**
+** Function gap_config_cfm
+**
+** Description This function processes the L2CAP configuration confirmation
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ tGAP_CCB *p_ccb;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL) {
+ return;
+ }
+
+ if (p_cfg->result == L2CAP_CFG_OK) {
+ p_ccb->con_flags |= GAP_CCB_FLAGS_MY_CFG_DONE;
+
+
+ if (p_ccb->cfg.fcr_present) {
+ p_ccb->cfg.fcr.mode = p_cfg->fcr.mode;
+ } else {
+ p_ccb->cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+ }
+
+ gap_checks_con_flags (p_ccb);
+ } else {
+ p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
+ gap_release_ccb (p_ccb);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function gap_disconnect_ind
+**
+** Description This function handles a disconnect event from L2CAP. If
+** requested to, we ack the disconnect before dropping the CCB
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
+{
+ tGAP_CCB *p_ccb;
+
+ GAP_TRACE_EVENT ("GAP_CONN - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+
+ /* Find CCB based on CID */
+ if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL) {
+ return;
+ }
+
+ if (ack_needed) {
+ L2CA_DISCONNECT_RSP (l2cap_cid);
+ }
+
+ p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
+ gap_release_ccb (p_ccb);
+}
+
+
+/*******************************************************************************
+**
+** Function gap_data_ind
+**
+** Description This function is called when data is received from L2CAP.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
+{
+ tGAP_CCB *p_ccb;
+
+ /* Find CCB based on CID */
+ if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL) {
+ osi_free (p_msg);
+ return;
+ }
+
+ if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) {
+ fixed_queue_enqueue(p_ccb->rx_queue, p_msg, FIXED_QUEUE_MAX_TIMEOUT);
+
+ p_ccb->rx_queue_size += p_msg->len;
+ /*
+ GAP_TRACE_EVENT ("gap_data_ind - rx_queue_size=%d, msg len=%d",
+ p_ccb->rx_queue_size, p_msg->len);
+ */
+
+ p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_DATA_AVAIL);
+ } else {
+ osi_free (p_msg);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function gap_congestion_ind
+**
+** Description This is a callback function called by L2CAP when
+** data L2CAP congestion status changes
+**
+*******************************************************************************/
+static void gap_congestion_ind (UINT16 lcid, BOOLEAN is_congested)
+{
+ tGAP_CCB *p_ccb;
+ UINT16 event;
+ BT_HDR *p_buf;
+ UINT8 status;
+
+ GAP_TRACE_EVENT ("GAP_CONN - Rcvd L2CAP Is Congested (%d), CID: 0x%x",
+ is_congested, lcid);
+
+ /* Find CCB based on CID */
+ if ((p_ccb = gap_find_ccb_by_cid (lcid)) == NULL) {
+ return;
+ }
+
+ p_ccb->is_congested = is_congested;
+
+ event = (is_congested) ? GAP_EVT_CONN_CONGESTED : GAP_EVT_CONN_UNCONGESTED;
+ p_ccb->p_callback (p_ccb->gap_handle, event);
+
+ if (!is_congested) {
+ while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_ccb->tx_queue, 0)) != NULL) {
+ status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf);
+
+ if (status == L2CAP_DW_CONGESTED) {
+ p_ccb->is_congested = TRUE;
+ break;
+ } else if (status != L2CAP_DW_SUCCESS) {
+ break;
+ }
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function gap_find_ccb_by_cid
+**
+** Description This function searches the CCB table for an entry with the
+** passed CID.
+**
+** Returns the CCB address, or NULL if not found.
+**
+*******************************************************************************/
+static tGAP_CCB *gap_find_ccb_by_cid (UINT16 cid)
+{
+ UINT16 xx;
+ tGAP_CCB *p_ccb;
+
+ /* Look through each connection control block */
+ for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++) {
+ if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) && (p_ccb->connection_id == cid)) {
+ return (p_ccb);
+ }
+ }
+
+ /* If here, not found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function gap_find_ccb_by_handle
+**
+** Description This function searches the CCB table for an entry with the
+** passed handle.
+**
+** Returns the CCB address, or NULL if not found.
+**
+*******************************************************************************/
+static tGAP_CCB *gap_find_ccb_by_handle (UINT16 handle)
+{
+ tGAP_CCB *p_ccb;
+
+ /* Check that handle is valid */
+ if (handle < GAP_MAX_CONNECTIONS) {
+ p_ccb = &gap_cb.conn.ccb_pool[handle];
+
+ if (p_ccb->con_state != GAP_CCB_STATE_IDLE) {
+ return (p_ccb);
+ }
+ }
+
+ /* If here, handle points to invalid connection */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function gap_allocate_ccb
+**
+** Description This function allocates a new CCB.
+**
+** Returns CCB address, or NULL if none available.
+**
+*******************************************************************************/
+static tGAP_CCB *gap_allocate_ccb (void)
+{
+ UINT16 xx;
+ tGAP_CCB *p_ccb;
+
+ /* Look through each connection control block for a free one */
+ for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++) {
+ if (p_ccb->con_state == GAP_CCB_STATE_IDLE) {
+ memset (p_ccb, 0, sizeof (tGAP_CCB));
+ p_ccb->tx_queue = fixed_queue_new(QUEUE_SIZE_MAX);
+ p_ccb->rx_queue = fixed_queue_new(QUEUE_SIZE_MAX);
+
+ p_ccb->gap_handle = xx;
+ p_ccb->rem_mtu_size = L2CAP_MTU_SIZE;
+
+ return (p_ccb);
+ }
+ }
+
+ /* If here, no free CCB found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function gap_release_ccb
+**
+** Description This function releases a CCB.
+**
+** Returns void
+**
+*******************************************************************************/
+static void gap_release_ccb (tGAP_CCB *p_ccb)
+{
+ UINT16 xx;
+ UINT16 psm = p_ccb->psm;
+ UINT8 service_id = p_ccb->service_id;
+
+ /* Drop any buffers we may be holding */
+ p_ccb->rx_queue_size = 0;
+
+ while (!fixed_queue_is_empty(p_ccb->rx_queue)) {
+ osi_free(fixed_queue_dequeue(p_ccb->rx_queue, 0));
+ }
+ fixed_queue_free(p_ccb->rx_queue, NULL);
+ p_ccb->rx_queue = NULL;
+
+ while (!fixed_queue_is_empty(p_ccb->tx_queue)) {
+ osi_free(fixed_queue_dequeue(p_ccb->tx_queue, 0));
+ }
+ fixed_queue_free(p_ccb->tx_queue, NULL);
+ p_ccb->tx_queue = NULL;
+
+ p_ccb->con_state = GAP_CCB_STATE_IDLE;
+
+ /* If no-one else is using the PSM, deregister from L2CAP */
+ for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++) {
+ if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) && (p_ccb->psm == psm)) {
+ return;
+ }
+ }
+#if (SDP_INCLUDED == TRUE)
+ /* Free the security record for this PSM */
+ BTM_SecClrService(service_id);
+#endif ///SDP_INCLUDED == TRUE
+ L2CA_DEREGISTER (psm);
+}
+
+#if (GAP_CONN_POST_EVT_INCLUDED == TRUE)
+
+/*******************************************************************************
+**
+** Function gap_send_event
+**
+** Description Send BT_EVT_TO_GAP_MSG event to BTU task
+**
+** Returns None
+**
+*******************************************************************************/
+void gap_send_event (UINT16 gap_handle)
+{
+ BT_HDR *p_msg;
+
+ if ((p_msg = (BT_HDR *)osi_malloc(BT_HDR_SIZE)) != NULL) {
+ p_msg->event = BT_EVT_TO_GAP_MSG;
+ p_msg->len = 0;
+ p_msg->offset = 0;
+ p_msg->layer_specific = gap_handle;
+
+ GKI_send_msg(BTU_TASK, BTU_HCI_RCV_MBOX, p_msg);
+ } else {
+ GAP_TRACE_ERROR("Unable to allocate message buffer for event.");
+ }
+}
+
+#endif /* (GAP_CONN_POST_EVT_INCLUDED == TRUE) */
+#endif /* GAP_CONN_INCLUDED */
diff --git a/lib/bt/host/bluedroid/stack/gap/gap_utils.c b/lib/bt/host/bluedroid/stack/gap/gap_utils.c
new file mode 100644
index 00000000..b358021a
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/gap/gap_utils.c
@@ -0,0 +1,141 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "common/bt_target.h"
+//#include "bt_utils.h"
+#include "gap_int.h"
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function gap_allocate_cb
+**
+** Description Look through the GAP Control Blocks for a free one.
+**
+** Returns Pointer to the control block or NULL if not found
+**
+*******************************************************************************/
+tGAP_INFO *gap_allocate_cb (void)
+{
+ tGAP_INFO *p_cb = &gap_cb.blk[0];
+ UINT8 x;
+
+ for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++) {
+ if (!p_cb->in_use) {
+ memset (p_cb, 0, sizeof (tGAP_INFO));
+
+ p_cb->in_use = TRUE;
+ p_cb->index = x;
+ p_cb->p_data = (void *)NULL;
+ return (p_cb);
+ }
+ }
+
+ /* If here, no free control blocks found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function gap_free_cb
+**
+** Description Release GAP control block.
+**
+** Returns Pointer to the control block or NULL if not found
+**
+*******************************************************************************/
+void gap_free_cb (tGAP_INFO *p_cb)
+{
+ if (p_cb) {
+ p_cb->gap_cback = NULL;
+ p_cb->in_use = FALSE;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function gap_is_service_busy
+**
+** Description Look through the GAP Control Blocks that are in use
+** and check to see if the event waiting for is the command
+** requested.
+**
+** Returns TRUE if already in use
+** FALSE if not busy
+**
+*******************************************************************************/
+BOOLEAN gap_is_service_busy (UINT16 request)
+{
+ tGAP_INFO *p_cb = &gap_cb.blk[0];
+ UINT8 x;
+
+ for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++) {
+ if (p_cb->in_use && p_cb->event == request) {
+ return (TRUE);
+ }
+ }
+
+ /* If here, service is not busy */
+ return (FALSE);
+}
+
+
+/*******************************************************************************
+**
+** Function gap_convert_btm_status
+**
+** Description Converts a BTM error status into a GAP error status
+**
+**
+** Returns GAP_UNKNOWN_BTM_STATUS is returned if not recognized
+**
+*******************************************************************************/
+UINT16 gap_convert_btm_status (tBTM_STATUS btm_status)
+{
+ switch (btm_status) {
+ case BTM_SUCCESS:
+ return (BT_PASS);
+
+ case BTM_CMD_STARTED:
+ return (GAP_CMD_INITIATED);
+
+ case BTM_BUSY:
+ return (GAP_ERR_BUSY);
+
+ case BTM_MODE_UNSUPPORTED:
+ case BTM_ILLEGAL_VALUE:
+ return (GAP_ERR_ILL_PARM);
+
+ case BTM_WRONG_MODE:
+ return (GAP_DEVICE_NOT_UP);
+
+ case BTM_UNKNOWN_ADDR:
+ return (GAP_BAD_BD_ADDR);
+
+ case BTM_DEVICE_TIMEOUT:
+ return (GAP_ERR_TIMEOUT);
+
+ default:
+ return (GAP_ERR_PROCESSING);
+ }
+}
+
+#endif ///CLASSIC_BT_INCLUDED == TRUE
diff --git a/lib/bt/host/bluedroid/stack/gap/include/gap_int.h b/lib/bt/host/bluedroid/stack/gap/include/gap_int.h
new file mode 100644
index 00000000..8a3ae0e2
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/gap/include/gap_int.h
@@ -0,0 +1,159 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+
+#ifndef GAP_INT_H
+#define GAP_INT_H
+
+#include "common/bt_target.h"
+#include "osi/fixed_queue.h"
+#include "stack/gap_api.h"
+#include "stack/gatt_api.h"
+#define GAP_MAX_BLOCKS 2 /* Concurrent GAP commands pending at a time*/
+/* Define the Generic Access Profile control structure */
+typedef struct {
+ void *p_data; /* Pointer to any data returned in callback */
+ tGAP_CALLBACK *gap_cback; /* Pointer to users callback function */
+ tGAP_CALLBACK *gap_inq_rslt_cback; /* Used for inquiry results */
+ UINT16 event; /* Passed back in the callback */
+ UINT8 index; /* Index of this control block and callback */
+ BOOLEAN in_use; /* True when structure is allocated */
+} tGAP_INFO;
+
+/* Define the control block for the FindAddrByName operation (Only 1 active at a time) */
+typedef struct {
+ tGAP_CALLBACK *p_cback;
+ tBTM_INQ_INFO *p_cur_inq; /* Pointer to the current inquiry database entry */
+ tGAP_FINDADDR_RESULTS results;
+ BOOLEAN in_use;
+} tGAP_FINDADDR_CB;
+
+/* Define the GAP Connection Control Block.
+*/
+typedef struct {
+#define GAP_CCB_STATE_IDLE 0
+#define GAP_CCB_STATE_LISTENING 1
+#define GAP_CCB_STATE_CONN_SETUP 2
+#define GAP_CCB_STATE_CFG_SETUP 3
+#define GAP_CCB_STATE_WAIT_SEC 4
+#define GAP_CCB_STATE_CONNECTED 5
+ UINT8 con_state;
+
+#define GAP_CCB_FLAGS_IS_ORIG 0x01
+#define GAP_CCB_FLAGS_HIS_CFG_DONE 0x02
+#define GAP_CCB_FLAGS_MY_CFG_DONE 0x04
+#define GAP_CCB_FLAGS_SEC_DONE 0x08
+#define GAP_CCB_FLAGS_CONN_DONE 0x0E
+ UINT8 con_flags;
+
+ UINT8 service_id; /* Used by BTM */
+ UINT16 gap_handle; /* GAP handle */
+ UINT16 connection_id; /* L2CAP CID */
+ BOOLEAN rem_addr_specified;
+ UINT8 chan_mode_mask; /* Supported channel modes (FCR) */
+ BD_ADDR rem_dev_address;
+ UINT16 psm;
+ UINT16 rem_mtu_size;
+
+ BOOLEAN is_congested;
+ fixed_queue_t *tx_queue; /* Queue of buffers waiting to be sent */
+ fixed_queue_t *rx_queue; /* Queue of buffers waiting to be read */
+
+ UINT32 rx_queue_size; /* Total data count in rx_queue */
+
+ tGAP_CONN_CALLBACK *p_callback; /* Users callback function */
+
+ tL2CAP_CFG_INFO cfg; /* Configuration */
+ tL2CAP_ERTM_INFO ertm_info; /* Pools and modes for ertm */
+} tGAP_CCB;
+
+typedef struct {
+#if ((defined AMP_INCLUDED) && (AMP_INCLUDED == TRUE))
+ tAMP_APPL_INFO reg_info;
+#else
+ tL2CAP_APPL_INFO reg_info; /* L2CAP Registration info */
+#endif
+ tGAP_CCB ccb_pool[GAP_MAX_CONNECTIONS];
+} tGAP_CONN;
+
+
+#if BLE_INCLUDED == TRUE
+#define GAP_MAX_CHAR_NUM 4
+
+typedef struct {
+ UINT16 handle;
+ UINT16 uuid;
+ tGAP_BLE_ATTR_VALUE attr_value;
+} tGAP_ATTR;
+#endif
+/**********************************************************************
+** M A I N C O N T R O L B L O C K
+***********************************************************************/
+
+#define GAP_MAX_CL GATT_CL_MAX_LCB
+
+typedef struct {
+ UINT16 uuid;
+ tGAP_BLE_CMPL_CBACK *p_cback;
+} tGAP_BLE_REQ;
+
+typedef struct {
+ BD_ADDR bda;
+ tGAP_BLE_CMPL_CBACK *p_cback;
+ UINT16 conn_id;
+ UINT16 cl_op_uuid;
+ BOOLEAN in_use;
+ BOOLEAN connected;
+ fixed_queue_t *pending_req_q;
+
+} tGAP_CLCB;
+
+typedef struct {
+ tGAP_INFO blk[GAP_MAX_BLOCKS];
+ tBTM_CMPL_CB *btm_cback[GAP_MAX_BLOCKS];
+ UINT8 trace_level;
+ //tGAP_FINDADDR_CB findaddr_cb; /* Contains the control block for finding a device addr */
+ //tBTM_INQ_INFO *cur_inqptr;
+
+#if GAP_CONN_INCLUDED == TRUE
+ tGAP_CONN conn;
+#endif
+
+ /* LE GAP attribute database */
+#if BLE_INCLUDED == TRUE && GATTS_INCLUDED == TRUE
+ tGAP_ATTR gap_attr[GAP_MAX_CHAR_NUM];
+ tGAP_CLCB clcb[GAP_MAX_CL]; /* connection link*/
+ tGATT_IF gatt_if;
+#endif
+} tGAP_CB;
+
+#if GAP_DYNAMIC_MEMORY == FALSE
+extern tGAP_CB gap_cb;
+#else
+extern tGAP_CB *gap_cb_ptr;
+#define gap_cb (*gap_cb_ptr)
+#endif
+
+#if (GAP_CONN_INCLUDED == TRUE)
+extern void gap_conn_init(void);
+#endif
+#if (BLE_INCLUDED == TRUE && GATTS_INCLUDED == TRUE)
+extern void gap_attr_db_init(void);
+#endif
+
+#endif