summaryrefslogtreecommitdiff
path: root/lib/bt/host/bluedroid/stack/btm
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/btm
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/btm')
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_acl.c2757
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_ble.c2934
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c1455
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_ble_addr.c608
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c1306
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_ble_batchscan.c953
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_ble_bgconn.c836
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_ble_cont_energy.c108
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_ble_gap.c4724
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_ble_multi_adv.c878
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_ble_privacy.c1086
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_dev.c741
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_devctl.c1294
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_inq.c2973
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_main.c152
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_pm.c965
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_sco.c1907
-rw-r--r--lib/bt/host/bluedroid/stack/btm/btm_sec.c6382
-rw-r--r--lib/bt/host/bluedroid/stack/btm/include/btm_ble_int.h548
-rw-r--r--lib/bt/host/bluedroid/stack/btm/include/btm_int.h1258
20 files changed, 33865 insertions, 0 deletions
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_acl.c b/lib/bt/host/bluedroid/stack/btm/btm_acl.c
new file mode 100644
index 00000000..4b7e7eed
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_acl.c
@@ -0,0 +1,2757 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2000-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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+**
+** Name: btm_acl.c
+**
+** Description: This file contains functions that handle ACL connections.
+** This includes operations such as hold and sniff modes,
+** supported packet types.
+**
+** This module contains both internal and external (API)
+** functions. External (API) functions are distinguishable
+** by their names beginning with uppercase BTM.
+**
+**
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+//#include <stdio.h>
+#include <stddef.h>
+
+#include "stack/bt_types.h"
+#include "common/bt_target.h"
+#include "device/controller.h"
+#include "stack/hcimsgs.h"
+#include "stack/btu.h"
+#include "stack/btm_api.h"
+#include "btm_int.h"
+#include "stack/acl_hci_link_interface.h"
+#include "l2c_int.h"
+#include "stack/l2cap_hci_link_interface.h"
+#include "stack/hcidefs.h"
+//#include "bt_utils.h"
+#include "osi/list.h"
+
+static void btm_read_remote_features (UINT16 handle);
+static void btm_read_remote_ext_features (UINT16 handle, UINT8 page_number);
+static void btm_process_remote_ext_features (tACL_CONN *p_acl_cb, UINT8 num_read_pages);
+
+#define BTM_DEV_REPLY_TIMEOUT 3 /* 3 second timeout waiting for responses */
+
+/*******************************************************************************
+**
+** Function btm_acl_init
+**
+** Description This function is called at BTM startup to initialize
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_init (void)
+{
+ BTM_TRACE_DEBUG ("btm_acl_init\n");
+#if 0 /* cleared in btm_init; put back in if called from anywhere else! */
+ memset (&btm_cb.acl_db, 0, sizeof (btm_cb.acl_db));
+ memset (btm_cb.btm_scn, 0, BTM_MAX_SCN); /* Initialize the SCN usage to FALSE */
+ btm_cb.btm_def_link_policy = 0;
+ btm_cb.p_bl_changed_cb = NULL;
+#endif
+ btm_cb.p_acl_db_list = list_new(osi_free_func);
+ btm_cb.p_pm_mode_db_list = list_new(osi_free_func);
+
+ /* Initialize nonzero defaults */
+ btm_cb.btm_def_link_super_tout = HCI_DEFAULT_INACT_TOUT;
+ btm_cb.acl_disc_reason = 0xff ;
+}
+
+/*******************************************************************************
+**
+** Function btm_bda_to_acl
+**
+** Description This function returns the FIRST acl_db entry for the passed BDA.
+**
+** Parameters bda : BD address of the remote device
+** transport : Physical transport used for ACL connection (BR/EDR or LE)
+**
+** Returns Returns pointer to the ACL DB for the requested BDA if found.
+** NULL if not found.
+**
+*******************************************************************************/
+BOOLEAN btm_get_acl_db(void *p_acl_db_node, void *context)
+{
+ tACL_CONN *p_acl_db =(tACL_CONN *)p_acl_db_node;
+ BOOLEAN ret = TRUE;
+ tACL_DB_PARAM *p_param = (tACL_DB_PARAM *)context;
+ switch(p_param->type) {
+ case ACL_DB_BDA:
+ {
+ UINT8 *p_bda = (UINT8 *)p_param->p_data1;
+#if BLE_INCLUDED == TRUE
+ tBT_TRANSPORT transport = (tBT_TRANSPORT)(*((UINT8 *)p_param->p_data2));
+#endif
+ if (p_acl_db->in_use
+ && !memcmp(p_bda, p_acl_db->remote_addr, BD_ADDR_LEN)
+#if BLE_INCLUDED == TRUE
+ && transport == p_acl_db->transport
+#endif
+ ) {
+ ret = FALSE;
+ }
+ break;
+ }
+ case ACL_DB_HANDLE:
+ {
+ UINT16 handle = (UINT16) *((UINT16 *)p_param->p_data1);
+ if (p_acl_db->in_use && handle == p_acl_db->hci_handle) {
+ ret = FALSE;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return ret;
+}
+
+tACL_CONN *btm_bda_to_acl (BD_ADDR bda, tBT_TRANSPORT transport)
+{
+ tACL_CONN *p_acl_db = NULL;
+ list_node_t *p_node = NULL;
+ tACL_DB_PARAM acl_params;
+ acl_params.type = ACL_DB_BDA;
+ acl_params.p_data1 = (void *)bda;
+ acl_params.p_data2 = (void *)&transport;
+ p_node = list_foreach(btm_cb.p_acl_db_list, btm_get_acl_db, (void *)&acl_params);
+ if (p_node) {
+ p_acl_db = list_node(p_node);
+ }
+
+ return (p_acl_db);
+}
+
+/*******************************************************************************
+**
+** Function btm_handle_to_acl
+**
+** Description This function returns the FIRST acl_db entry for the passed hci_handle.
+**
+** Returns Returns pointer to the ACL DB for the requested BDA if found.
+** NULL if not found.
+**
+*******************************************************************************/
+tACL_CONN *btm_handle_to_acl (UINT16 hci_handle)
+{
+ tACL_CONN *p_acl_db = NULL;
+ tACL_DB_PARAM acl_params;
+ list_node_t *p_node = NULL;
+
+ BTM_TRACE_DEBUG ("btm_handle_to_acl_index: %d\n", hci_handle);
+
+ acl_params.type = ACL_DB_HANDLE;
+ acl_params.p_data1 = (void *)&hci_handle;
+ acl_params.p_data2 = NULL;
+ p_node = list_foreach(btm_cb.p_acl_db_list, btm_get_acl_db, (void *)&acl_params);
+ if (p_node) {
+ p_acl_db = list_node(p_node);
+ }
+
+ return (p_acl_db);
+}
+
+#if BLE_PRIVACY_SPT == TRUE
+/*******************************************************************************
+**
+** Function btm_ble_get_acl_remote_addr
+**
+** Description This function reads the active remote address used for the
+** connection.
+**
+** Returns success return TRUE, otherwise FALSE.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_get_acl_remote_addr(tBTM_SEC_DEV_REC *p_dev_rec, BD_ADDR conn_addr,
+ tBLE_ADDR_TYPE *p_addr_type)
+{
+#if BLE_INCLUDED == TRUE
+ BOOLEAN st = TRUE;
+
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR("btm_ble_get_acl_remote_addr can not find device with matching address\n");
+ return FALSE;
+ }
+
+ switch (p_dev_rec->ble.active_addr_type) {
+ case BTM_BLE_ADDR_PSEUDO:
+ memcpy(conn_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ * p_addr_type = p_dev_rec->ble.ble_addr_type;
+ break;
+
+ case BTM_BLE_ADDR_RRA:
+ memcpy(conn_addr, p_dev_rec->ble.cur_rand_addr, BD_ADDR_LEN);
+ * p_addr_type = BLE_ADDR_RANDOM;
+ break;
+
+ case BTM_BLE_ADDR_STATIC:
+ memcpy(conn_addr, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
+ * p_addr_type = p_dev_rec->ble.static_addr_type;
+ break;
+
+ default:
+ BTM_TRACE_ERROR("Unknown active address: %d\n", p_dev_rec->ble.active_addr_type);
+ st = FALSE;
+ break;
+ }
+
+ return st;
+#else
+ UNUSED(p_dev_rec);
+ UNUSED(conn_addr);
+ UNUSED(p_addr_type);
+ return FALSE;
+#endif
+}
+#endif
+/*******************************************************************************
+**
+** Function btm_acl_created
+**
+** Description This function is called by L2CAP when an ACL connection
+** is created.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, UINT8 bdn[BTM_MAX_REM_BD_NAME_LEN],
+ UINT16 hci_handle, UINT8 link_role, tBT_TRANSPORT transport)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+ tACL_CONN *p;
+
+ BTM_TRACE_DEBUG ("btm_acl_created hci_handle=%d link_role=%d transport=%d\n",
+ hci_handle, link_role, transport);
+ /* Ensure we don't have duplicates */
+ p = btm_bda_to_acl(bda, transport);
+ if (p != (tACL_CONN *)NULL) {
+ p->hci_handle = hci_handle;
+ p->link_role = link_role;
+#if BLE_INCLUDED == TRUE
+ p->transport = transport;
+#endif
+ BTM_TRACE_DEBUG ("Duplicate btm_acl_created: RemBdAddr: %02x%02x%02x%02x%02x%02x\n",
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+ BTM_SetLinkPolicy(p->remote_addr, &btm_cb.btm_def_link_policy);
+ return;
+ }
+
+ /* Allocate acl_db entry */
+ if (list_length(btm_cb.p_acl_db_list) >= MAX_L2CAP_LINKS) {
+ return;
+ }
+ else {
+ p = (tACL_CONN *)osi_malloc(sizeof(tACL_CONN));
+ if (p && list_append(btm_cb.p_acl_db_list, p)) {
+ memset(p, 0, sizeof(tACL_CONN));
+ p->in_use = TRUE;
+ p->hci_handle = hci_handle;
+ p->link_role = link_role;
+ p->link_up_issued = FALSE;
+ memcpy (p->remote_addr, bda, BD_ADDR_LEN);
+ /* Set the default version of the peer device to version4.0 before exchange the version with it.
+ If the peer device act as a master and don't exchange the version with us, then it can only use the
+ legacy connect instead of secure connection in the pairing step. */
+ p->lmp_version = HCI_PROTO_VERSION_4_0;
+#if BLE_INCLUDED == TRUE
+ p->transport = transport;
+#if BLE_PRIVACY_SPT == TRUE
+ if (transport == BT_TRANSPORT_LE) {
+ btm_ble_refresh_local_resolvable_private_addr(bda,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr);
+ }
+#else
+ p->conn_addr_type = BLE_ADDR_PUBLIC;
+ memcpy(p->conn_addr, &controller_get_interface()->get_address()->address, BD_ADDR_LEN);
+ BTM_TRACE_DEBUG ("conn_addr: RemBdAddr: %02x%02x%02x%02x%02x%02x\n",
+ p->conn_addr[0], p->conn_addr[1], p->conn_addr[2], p->conn_addr[3], p->conn_addr[4], p->conn_addr[5]);
+#endif
+#endif
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+
+ p->p_pm_mode_db = btm_pm_sm_alloc();
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG( "btm_pm_sm_alloc handle:%d st:%d", hci_handle, p->p_pm_mode_db->state);
+#endif // BTM_PM_DEBUG
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ btm_sec_update_legacy_auth_state(p, BTM_ACL_LEGACY_AUTH_NONE);
+#endif
+
+ if (dc) {
+ memcpy (p->remote_dc, dc, DEV_CLASS_LEN);
+ }
+
+ if (bdn) {
+ memcpy (p->remote_name, bdn, BTM_MAX_REM_BD_NAME_LEN);
+ }
+
+ /* if BR/EDR do something more */
+ if (transport == BT_TRANSPORT_BR_EDR) {
+ btsnd_hcic_read_rmt_clk_offset (p->hci_handle);
+ btsnd_hcic_rmt_ver_req (p->hci_handle);
+ }
+ p_dev_rec = btm_find_dev_by_handle (hci_handle);
+
+#if (BLE_INCLUDED == TRUE)
+ if (p_dev_rec ) {
+ BTM_TRACE_DEBUG ("device_type=0x%x\n", p_dev_rec->device_type);
+ }
+#endif
+
+ if (p_dev_rec && !(transport == BT_TRANSPORT_LE)) {
+ if (!p_dev_rec->remote_secure_connection_previous_state) {
+ /* If remote features already known, copy them and continue connection setup */
+ if ((p_dev_rec->num_read_pages) &&
+ (p_dev_rec->num_read_pages <= (HCI_EXT_FEATURES_PAGE_MAX + 1))) {
+ memcpy (p->peer_lmp_features, p_dev_rec->features,
+ (HCI_FEATURE_BYTES_PER_PAGE * p_dev_rec->num_read_pages));
+ p->num_read_pages = p_dev_rec->num_read_pages;
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ const UINT8 req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND);
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+ /* Store the Peer Security Capabilites (in SM4 and rmt_sec_caps) */
+#if (SMP_INCLUDED == TRUE)
+ btm_sec_set_peer_sec_caps(p, p_dev_rec);
+#endif ///SMP_INCLUDED == TRUE
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ BTM_TRACE_API("%s: pend:%d\n", __FUNCTION__, req_pend);
+ if (req_pend) {
+ /* Request for remaining Security Features (if any) */
+ l2cu_resubmit_pending_sec_req (p_dev_rec->bd_addr);
+ }
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+ btm_establish_continue (p);
+ return;
+ }
+ } else {
+ /* If remote features indicated secure connection (SC) mode, check the remote feautres again*/
+ /* this is to prevent from BIAS attack where attacker can downgrade SC mode*/
+ btm_read_remote_features (p->hci_handle);
+ }
+ }
+
+#if (BLE_INCLUDED == TRUE)
+ /* If here, features are not known yet */
+ if (p_dev_rec && transport == BT_TRANSPORT_LE) {
+#if BLE_PRIVACY_SPT == TRUE
+ btm_ble_get_acl_remote_addr (p_dev_rec, p->active_remote_addr,
+ &p->active_remote_addr_type);
+#endif
+
+ if (link_role == HCI_ROLE_MASTER) {
+ btsnd_hcic_ble_read_remote_feat(p->hci_handle);
+ } else if (HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(controller_get_interface()->get_features_ble()->as_array)
+ && link_role == HCI_ROLE_SLAVE) {
+ btsnd_hcic_rmt_ver_req (p->hci_handle);
+ } else {
+ btm_establish_continue(p);
+ }
+ } else
+#endif
+ {
+ btm_read_remote_features (p->hci_handle);
+ }
+
+ /* read page 1 - on rmt feature event for buffer reasons */
+ return;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_acl_report_role_change
+**
+** Description This function is called when the local device is deemed
+** to be down. It notifies L2CAP of the failure.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_report_role_change (UINT8 hci_status, BD_ADDR bda)
+{
+ tBTM_ROLE_SWITCH_CMPL ref_data;
+ BTM_TRACE_DEBUG ("btm_acl_report_role_change\n");
+ if (btm_cb.devcb.p_switch_role_cb
+ && (bda && (0 == memcmp(btm_cb.devcb.switch_role_ref_data.remote_bd_addr, bda, BD_ADDR_LEN)))) {
+ memcpy (&ref_data, &btm_cb.devcb.switch_role_ref_data, sizeof(tBTM_ROLE_SWITCH_CMPL));
+ ref_data.hci_status = hci_status;
+ (*btm_cb.devcb.p_switch_role_cb)(&ref_data);
+ memset (&btm_cb.devcb.switch_role_ref_data, 0, sizeof(tBTM_ROLE_SWITCH_CMPL));
+ btm_cb.devcb.p_switch_role_cb = NULL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_removed
+**
+** Description This function is called by L2CAP when an ACL connection
+** is removed. Since only L2CAP creates ACL links, we use
+** the L2CAP link index as our index into the control blocks.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_removed (BD_ADDR bda, tBT_TRANSPORT transport)
+{
+ tACL_CONN *p;
+ tBTM_BL_EVENT_DATA evt_data;
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+#endif
+ BTM_TRACE_DEBUG ("btm_acl_removed\n");
+ p = btm_bda_to_acl(bda, transport);
+ if (p != (tACL_CONN *)NULL) {
+ p->in_use = FALSE;
+
+ /* if the disconnected channel has a pending role switch, clear it now */
+ btm_acl_report_role_change(HCI_ERR_NO_CONNECTION, bda);
+
+ /* Only notify if link up has had a chance to be issued */
+ if (p->link_up_issued) {
+ p->link_up_issued = FALSE;
+
+ /* If anyone cares, tell him database changed */
+ if (btm_cb.p_bl_changed_cb) {
+ evt_data.event = BTM_BL_DISCN_EVT;
+ evt_data.discn.p_bda = bda;
+#if BLE_INCLUDED == TRUE
+ evt_data.discn.handle = p->hci_handle;
+ evt_data.discn.transport = p->transport;
+#endif
+ (*btm_cb.p_bl_changed_cb)(&evt_data);
+ }
+
+ btm_acl_update_busy_level (BTM_BLI_ACL_DOWN_EVT);
+ }
+
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+
+ BTM_TRACE_DEBUG ("acl hci_handle=%d transport=%d connectable_mode=0x%0x link_role=%d\n",
+ p->hci_handle,
+ p->transport,
+ btm_cb.ble_ctr_cb.inq_var.connectable_mode,
+ p->link_role);
+
+ p_dev_rec = btm_find_dev(bda);
+ if ( p_dev_rec) {
+ BTM_TRACE_DEBUG("before update p_dev_rec->sec_flags=0x%x\n", p_dev_rec->sec_flags);
+ if (p->transport == BT_TRANSPORT_LE) {
+ BTM_TRACE_DEBUG("LE link down\n");
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LE_ENCRYPTED | BTM_SEC_ROLE_SWITCHED);
+ if ( (p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN) == 0) {
+ BTM_TRACE_DEBUG("Not Bonded\n");
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LE_LINK_KEY_AUTHED | BTM_SEC_LE_AUTHENTICATED);
+ } else {
+ BTM_TRACE_DEBUG("Bonded\n");
+ }
+ } else {
+ BTM_TRACE_DEBUG("Bletooth link down\n");
+ p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED
+ | BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED);
+ }
+ BTM_TRACE_DEBUG("after update p_dev_rec->sec_flags=0x%x\n", p_dev_rec->sec_flags);
+ } else {
+ BTM_TRACE_ERROR("Device not found\n");
+
+ }
+#endif
+
+ list_remove(btm_cb.p_pm_mode_db_list, p->p_pm_mode_db);
+ /* Clear the ACL connection data */
+ memset(p, 0, sizeof(tACL_CONN));
+ if (list_remove(btm_cb.p_acl_db_list, p)) {
+ p = NULL;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_acl_device_down
+**
+** Description This function is called when the local device is deemed
+** to be down. It notifies L2CAP of the failure.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_device_down (void)
+{
+ tACL_CONN *p = NULL;
+ BTM_TRACE_DEBUG ("btm_acl_device_down\n");
+ for (list_node_t *p_node = list_begin(btm_cb.p_acl_db_list); p_node;) {
+ list_node_t *p_next = list_next(p_node);
+ p = list_node(p_node);
+ if (p && p->in_use) {
+ BTM_TRACE_DEBUG ("hci_handle=%d HCI_ERR_HW_FAILURE \n", p->hci_handle );
+ l2c_link_hci_disc_comp (p->hci_handle, HCI_ERR_HW_FAILURE);
+ }
+ p_node = p_next;
+ }
+}
+/*******************************************************************************
+**
+** Function btm_acl_update_busy_level
+**
+** Description This function is called to update the busy level of the system
+** .
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_update_busy_level (tBTM_BLI_EVENT event)
+{
+ tBTM_BL_UPDATE_DATA evt;
+ UINT8 busy_level;
+ BTM_TRACE_DEBUG ("btm_acl_update_busy_level\n");
+ BOOLEAN old_inquiry_state = btm_cb.is_inquiry;
+ switch (event) {
+ case BTM_BLI_ACL_UP_EVT:
+ BTM_TRACE_DEBUG ("BTM_BLI_ACL_UP_EVT\n");
+ break;
+ case BTM_BLI_ACL_DOWN_EVT:
+ BTM_TRACE_DEBUG ("BTM_BLI_ACL_DOWN_EVT\n");
+ break;
+ case BTM_BLI_PAGE_EVT:
+ BTM_TRACE_DEBUG ("BTM_BLI_PAGE_EVT\n");
+ btm_cb.is_paging = TRUE;
+ evt.busy_level_flags = BTM_BL_PAGING_STARTED;
+ break;
+ case BTM_BLI_PAGE_DONE_EVT:
+ BTM_TRACE_DEBUG ("BTM_BLI_PAGE_DONE_EVT\n");
+ btm_cb.is_paging = FALSE;
+ evt.busy_level_flags = BTM_BL_PAGING_COMPLETE;
+ break;
+ case BTM_BLI_INQ_EVT:
+ BTM_TRACE_DEBUG ("BTM_BLI_INQ_EVT\n");
+ btm_cb.is_inquiry = TRUE;
+ evt.busy_level_flags = BTM_BL_INQUIRY_STARTED;
+ break;
+ case BTM_BLI_INQ_CANCEL_EVT:
+ BTM_TRACE_DEBUG ("BTM_BLI_INQ_CANCEL_EVT\n");
+ btm_cb.is_inquiry = FALSE;
+ evt.busy_level_flags = BTM_BL_INQUIRY_CANCELLED;
+ break;
+ case BTM_BLI_INQ_DONE_EVT:
+ BTM_TRACE_DEBUG ("BTM_BLI_INQ_DONE_EVT\n");
+ btm_cb.is_inquiry = FALSE;
+ evt.busy_level_flags = BTM_BL_INQUIRY_COMPLETE;
+ break;
+ }
+
+ if (btm_cb.is_paging || btm_cb.is_inquiry) {
+ busy_level = 10;
+ } else {
+ busy_level = BTM_GetNumAclLinks();
+ }
+
+ if ((busy_level != btm_cb.busy_level) || (old_inquiry_state != btm_cb.is_inquiry)) {
+ evt.event = BTM_BL_UPDATE_EVT;
+ evt.busy_level = busy_level;
+ btm_cb.busy_level = busy_level;
+ if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_UPDATE_MASK)) {
+ (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA *)&evt);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_link_stat_report
+**
+** Description This function is called when the ACL link related
+ events are received from controller. It reports the ACL
+ link status to upper layer.
+
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_link_stat_report(tBTM_ACL_LINK_STAT_EVENT_DATA *p_data)
+{
+ BTM_TRACE_DEBUG ("btm_acl_link_stat_report\n");
+
+ if (btm_cb.p_acl_link_stat_cb) {
+ (*btm_cb.p_acl_link_stat_cb)(p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetRole
+**
+** Description This function is called to get the role of the local device
+** for the ACL connection with the specified remote device
+**
+** Returns BTM_SUCCESS if connection exists.
+** BTM_UNKNOWN_ADDR if no active link with bd addr specified
+**
+*******************************************************************************/
+tBTM_STATUS BTM_GetRole (BD_ADDR remote_bd_addr, UINT8 *p_role)
+{
+ tACL_CONN *p;
+ BTM_TRACE_DEBUG ("BTM_GetRole\n");
+ if ((p = btm_bda_to_acl(remote_bd_addr, BT_TRANSPORT_BR_EDR)) == NULL) {
+ *p_role = BTM_ROLE_UNDEFINED;
+ return (BTM_UNKNOWN_ADDR);
+ }
+
+ /* Get the current role */
+ *p_role = p->link_role;
+ return (BTM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SwitchRole
+**
+** Description This function is called to switch role between master and
+** slave. If role is already set it will do nothing. If the
+** command was initiated, the callback function is called upon
+** completion.
+**
+** Returns BTM_SUCCESS if already in specified role.
+** BTM_CMD_STARTED if command issued to controller.
+** BTM_NO_RESOURCES if couldn't allocate memory to issue command
+** BTM_UNKNOWN_ADDR if no active link with bd addr specified
+** BTM_MODE_UNSUPPORTED if local device does not support role switching
+** BTM_BUSY if the previous command is not completed
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SwitchRole (BD_ADDR remote_bd_addr, UINT8 new_role, tBTM_CMPL_CB *p_cb)
+{
+ tACL_CONN *p;
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+#if BTM_SCO_INCLUDED == TRUE
+ BOOLEAN is_sco_active;
+#endif
+ tBTM_STATUS status;
+ tBTM_PM_MODE pwr_mode;
+ tBTM_PM_PWR_MD settings;
+#if (BT_USE_TRACES == TRUE)
+ BD_ADDR_PTR p_bda;
+#endif
+ BTM_TRACE_API ("BTM_SwitchRole BDA: %02x-%02x-%02x-%02x-%02x-%02x\n",
+ remote_bd_addr[0], remote_bd_addr[1], remote_bd_addr[2],
+ remote_bd_addr[3], remote_bd_addr[4], remote_bd_addr[5]);
+
+ /* Make sure the local device supports switching */
+ if (!controller_get_interface()->supports_master_slave_role_switch()) {
+ return (BTM_MODE_UNSUPPORTED);
+ }
+
+ if (btm_cb.devcb.p_switch_role_cb && p_cb) {
+#if (BT_USE_TRACES == TRUE)
+ p_bda = btm_cb.devcb.switch_role_ref_data.remote_bd_addr;
+ BTM_TRACE_DEBUG ("Role switch on other device is in progress 0x%02x%02x%02x%02x%02x%02x\n",
+ p_bda[0], p_bda[1], p_bda[2],
+ p_bda[3], p_bda[4], p_bda[5]);
+#endif
+ return (BTM_BUSY);
+ }
+
+ if ((p = btm_bda_to_acl(remote_bd_addr, BT_TRANSPORT_BR_EDR)) == NULL) {
+ return (BTM_UNKNOWN_ADDR);
+ }
+
+ /* Finished if already in desired role */
+ if (p->link_role == new_role) {
+ return (BTM_SUCCESS);
+ }
+
+#if BTM_SCO_INCLUDED == TRUE
+ /* Check if there is any SCO Active on this BD Address */
+ is_sco_active = btm_is_sco_active_by_bdaddr(remote_bd_addr);
+
+ if (is_sco_active == TRUE) {
+ return (BTM_NO_RESOURCES);
+ }
+#endif
+
+ /* Ignore role switch request if the previous request was not completed */
+ if (p->switch_role_state != BTM_ACL_SWKEY_STATE_IDLE) {
+ BTM_TRACE_DEBUG ("BTM_SwitchRole busy: %d\n",
+ p->switch_role_state);
+ return (BTM_BUSY);
+ }
+
+ if ((status = BTM_ReadPowerMode(p->remote_addr, &pwr_mode)) != BTM_SUCCESS) {
+ return (status);
+ }
+
+ /* Wake up the link if in sniff or park before attempting switch */
+ if (pwr_mode == BTM_PM_MD_PARK || pwr_mode == BTM_PM_MD_SNIFF) {
+ memset( (void *)&settings, 0, sizeof(settings));
+ settings.mode = BTM_PM_MD_ACTIVE;
+ status = BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p->remote_addr, &settings);
+ if (status != BTM_CMD_STARTED) {
+ return (BTM_WRONG_MODE);
+ }
+
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_MODE_CHANGE;
+ }
+ /* some devices do not support switch while encryption is on */
+ else {
+ p_dev_rec = btm_find_dev (remote_bd_addr);
+ if ((p_dev_rec != NULL)
+ && ((p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) != 0)
+ && !BTM_EPR_AVAILABLE(p)) {
+ /* bypass turning off encryption if change link key is already doing it */
+ if (p->encrypt_state != BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF) {
+ if (!btsnd_hcic_set_conn_encrypt (p->hci_handle, FALSE)) {
+ return (BTM_NO_RESOURCES);
+ } else {
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF;
+ }
+ }
+
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF;
+ } else {
+ if (!btsnd_hcic_switch_role (remote_bd_addr, new_role)) {
+ return (BTM_NO_RESOURCES);
+ }
+
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IN_PROGRESS;
+
+#if BTM_DISC_DURING_RS == TRUE
+ if (p_dev_rec) {
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING;
+ }
+#endif
+ }
+ }
+
+ /* Initialize return structure in case request fails */
+ if (p_cb) {
+ memcpy (btm_cb.devcb.switch_role_ref_data.remote_bd_addr, remote_bd_addr,
+ BD_ADDR_LEN);
+ btm_cb.devcb.switch_role_ref_data.role = new_role;
+ /* initialized to an error code */
+ btm_cb.devcb.switch_role_ref_data.hci_status = HCI_ERR_UNSUPPORTED_VALUE;
+ btm_cb.devcb.p_switch_role_cb = p_cb;
+ }
+ return (BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_encrypt_change
+**
+** Description This function is when encryption of the connection is
+** completed by the LM. Checks to see if a role switch or
+** change of link key was active and initiates or continues
+** process if needed.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable)
+{
+ tACL_CONN *p;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_BL_ROLE_CHG_DATA evt;
+
+ BTM_TRACE_DEBUG ("btm_acl_encrypt_change handle=%d status=%d encr_enabl=%d\n",
+ handle, status, encr_enable);
+ p = btm_handle_to_acl(handle);
+ if (p == NULL) {
+ return;
+ }
+ /* Process Role Switch if active */
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF) {
+ /* if encryption turn off failed we still will try to switch role */
+ if (encr_enable) {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ } else {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_SWITCHING;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_TEMP_FUNC;
+ }
+
+ if (!btsnd_hcic_switch_role (p->remote_addr, (UINT8)!p->link_role)) {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ btm_acl_report_role_change(btm_cb.devcb.switch_role_ref_data.hci_status, p->remote_addr);
+ }
+#if BTM_DISC_DURING_RS == TRUE
+ else {
+ if ((p_dev_rec = btm_find_dev (p->remote_addr)) != NULL) {
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING;
+ }
+ }
+#endif
+
+ }
+ /* Finished enabling Encryption after role switch */
+ else if (p->switch_role_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_ON) {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ btm_acl_report_role_change(btm_cb.devcb.switch_role_ref_data.hci_status, p->remote_addr);
+
+ /* if role change event is registered, report it now */
+ if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_ROLE_CHG_MASK)) {
+ evt.event = BTM_BL_ROLE_CHG_EVT;
+ evt.new_role = btm_cb.devcb.switch_role_ref_data.role;
+ evt.p_bda = btm_cb.devcb.switch_role_ref_data.remote_bd_addr;
+ evt.hci_status = btm_cb.devcb.switch_role_ref_data.hci_status;
+ (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA *)&evt);
+
+ BTM_TRACE_DEBUG("Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, rs_st:%d\n",
+ evt.new_role, evt.hci_status, p->switch_role_state);
+ }
+
+#if BTM_DISC_DURING_RS == TRUE
+ /* If a disconnect is pending, issue it now that role switch has completed */
+ if ((p_dev_rec = btm_find_dev (p->remote_addr)) != NULL) {
+ if (p_dev_rec->rs_disc_pending == BTM_SEC_DISC_PENDING) {
+ BTM_TRACE_WARNING("btm_acl_encrypt_change -> Issuing delayed HCI_Disconnect!!!\n");
+ btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER);
+ }
+ BTM_TRACE_WARNING("btm_acl_encrypt_change: tBTM_SEC_DEV:0x%x rs_disc_pending=%d\n",
+ (UINT32)p_dev_rec, p_dev_rec->rs_disc_pending);
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+ }
+#endif
+ }
+}
+/*******************************************************************************
+**
+** Function BTM_SetLinkPolicy
+**
+** Description Create and send HCI "Write Policy Set" command
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetLinkPolicy (BD_ADDR remote_bda, UINT16 *settings)
+{
+ tACL_CONN *p;
+ UINT8 *localFeatures = BTM_ReadLocalFeatures();
+ BTM_TRACE_DEBUG ("BTM_SetLinkPolicy\n");
+ /* BTM_TRACE_API ("BTM_SetLinkPolicy: requested settings: 0x%04x", *settings ); */
+
+ /* First, check if hold mode is supported */
+ if (*settings != HCI_DISABLE_ALL_LM_MODES) {
+ if ( (*settings & HCI_ENABLE_MASTER_SLAVE_SWITCH) && (!HCI_SWITCH_SUPPORTED(localFeatures)) ) {
+ *settings &= (~HCI_ENABLE_MASTER_SLAVE_SWITCH);
+ BTM_TRACE_API ("BTM_SetLinkPolicy switch not supported (settings: 0x%04x)\n", *settings );
+ }
+ if ( (*settings & HCI_ENABLE_HOLD_MODE) && (!HCI_HOLD_MODE_SUPPORTED(localFeatures)) ) {
+ *settings &= (~HCI_ENABLE_HOLD_MODE);
+ BTM_TRACE_API ("BTM_SetLinkPolicy hold not supported (settings: 0x%04x)\n", *settings );
+ }
+ if ( (*settings & HCI_ENABLE_SNIFF_MODE) && (!HCI_SNIFF_MODE_SUPPORTED(localFeatures)) ) {
+ *settings &= (~HCI_ENABLE_SNIFF_MODE);
+ BTM_TRACE_API ("BTM_SetLinkPolicy sniff not supported (settings: 0x%04x)\n", *settings );
+ }
+ if ( (*settings & HCI_ENABLE_PARK_MODE) && (!HCI_PARK_MODE_SUPPORTED(localFeatures)) ) {
+ *settings &= (~HCI_ENABLE_PARK_MODE);
+ BTM_TRACE_API ("BTM_SetLinkPolicy park not supported (settings: 0x%04x)\n", *settings );
+ }
+ }
+
+ if ((p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR)) != NULL) {
+ return (btsnd_hcic_write_policy_set (p->hci_handle, *settings) ? BTM_CMD_STARTED : BTM_NO_RESOURCES);
+ }
+
+ /* If here, no BD Addr found */
+ return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetDefaultLinkPolicy
+**
+** Description Set the default value for HCI "Write Policy Set" command
+** to use when an ACL link is created.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_SetDefaultLinkPolicy (UINT16 settings)
+{
+ UINT8 *localFeatures = BTM_ReadLocalFeatures();
+
+ BTM_TRACE_DEBUG("BTM_SetDefaultLinkPolicy setting:0x%04x\n", settings);
+
+ if ((settings & HCI_ENABLE_MASTER_SLAVE_SWITCH) && (!HCI_SWITCH_SUPPORTED(localFeatures))) {
+ settings &= ~HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ BTM_TRACE_DEBUG("BTM_SetDefaultLinkPolicy switch not supported (settings: 0x%04x)\n", settings);
+ }
+ if ((settings & HCI_ENABLE_HOLD_MODE) && (!HCI_HOLD_MODE_SUPPORTED(localFeatures))) {
+ settings &= ~HCI_ENABLE_HOLD_MODE;
+ BTM_TRACE_DEBUG("BTM_SetDefaultLinkPolicy hold not supported (settings: 0x%04x)\n", settings);
+ }
+ if ((settings & HCI_ENABLE_SNIFF_MODE) && (!HCI_SNIFF_MODE_SUPPORTED(localFeatures))) {
+ settings &= ~HCI_ENABLE_SNIFF_MODE;
+ BTM_TRACE_DEBUG("BTM_SetDefaultLinkPolicy sniff not supported (settings: 0x%04x)\n", settings);
+ }
+ if ((settings & HCI_ENABLE_PARK_MODE) && (!HCI_PARK_MODE_SUPPORTED(localFeatures))) {
+ settings &= ~HCI_ENABLE_PARK_MODE;
+ BTM_TRACE_DEBUG("BTM_SetDefaultLinkPolicy park not supported (settings: 0x%04x)\n", settings);
+ }
+ BTM_TRACE_DEBUG("Set DefaultLinkPolicy:0x%04x\n", settings);
+
+ btm_cb.btm_def_link_policy = settings;
+
+ /* Set the default Link Policy of the controller */
+ btsnd_hcic_write_def_policy_set(settings);
+}
+
+/*******************************************************************************
+**
+** Function btm_read_remote_version_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the remote version info.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_remote_version_complete (UINT8 *p)
+{
+ tACL_CONN *p_acl_cb = NULL;
+ UINT8 status;
+ UINT16 handle;
+ BTM_TRACE_DEBUG ("btm_read_remote_version_complete\n");
+
+ STREAM_TO_UINT8 (status, p);
+ STREAM_TO_UINT16 (handle, p);
+
+ /* Look up the connection by handle and copy features */
+ p_acl_cb = btm_handle_to_acl(handle);
+ if (p_acl_cb) {
+ if (status == HCI_SUCCESS) {
+ STREAM_TO_UINT8 (p_acl_cb->lmp_version, p);
+ STREAM_TO_UINT16 (p_acl_cb->manufacturer, p);
+ STREAM_TO_UINT16 (p_acl_cb->lmp_subversion, p);
+ }
+#if BLE_INCLUDED == TRUE
+ if (p_acl_cb->transport == BT_TRANSPORT_LE) {
+ if(p_acl_cb->link_role == HCI_ROLE_MASTER) {
+ if (HCI_LE_DATA_LEN_EXT_SUPPORTED(p_acl_cb->peer_le_features)) {
+ uint16_t data_length = controller_get_interface()->get_ble_default_data_packet_length();
+ uint16_t data_txtime = controller_get_interface()->get_ble_default_data_packet_txtime();
+ if (data_length != p_acl_cb->data_length_params.tx_len) {
+ p_acl_cb->data_len_updating = true;
+ btsnd_hcic_ble_set_data_length(p_acl_cb->hci_handle, data_length, data_txtime);
+ }
+ }
+ l2cble_notify_le_connection (p_acl_cb->remote_addr);
+ } else {
+ //slave role, read remote feature
+ btsnd_hcic_ble_read_remote_feat(p_acl_cb->hci_handle);
+ }
+ }
+#endif
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_process_remote_ext_features
+**
+** Description Local function called to process all extended features pages
+** read from a remote device.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_process_remote_ext_features (tACL_CONN *p_acl_cb, UINT8 num_read_pages)
+{
+ UINT16 handle = p_acl_cb->hci_handle;
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
+ UINT8 page_idx;
+
+ BTM_TRACE_DEBUG ("btm_process_remote_ext_features\n");
+
+ /* Make sure we have the record to save remote features information */
+ if (p_dev_rec == NULL) {
+ /* Get a new device; might be doing dedicated bonding */
+ p_dev_rec = btm_find_or_alloc_dev (p_acl_cb->remote_addr);
+ }
+
+ p_acl_cb->num_read_pages = num_read_pages;
+ p_dev_rec->num_read_pages = num_read_pages;
+
+ /* Move the pages to placeholder */
+ for (page_idx = 0; page_idx < num_read_pages; page_idx++) {
+ if (page_idx > HCI_EXT_FEATURES_PAGE_MAX) {
+ BTM_TRACE_ERROR("%s: page=%d unexpected\n", __FUNCTION__, page_idx);
+ break;
+ }
+ memcpy (p_dev_rec->features[page_idx], p_acl_cb->peer_lmp_features[page_idx],
+ HCI_FEATURE_BYTES_PER_PAGE);
+ }
+
+ const UINT8 req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND);
+#if (SMP_INCLUDED == TRUE)
+ /* Store the Peer Security Capabilites (in SM4 and rmt_sec_caps) */
+ btm_sec_set_peer_sec_caps(p_acl_cb, p_dev_rec);
+#endif ///SMP_INCLUDED == TRUE
+ BTM_TRACE_API("%s: pend:%d\n", __FUNCTION__, req_pend);
+ if (req_pend) {
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ /* Request for remaining Security Features (if any) */
+ l2cu_resubmit_pending_sec_req (p_dev_rec->bd_addr);
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_read_remote_features
+**
+** Description Local function called to send a read remote supported features/
+** remote extended features page[0].
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_remote_features (UINT16 handle)
+{
+ tACL_CONN *p_acl_cb;
+
+ BTM_TRACE_DEBUG("btm_read_remote_features() handle: %d\n", handle);
+
+ p_acl_cb = btm_handle_to_acl(handle);
+ if (p_acl_cb == NULL) {
+ BTM_TRACE_ERROR("btm_read_remote_features handle=%d invalid\n", handle);
+ return;
+ }
+
+ p_acl_cb->num_read_pages = 0;
+ memset (p_acl_cb->peer_lmp_features, 0, sizeof(p_acl_cb->peer_lmp_features));
+
+ /* first send read remote supported features HCI command */
+ /* because we don't know whether the remote support extended feature command */
+ btsnd_hcic_rmt_features_req (handle);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_read_remote_ext_features
+**
+** Description Local function called to send a read remote extended features
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_remote_ext_features (UINT16 handle, UINT8 page_number)
+{
+ BTM_TRACE_DEBUG("btm_read_remote_ext_features() handle: %d page: %d\n", handle, page_number);
+
+ btsnd_hcic_rmt_ext_features(handle, page_number);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_read_remote_features_complete
+**
+** Description This function is called when the remote supported features
+** complete event is received from the HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_remote_features_complete (UINT8 *p)
+{
+ tACL_CONN *p_acl_cb;
+ UINT8 status;
+ UINT16 handle;
+
+ BTM_TRACE_DEBUG ("btm_read_remote_features_complete\n");
+ STREAM_TO_UINT8 (status, p);
+
+ if (status != HCI_SUCCESS) {
+ BTM_TRACE_ERROR ("btm_read_remote_features_complete failed (status 0x%02x)\n", status);
+ return;
+ }
+
+ STREAM_TO_UINT16 (handle, p);
+
+ p_acl_cb = btm_handle_to_acl(handle);
+ if (p_acl_cb == NULL) {
+ BTM_TRACE_ERROR("btm_read_remote_features_complete handle=%d invalid\n", handle);
+ return;
+ }
+
+ /* Copy the received features page */
+ STREAM_TO_ARRAY(p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0], p,
+ HCI_FEATURE_BYTES_PER_PAGE);
+
+ if ((HCI_LMP_EXTENDED_SUPPORTED(p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) &&
+ (controller_get_interface()->supports_reading_remote_extended_features())) {
+ /* if the remote controller has extended features and local controller supports
+ ** HCI_Read_Remote_Extended_Features command then start reading these feature starting
+ ** with extended features page 1 */
+ BTM_TRACE_DEBUG ("Start reading remote extended features\n");
+ btm_read_remote_ext_features(handle, HCI_EXT_FEATURES_PAGE_1);
+ return;
+ }
+
+ /* Remote controller has no extended features. Process remote controller supported features
+ (features page HCI_EXT_FEATURES_PAGE_0). */
+ btm_process_remote_ext_features (p_acl_cb, 1);
+
+ /* Continue with HCI connection establishment */
+ btm_establish_continue (p_acl_cb);
+}
+
+/*******************************************************************************
+**
+** Function btm_read_remote_ext_features_complete
+**
+** Description This function is called when the remote extended features
+** complete event is received from the HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_remote_ext_features_complete (UINT8 *p)
+{
+ tACL_CONN *p_acl_cb;
+ UINT8 page_num, max_page;
+ UINT16 handle;
+
+ BTM_TRACE_DEBUG ("btm_read_remote_ext_features_complete\n");
+
+ ++p;
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT8 (page_num, p);
+ STREAM_TO_UINT8 (max_page, p);
+
+ /* Validate parameters */
+ p_acl_cb = btm_handle_to_acl(handle);
+ if (p_acl_cb == NULL) {
+ BTM_TRACE_ERROR("btm_read_remote_ext_features_complete handle=%d invalid\n", handle);
+ return;
+ }
+
+ if (max_page > HCI_EXT_FEATURES_PAGE_MAX) {
+ BTM_TRACE_ERROR("btm_read_remote_ext_features_complete page=%d unknown", max_page);
+ }
+
+
+ /* Copy the received features page */
+ STREAM_TO_ARRAY(p_acl_cb->peer_lmp_features[page_num], p, HCI_FEATURE_BYTES_PER_PAGE);
+
+ /* If there is the next remote features page and
+ * we have space to keep this page data - read this page */
+ if ((page_num < max_page) && (page_num < HCI_EXT_FEATURES_PAGE_MAX)) {
+ page_num++;
+ BTM_TRACE_DEBUG("BTM reads next remote extended features page (%d)\n", page_num);
+ btm_read_remote_ext_features (handle, page_num);
+ return;
+ }
+
+ /* Reading of remote feature pages is complete */
+ BTM_TRACE_DEBUG("BTM reached last remote extended features page (%d)\n", page_num);
+
+ /* Process the pages */
+ btm_process_remote_ext_features (p_acl_cb, (UINT8) (page_num + 1));
+
+ /* Continue with HCI connection establishment */
+ btm_establish_continue (p_acl_cb);
+}
+
+/*******************************************************************************
+**
+** Function btm_read_remote_ext_features_failed
+**
+** Description This function is called when the remote extended features
+** complete event returns a failed status.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_remote_ext_features_failed (UINT8 status, UINT16 handle)
+{
+ tACL_CONN *p_acl_cb;
+
+ BTM_TRACE_WARNING ("btm_read_remote_ext_features_failed (status 0x%02x) for handle %d\n",
+ status, handle);
+
+ p_acl_cb = btm_handle_to_acl(handle);
+ if (p_acl_cb == NULL) {
+ BTM_TRACE_ERROR("btm_read_remote_ext_features_failed handle=%d invalid\n", handle);
+ return;
+ }
+
+ /* Process supported features only */
+ btm_process_remote_ext_features (p_acl_cb, 1);
+
+ /* Continue HCI connection establishment */
+ btm_establish_continue (p_acl_cb);
+}
+
+/*******************************************************************************
+**
+** Function btm_establish_continue
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the read local link policy request.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_establish_continue (tACL_CONN *p_acl_cb)
+{
+ tBTM_BL_EVENT_DATA evt_data;
+ BTM_TRACE_DEBUG ("btm_establish_continue\n");
+#if (!defined(BTM_BYPASS_EXTRA_ACL_SETUP) || BTM_BYPASS_EXTRA_ACL_SETUP == FALSE)
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+ if (p_acl_cb->transport == BT_TRANSPORT_BR_EDR)
+#endif
+ {
+ /* For now there are a some devices that do not like sending */
+ /* commands events and data at the same time. */
+ /* Set the packet types to the default allowed by the device */
+ btm_set_packet_types (p_acl_cb, btm_cb.btm_acl_pkt_types_supported);
+
+ if (btm_cb.btm_def_link_policy) {
+ BTM_SetLinkPolicy (p_acl_cb->remote_addr, &btm_cb.btm_def_link_policy);
+ }
+ }
+#endif
+ p_acl_cb->link_up_issued = TRUE;
+
+ /* If anyone cares, tell him database changed */
+ if (btm_cb.p_bl_changed_cb) {
+ evt_data.event = BTM_BL_CONN_EVT;
+ evt_data.conn.p_bda = p_acl_cb->remote_addr;
+ evt_data.conn.p_bdn = p_acl_cb->remote_name;
+ evt_data.conn.p_dc = p_acl_cb->remote_dc;
+ evt_data.conn.p_features = p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0];
+ evt_data.conn.sc_downgrade = p_acl_cb->sc_downgrade;
+#if BLE_INCLUDED == TRUE
+ evt_data.conn.handle = p_acl_cb->hci_handle;
+ evt_data.conn.transport = p_acl_cb->transport;
+#endif
+
+ (*btm_cb.p_bl_changed_cb)(&evt_data);
+ }
+ btm_acl_update_busy_level (BTM_BLI_ACL_UP_EVT);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetDefaultLinkSuperTout
+**
+** Description Set the default value for HCI "Write Link Supervision Timeout"
+** command to use when an ACL link is created.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_SetDefaultLinkSuperTout (UINT16 timeout)
+{
+ BTM_TRACE_DEBUG ("BTM_SetDefaultLinkSuperTout\n");
+ btm_cb.btm_def_link_super_tout = timeout;
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetLinkSuperTout
+**
+** Description Read the link supervision timeout value of the connection
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_GetLinkSuperTout (BD_ADDR remote_bda, UINT16 *p_timeout)
+{
+ tACL_CONN *p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+
+ BTM_TRACE_DEBUG ("BTM_GetLinkSuperTout\n");
+ if (p != (tACL_CONN *)NULL) {
+ *p_timeout = p->link_super_tout;
+ return (BTM_SUCCESS);
+ }
+ /* If here, no BD Addr found */
+ return (BTM_UNKNOWN_ADDR);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetLinkSuperTout
+**
+** Description Create and send HCI "Write Link Supervision Timeout" command
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetLinkSuperTout (BD_ADDR remote_bda, UINT16 timeout)
+{
+ tACL_CONN *p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+
+ BTM_TRACE_DEBUG ("BTM_SetLinkSuperTout\n");
+ if (p != (tACL_CONN *)NULL) {
+ p->link_super_tout = timeout;
+
+ /* Only send if current role is Master; 2.0 spec requires this */
+ if (p->link_role == BTM_ROLE_MASTER) {
+ if (!btsnd_hcic_write_link_super_tout (LOCAL_BR_EDR_CONTROLLER_ID,
+ p->hci_handle, timeout)) {
+ return (BTM_NO_RESOURCES);
+ }
+
+ return (BTM_CMD_STARTED);
+ } else {
+ return (BTM_SUCCESS);
+ }
+ }
+
+ /* If here, no BD Addr found */
+ return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** Function BTM_IsAclConnectionUp
+**
+** Description This function is called to check if an ACL connection exists
+** to a specific remote BD Address.
+**
+** Returns TRUE if connection is up, else FALSE.
+**
+*******************************************************************************/
+BOOLEAN BTM_IsAclConnectionUp (BD_ADDR remote_bda, tBT_TRANSPORT transport)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_API ("BTM_IsAclConnectionUp: RemBdAddr: %02x%02x%02x%02x%02x%02x\n",
+ remote_bda[0], remote_bda[1], remote_bda[2],
+ remote_bda[3], remote_bda[4], remote_bda[5]);
+
+ p = btm_bda_to_acl(remote_bda, transport);
+ if (p != (tACL_CONN *)NULL) {
+ return (TRUE);
+ }
+
+ /* If here, no BD Addr found */
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetNumAclLinks
+**
+** Description This function is called to count the number of
+** ACL links that are active.
+**
+** Returns UINT16 Number of active ACL links
+**
+*******************************************************************************/
+UINT16 BTM_GetNumAclLinks (void)
+{
+ uint16_t num_acl = 0;
+
+ num_acl = list_length(btm_cb.p_acl_db_list);
+ return num_acl;
+}
+
+/*******************************************************************************
+**
+** Function btm_get_acl_disc_reason_code
+**
+** Description This function is called to get the disconnection reason code
+** returned by the HCI at disconnection complete event.
+**
+** Returns TRUE if connection is up, else FALSE.
+**
+*******************************************************************************/
+UINT16 btm_get_acl_disc_reason_code (void)
+{
+ UINT8 res = btm_cb.acl_disc_reason;
+ BTM_TRACE_DEBUG ("btm_get_acl_disc_reason_code\n");
+ return (res);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_GetHCIConnHandle
+**
+** Description This function is called to get the handle for an ACL connection
+** to a specific remote BD Address.
+**
+** Returns the handle of the connection, or 0xFFFF if none.
+**
+*******************************************************************************/
+UINT16 BTM_GetHCIConnHandle (BD_ADDR remote_bda, tBT_TRANSPORT transport)
+{
+ tACL_CONN *p;
+ BTM_TRACE_DEBUG ("BTM_GetHCIConnHandle\n");
+ p = btm_bda_to_acl(remote_bda, transport);
+ if (p != (tACL_CONN *)NULL) {
+ return (p->hci_handle);
+ }
+
+ /* If here, no BD Addr found */
+ return (0xFFFF);
+}
+
+/*******************************************************************************
+**
+** Function btm_process_clk_off_comp_evt
+**
+** Description This function is called when clock offset command completes.
+**
+** Input Parms hci_handle - connection handle associated with the change
+** clock offset
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_process_clk_off_comp_evt (UINT16 hci_handle, UINT16 clock_offset)
+{
+ tACL_CONN *p_acl_cb = NULL;
+ BTM_TRACE_DEBUG ("btm_process_clk_off_comp_evt\n");
+ /* Look up the connection by handle and set the current mode */
+ p_acl_cb = btm_handle_to_acl(hci_handle);
+ if (p_acl_cb) {
+ p_acl_cb->clock_offset = clock_offset;
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_role_changed
+**
+** Description This function is called whan a link's master/slave role change
+** event or command status event (with error) is received.
+** It updates the link control block, and calls
+** the registered callback with status and role (if registered).
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_role_changed (UINT8 hci_status, BD_ADDR bd_addr, UINT8 new_role)
+{
+ UINT8 *p_bda = (bd_addr) ? bd_addr :
+ btm_cb.devcb.switch_role_ref_data.remote_bd_addr;
+ tACL_CONN *p = btm_bda_to_acl(p_bda, BT_TRANSPORT_BR_EDR);
+ tBTM_ROLE_SWITCH_CMPL *p_data = &btm_cb.devcb.switch_role_ref_data;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_BL_ROLE_CHG_DATA evt;
+
+ BTM_TRACE_DEBUG ("btm_acl_role_changed\n");
+ /* Ignore any stray events */
+ if (p == NULL) {
+ /* it could be a failure */
+ if (hci_status != HCI_SUCCESS) {
+ btm_acl_report_role_change(hci_status, bd_addr);
+ }
+ return;
+ }
+
+ p_data->hci_status = hci_status;
+
+ if (hci_status == HCI_SUCCESS) {
+ p_data->role = new_role;
+ memcpy(p_data->remote_bd_addr, p_bda, BD_ADDR_LEN);
+
+ /* Update cached value */
+ p->link_role = new_role;
+
+ /* Reload LSTO: link supervision timeout is reset in the LM after a role switch */
+ if (new_role == BTM_ROLE_MASTER) {
+ BTM_SetLinkSuperTout (p->remote_addr, p->link_super_tout);
+ }
+ } else {
+ /* so the BTM_BL_ROLE_CHG_EVT uses the old role */
+ new_role = p->link_role;
+ }
+
+ /* Check if any SCO req is pending for role change */
+ btm_sco_chk_pend_rolechange (p->hci_handle);
+
+ /* if switching state is switching we need to turn encryption on */
+ /* if idle, we did not change encryption */
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_SWITCHING) {
+ if (btsnd_hcic_set_conn_encrypt (p->hci_handle, TRUE)) {
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_ON;
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_ON;
+ return;
+ }
+ }
+
+ /* Set the switch_role_state to IDLE since the reply received from HCI */
+ /* regardless of its result either success or failed. */
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_IN_PROGRESS) {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ }
+
+ /* if role switch complete is needed, report it now */
+ btm_acl_report_role_change(hci_status, bd_addr);
+
+ /* if role change event is registered, report it now */
+ if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_ROLE_CHG_MASK)) {
+ evt.event = BTM_BL_ROLE_CHG_EVT;
+ evt.new_role = new_role;
+ evt.p_bda = p_bda;
+ evt.hci_status = hci_status;
+ (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA *)&evt);
+ }
+
+ BTM_TRACE_DEBUG("Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, rs_st:%d\n",
+ p_data->role, p_data->hci_status, p->switch_role_state);
+
+#if BTM_DISC_DURING_RS == TRUE
+ /* If a disconnect is pending, issue it now that role switch has completed */
+ if ((p_dev_rec = btm_find_dev (p_bda)) != NULL) {
+ if (p_dev_rec->rs_disc_pending == BTM_SEC_DISC_PENDING) {
+ BTM_TRACE_WARNING("btm_acl_role_changed -> Issuing delayed HCI_Disconnect!!!\n");
+ btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER);
+ }
+ BTM_TRACE_ERROR("tBTM_SEC_DEV:0x%x rs_disc_pending=%d\n",
+ (UINT32)p_dev_rec, p_dev_rec->rs_disc_pending);
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+ }
+
+#endif
+
+}
+
+/*******************************************************************************
+**
+** Function BTM_AllocateSCN
+**
+** Description Look through the Server Channel Numbers for a free one.
+**
+** Returns Allocated SCN number or 0 if none.
+**
+*******************************************************************************/
+#if (CLASSIC_BT_INCLUDED == TRUE)
+UINT8 BTM_AllocateSCN(void)
+{
+ UINT8 x;
+ BTM_TRACE_DEBUG ("BTM_AllocateSCN\n");
+ for (x = 1; x < BTM_MAX_SCN; x++) {
+ if (!btm_cb.btm_scn[x - 1]) {
+ btm_cb.btm_scn[x - 1] = TRUE;
+ return x;
+ }
+ }
+ return (0); /* No free ports */
+}
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function BTM_TryAllocateSCN
+**
+** Description Try to allocate a fixed server channel
+**
+** Returns Returns TRUE if server channel was available
+**
+*******************************************************************************/
+#if (CLASSIC_BT_INCLUDED == TRUE)
+BOOLEAN BTM_TryAllocateSCN(UINT8 scn)
+{
+ if (scn >= BTM_MAX_SCN) {
+ return FALSE;
+ }
+
+ /* check if this port is available */
+ if (!btm_cb.btm_scn[scn - 1]) {
+ btm_cb.btm_scn[scn - 1] = TRUE;
+ return TRUE;
+ }
+
+ return (FALSE); /* Port was busy */
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_FreeSCN
+**
+** Description Free the specified SCN.
+**
+** Returns TRUE or FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_FreeSCN(UINT8 scn)
+{
+ BTM_TRACE_DEBUG ("BTM_FreeSCN \n");
+ if (scn <= BTM_MAX_SCN) {
+ btm_cb.btm_scn[scn - 1] = FALSE;
+ return (TRUE);
+ } else {
+ return (FALSE); /* Illegal SCN passed in */
+ }
+ return (FALSE);
+}
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_set_packet_types
+**
+** Description This function sets the packet types used for a specific
+** ACL connection. It is called internally by btm_acl_created
+** or by an application/profile by BTM_SetPacketTypes.
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS btm_set_packet_types (tACL_CONN *p, UINT16 pkt_types)
+{
+ UINT16 temp_pkt_types;
+ BTM_TRACE_DEBUG ("btm_set_packet_types\n");
+ /* Save in the ACL control blocks, types that we support */
+ temp_pkt_types = (pkt_types & BTM_ACL_SUPPORTED_PKTS_MASK &
+ btm_cb.btm_acl_pkt_types_supported);
+
+ /* OR in any exception packet types if at least 2.0 version of spec */
+ temp_pkt_types |= ((pkt_types & BTM_ACL_EXCEPTION_PKTS_MASK) |
+ (btm_cb.btm_acl_pkt_types_supported & BTM_ACL_EXCEPTION_PKTS_MASK));
+
+ /* Exclude packet types not supported by the peer */
+ btm_acl_chk_peer_pkt_type_support (p, &temp_pkt_types);
+
+ BTM_TRACE_DEBUG ("SetPacketType Mask -> 0x%04x\n", temp_pkt_types);
+
+ if (!btsnd_hcic_change_conn_type (p->hci_handle, temp_pkt_types)) {
+ return (BTM_NO_RESOURCES);
+ }
+
+ p->pkt_types_mask = temp_pkt_types;
+
+ return (BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+**
+** Function btm_get_max_packet_size
+**
+** Returns Returns maximum packet size that can be used for current
+** connection, 0 if connection is not established
+**
+*******************************************************************************/
+UINT16 btm_get_max_packet_size (BD_ADDR addr)
+{
+ tACL_CONN *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+ UINT16 pkt_types = 0;
+ UINT16 pkt_size = 0;
+ BTM_TRACE_DEBUG ("btm_get_max_packet_size\n");
+ if (p != NULL) {
+ pkt_types = p->pkt_types_mask;
+ } else {
+ /* Special case for when info for the local device is requested */
+ if (memcmp (controller_get_interface()->get_address(), addr, BD_ADDR_LEN) == 0) {
+ pkt_types = btm_cb.btm_acl_pkt_types_supported;
+ }
+ }
+
+ if (pkt_types) {
+ if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH5)) {
+ pkt_size = HCI_EDR3_DH5_PACKET_SIZE;
+ } else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH5)) {
+ pkt_size = HCI_EDR2_DH5_PACKET_SIZE;
+ } else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH3)) {
+ pkt_size = HCI_EDR3_DH3_PACKET_SIZE;
+ } else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH5) {
+ pkt_size = HCI_DH5_PACKET_SIZE;
+ } else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH3)) {
+ pkt_size = HCI_EDR2_DH3_PACKET_SIZE;
+ } else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM5) {
+ pkt_size = HCI_DM5_PACKET_SIZE;
+ } else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH3) {
+ pkt_size = HCI_DH3_PACKET_SIZE;
+ } else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM3) {
+ pkt_size = HCI_DM3_PACKET_SIZE;
+ } else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH1)) {
+ pkt_size = HCI_EDR3_DH1_PACKET_SIZE;
+ } else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH1)) {
+ pkt_size = HCI_EDR2_DH1_PACKET_SIZE;
+ } else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH1) {
+ pkt_size = HCI_DH1_PACKET_SIZE;
+ } else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM1) {
+ pkt_size = HCI_DM1_PACKET_SIZE;
+ }
+ }
+
+ return (pkt_size);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadRemoteVersion
+**
+** Returns If connected report peer device info
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadRemoteVersion (BD_ADDR addr, UINT8 *lmp_version,
+ UINT16 *manufacturer, UINT16 *lmp_sub_version)
+{
+ tACL_CONN *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+ BTM_TRACE_DEBUG ("BTM_ReadRemoteVersion\n");
+ if (p == NULL) {
+ return (BTM_UNKNOWN_ADDR);
+ }
+
+ if (lmp_version) {
+ *lmp_version = p->lmp_version;
+ }
+
+ if (manufacturer) {
+ *manufacturer = p->manufacturer;
+ }
+
+ if (lmp_sub_version) {
+ *lmp_sub_version = p->lmp_subversion;
+ }
+
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadRemoteFeatures
+**
+** Returns pointer to the remote supported features mask (8 bytes)
+**
+*******************************************************************************/
+UINT8 *BTM_ReadRemoteFeatures (BD_ADDR addr)
+{
+ tACL_CONN *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+ BTM_TRACE_DEBUG ("BTM_ReadRemoteFeatures\n");
+ if (p == NULL) {
+ return (NULL);
+ }
+
+ return (p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadRemoteExtendedFeatures
+**
+** Returns pointer to the remote extended features mask (8 bytes)
+** or NULL if bad page
+**
+*******************************************************************************/
+UINT8 *BTM_ReadRemoteExtendedFeatures (BD_ADDR addr, UINT8 page_number)
+{
+ tACL_CONN *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+ BTM_TRACE_DEBUG ("BTM_ReadRemoteExtendedFeatures\n");
+ if (p == NULL) {
+ return (NULL);
+ }
+
+ if (page_number > HCI_EXT_FEATURES_PAGE_MAX) {
+ BTM_TRACE_ERROR("Warning: BTM_ReadRemoteExtendedFeatures page %d unknown\n", page_number);
+ return NULL;
+ }
+
+ return (p->peer_lmp_features[page_number]);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadNumberRemoteFeaturesPages
+**
+** Returns number of features pages read from the remote device.
+**
+*******************************************************************************/
+UINT8 BTM_ReadNumberRemoteFeaturesPages (BD_ADDR addr)
+{
+ tACL_CONN *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+ BTM_TRACE_DEBUG ("BTM_ReadNumberRemoteFeaturesPages\n");
+ if (p == NULL) {
+ return (0);
+ }
+
+ return (p->num_read_pages);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadAllRemoteFeatures
+**
+** Returns pointer to all features of the remote (24 bytes).
+**
+*******************************************************************************/
+UINT8 *BTM_ReadAllRemoteFeatures (BD_ADDR addr)
+{
+ tACL_CONN *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+ BTM_TRACE_DEBUG ("BTM_ReadAllRemoteFeatures\n");
+ if (p == NULL) {
+ return (NULL);
+ }
+
+ return (p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]);
+}
+
+/*******************************************************************************
+**
+** Function BTM_RegBusyLevelNotif
+**
+** Description This function is called to register a callback to receive
+** busy level change events.
+**
+** Returns BTM_SUCCESS if successfully registered, otherwise error
+**
+*******************************************************************************/
+tBTM_STATUS BTM_RegBusyLevelNotif (tBTM_BL_CHANGE_CB *p_cb, UINT8 *p_level,
+ tBTM_BL_EVENT_MASK evt_mask)
+{
+ BTM_TRACE_DEBUG ("BTM_RegBusyLevelNotif\n");
+ if (p_level) {
+ *p_level = btm_cb.busy_level;
+ }
+
+ btm_cb.bl_evt_mask = evt_mask;
+
+ if (!p_cb) {
+ btm_cb.p_bl_changed_cb = NULL;
+ } else if (btm_cb.p_bl_changed_cb) {
+ return (BTM_BUSY);
+ } else {
+ btm_cb.p_bl_changed_cb = p_cb;
+ }
+
+ return (BTM_SUCCESS);
+}
+
+
+tBTM_STATUS BTM_RegAclLinkStatNotif(tBTM_ACL_LINK_STAT_CB *p_cb)
+{
+ BTM_TRACE_DEBUG ("BTM_RegAclLinkStatNotif\n");
+
+ if (!p_cb) {
+ btm_cb.p_acl_link_stat_cb = NULL;
+ } else if (btm_cb.p_acl_link_stat_cb) {
+ return BTM_BUSY;
+ } else {
+ btm_cb.p_acl_link_stat_cb = p_cb;
+ }
+
+ return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetQoS
+**
+** Description This function is called to setup QoS
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetQoS (BD_ADDR bd, FLOW_SPEC *p_flow, tBTM_CMPL_CB *p_cb)
+{
+ tACL_CONN *p = NULL;
+
+ BTM_TRACE_API ("BTM_SetQoS: BdAddr: %02x%02x%02x%02x%02x%02x\n",
+ bd[0], bd[1], bd[2],
+ bd[3], bd[4], bd[5]);
+
+ /* If someone already waiting on the version, do not allow another */
+ if (btm_cb.devcb.p_qossu_cmpl_cb) {
+ return (BTM_BUSY);
+ }
+
+ if ( (p = btm_bda_to_acl(bd, BT_TRANSPORT_BR_EDR)) != NULL) {
+ btu_start_timer (&btm_cb.devcb.qossu_timer, BTU_TTYPE_BTM_QOS, BTM_DEV_REPLY_TIMEOUT);
+ btm_cb.devcb.p_qossu_cmpl_cb = p_cb;
+
+ if (!btsnd_hcic_qos_setup (p->hci_handle, p_flow->qos_flags, p_flow->service_type,
+ p_flow->token_rate, p_flow->peak_bandwidth,
+ p_flow->latency, p_flow->delay_variation)) {
+ btm_cb.devcb.p_qossu_cmpl_cb = NULL;
+ btu_stop_timer(&btm_cb.devcb.qossu_timer);
+ return (BTM_NO_RESOURCES);
+ } else {
+ return (BTM_CMD_STARTED);
+ }
+ }
+
+ /* If here, no BD Addr found */
+ return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** Function btm_qos_setup_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the qos setup request.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_qos_setup_complete (UINT8 status, UINT16 handle, FLOW_SPEC *p_flow)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_qossu_cmpl_cb;
+ tBTM_QOS_SETUP_CMPL qossu;
+ BTM_TRACE_DEBUG ("btm_qos_setup_complete\n");
+ btu_stop_timer (&btm_cb.devcb.qossu_timer);
+
+ btm_cb.devcb.p_qossu_cmpl_cb = NULL;
+
+ if (p_cb) {
+ memset(&qossu, 0, sizeof(tBTM_QOS_SETUP_CMPL));
+ qossu.status = status;
+ qossu.handle = handle;
+ tACL_CONN *p = btm_handle_to_acl(handle);
+ if (p != NULL) {
+ memcpy (qossu.rem_bda, p->remote_addr, BD_ADDR_LEN);
+ }
+ if (p_flow != NULL) {
+ qossu.flow.qos_flags = p_flow->qos_flags;
+ qossu.flow.service_type = p_flow->service_type;
+ qossu.flow.token_rate = p_flow->token_rate;
+ qossu.flow.peak_bandwidth = p_flow->peak_bandwidth;
+ qossu.flow.latency = p_flow->latency;
+ qossu.flow.delay_variation = p_flow->delay_variation;
+ }
+ BTM_TRACE_DEBUG ("BTM: p_flow->delay_variation: 0x%02x\n",
+ qossu.flow.delay_variation);
+ (*p_cb)(&qossu);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_qos_setup_timeout
+**
+** Description This function processes a timeout.
+** Currently, we just report an error log
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_qos_setup_timeout (void *p_tle)
+{
+ BTM_TRACE_DEBUG ("%s\n", __func__);
+
+ btm_qos_setup_complete (HCI_ERR_HOST_TIMEOUT, 0, NULL);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadRSSI
+**
+** Description This function is called to read the link policy settings.
+** The address of link policy results are returned in the callback.
+** (tBTM_RSSI_RESULTS)
+**
+** Returns BTM_CMD_STARTED if successfully initiated or error code
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadRSSI (BD_ADDR remote_bda, tBT_TRANSPORT transport, tBTM_CMPL_CB *p_cb)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_API ("BTM_ReadRSSI: RemBdAddr: %02x%02x%02x%02x%02x%02x\n",
+ remote_bda[0], remote_bda[1], remote_bda[2],
+ remote_bda[3], remote_bda[4], remote_bda[5]);
+ tBTM_RSSI_RESULTS result;
+ /* If someone already waiting on the version, do not allow another */
+ if (btm_cb.devcb.p_rssi_cmpl_cb) {
+ result.status = BTM_BUSY;
+ (*p_cb)(&result);
+ return (BTM_BUSY);
+ }
+
+ p = btm_bda_to_acl(remote_bda, transport);
+ if (p != (tACL_CONN *)NULL) {
+ btu_start_timer (&btm_cb.devcb.rssi_timer, BTU_TTYPE_BTM_ACL,
+ BTM_DEV_REPLY_TIMEOUT);
+
+ btm_cb.devcb.p_rssi_cmpl_cb = p_cb;
+
+ if (!btsnd_hcic_read_rssi (p->hci_handle)) {
+ btm_cb.devcb.p_rssi_cmpl_cb = NULL;
+ btu_stop_timer (&btm_cb.devcb.rssi_timer);
+ result.status = BTM_NO_RESOURCES;
+ (*p_cb)(&result);
+ return (BTM_NO_RESOURCES);
+ } else {
+ return (BTM_CMD_STARTED);
+ }
+ }
+
+ /* If here, no BD Addr found */
+ return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadLinkQuality
+**
+** Description This function is called to read the link qulaity.
+** The value of the link quality is returned in the callback.
+** (tBTM_LINK_QUALITY_RESULTS)
+**
+** Returns BTM_CMD_STARTED if successfully initiated or error code
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadLinkQuality (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_API ("BTM_ReadLinkQuality: RemBdAddr: %02x%02x%02x%02x%02x%02x\n",
+ remote_bda[0], remote_bda[1], remote_bda[2],
+ remote_bda[3], remote_bda[4], remote_bda[5]);
+
+ /* If someone already waiting on the version, do not allow another */
+ if (btm_cb.devcb.p_lnk_qual_cmpl_cb) {
+ return (BTM_BUSY);
+ }
+
+ p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+ if (p != (tACL_CONN *)NULL) {
+ btu_start_timer (&btm_cb.devcb.lnk_quality_timer, BTU_TTYPE_BTM_ACL,
+ BTM_DEV_REPLY_TIMEOUT);
+ btm_cb.devcb.p_lnk_qual_cmpl_cb = p_cb;
+
+ if (!btsnd_hcic_get_link_quality (p->hci_handle)) {
+ btu_stop_timer (&btm_cb.devcb.lnk_quality_timer);
+ btm_cb.devcb.p_lnk_qual_cmpl_cb = NULL;
+ return (BTM_NO_RESOURCES);
+ } else {
+ return (BTM_CMD_STARTED);
+ }
+ }
+
+ /* If here, no BD Addr found */
+ return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadTxPower
+**
+** Description This function is called to read the current
+** TX power of the connection. The tx power level results
+** are returned in the callback.
+** (tBTM_RSSI_RESULTS)
+**
+** Returns BTM_CMD_STARTED if successfully initiated or error code
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadTxPower (BD_ADDR remote_bda, tBT_TRANSPORT transport, tBTM_CMPL_CB *p_cb)
+{
+ tACL_CONN *p;
+ BOOLEAN ret;
+#define BTM_READ_RSSI_TYPE_CUR 0x00
+#define BTM_READ_RSSI_TYPE_MAX 0X01
+
+ BTM_TRACE_API ("BTM_ReadTxPower: RemBdAddr: %02x%02x%02x%02x%02x%02x\n",
+ remote_bda[0], remote_bda[1], remote_bda[2],
+ remote_bda[3], remote_bda[4], remote_bda[5]);
+
+ /* If someone already waiting on the version, do not allow another */
+ if (btm_cb.devcb.p_tx_power_cmpl_cb) {
+ return (BTM_BUSY);
+ }
+
+ p = btm_bda_to_acl(remote_bda, transport);
+ if (p != (tACL_CONN *)NULL) {
+ btu_start_timer (&btm_cb.devcb.tx_power_timer, BTU_TTYPE_BTM_ACL,
+ BTM_DEV_REPLY_TIMEOUT);
+
+ btm_cb.devcb.p_tx_power_cmpl_cb = p_cb;
+
+#if BLE_INCLUDED == TRUE
+ if (p->transport == BT_TRANSPORT_LE) {
+ memcpy(btm_cb.devcb.read_tx_pwr_addr, remote_bda, BD_ADDR_LEN);
+ ret = btsnd_hcic_ble_read_adv_chnl_tx_power();
+ } else
+#endif
+ {
+ ret = btsnd_hcic_read_tx_power (p->hci_handle, BTM_READ_RSSI_TYPE_CUR);
+ }
+ if (!ret) {
+ btm_cb.devcb.p_tx_power_cmpl_cb = NULL;
+ btu_stop_timer (&btm_cb.devcb.tx_power_timer);
+ return (BTM_NO_RESOURCES);
+ } else {
+ return (BTM_CMD_STARTED);
+ }
+ }
+
+ /* If here, no BD Addr found */
+ return (BTM_UNKNOWN_ADDR);
+}
+
+tBTM_STATUS BTM_SetAclPktTypes(BD_ADDR remote_bda, UINT16 pkt_types, tBTM_CMPL_CB *p_cb)
+{
+#if CLASSIC_BT_INCLUDED == TRUE
+ tBTM_STATUS ret = BTM_UNKNOWN_ADDR;
+ tACL_CONN *p;
+ tBTM_SET_ACL_PKT_TYPES_RESULTS result;
+
+ /* If someone already waiting on the version, do not allow another */
+ if (btm_cb.devcb.p_set_acl_pkt_types_cmpl_cb) {
+ result.status = HCI_ERR_REPEATED_ATTEMPTS;
+ (*p_cb)(&result);
+ return (BTM_BUSY);;
+ }
+
+ p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+
+ if (p != (tACL_CONN *)NULL) {
+ btu_start_timer (&btm_cb.devcb.set_acl_pkt_types_timer, BTU_TTYPE_BTM_ACL,
+ BTM_DEV_REPLY_TIMEOUT);
+
+ btm_cb.devcb.p_set_acl_pkt_types_cmpl_cb = p_cb;
+ if (btm_set_packet_types(p, pkt_types) != BTM_CMD_STARTED) {
+ btm_cb.devcb.p_set_acl_pkt_types_cmpl_cb = NULL;
+ btu_stop_timer (&btm_cb.devcb.set_acl_pkt_types_timer);
+ result.status = HCI_ERR_MEMORY_FULL;
+ (*p_cb)(&result);
+ ret = BTM_NO_RESOURCES;
+ } else {
+ ret = BTM_CMD_STARTED;
+ }
+ }
+ /* If here, no BD Addr found */
+ return ret;
+#else
+ return BTM_NO_RESOURCES;
+#endif
+}
+
+void btm_acl_pkt_types_changed(UINT8 status, UINT16 handle, UINT16 pkt_types)
+{
+#if CLASSIC_BT_INCLUDED == TRUE
+ BTM_TRACE_DEBUG ("btm_acl_pkt_types_changed\n");
+ tACL_CONN *conn = NULL;
+ tBTM_SET_ACL_PKT_TYPES_RESULTS results;
+ btu_stop_timer (&btm_cb.devcb.set_acl_pkt_types_timer);
+
+ /* If there is a callback registered for packet types changed, call it */
+ if (btm_cb.devcb.p_set_acl_pkt_types_cmpl_cb) {
+ if (status == HCI_SUCCESS) {
+ results.status = BTM_SUCCESS;
+ } else {
+ results.status = BTM_BAD_VALUE_RET;
+ }
+ results.pkt_types = pkt_types;
+ /* Search through the list of active channels for the correct BD Addr */
+ if ((conn = btm_handle_to_acl(handle)) != NULL) {
+ memcpy(results.rem_bda, conn->remote_addr, BD_ADDR_LEN);
+ (*btm_cb.devcb.p_set_acl_pkt_types_cmpl_cb)(&results);
+ }
+ btm_cb.devcb.p_set_acl_pkt_types_cmpl_cb = NULL;
+ }
+#endif
+}
+
+#if (BLE_INCLUDED == TRUE)
+tBTM_STATUS BTM_BleReadAdvTxPower(tBTM_CMPL_CB *p_cb)
+{
+ BOOLEAN ret;
+ tBTM_TX_POWER_RESULTS result;
+ /* If someone already waiting on the version, do not allow another */
+ if (btm_cb.devcb.p_tx_power_cmpl_cb) {
+ result.status = BTM_BUSY;
+ (*p_cb)(&result);
+ return (BTM_BUSY);
+ }
+
+ btm_cb.devcb.p_tx_power_cmpl_cb = p_cb;
+ btu_start_timer (&btm_cb.devcb.tx_power_timer, BTU_TTYPE_BTM_ACL,
+ BTM_DEV_REPLY_TIMEOUT);
+ ret = btsnd_hcic_ble_read_adv_chnl_tx_power();
+
+ if(!ret) {
+ btm_cb.devcb.p_tx_power_cmpl_cb = NULL;
+ btu_stop_timer (&btm_cb.devcb.tx_power_timer);
+ result.status = BTM_NO_RESOURCES;
+ (*p_cb)(&result);
+ return (BTM_NO_RESOURCES);
+ } else {
+ return BTM_CMD_STARTED;
+ }
+}
+
+void BTM_BleGetWhiteListSize(uint16_t *length)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ if (p_cb->white_list_avail_size == 0) {
+ BTM_TRACE_WARNING("%s Whitelist full.", __func__);
+ }
+ *length = p_cb->white_list_avail_size;
+ return;
+}
+#endif ///BLE_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_read_tx_power_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the read tx power request.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_tx_power_complete (UINT8 *p, BOOLEAN is_ble)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_tx_power_cmpl_cb;
+ tBTM_TX_POWER_RESULTS results;
+ UINT16 handle;
+ tACL_CONN *p_acl_cb = NULL;
+ BTM_TRACE_DEBUG ("btm_read_tx_power_complete\n");
+ btu_stop_timer (&btm_cb.devcb.tx_power_timer);
+
+ /* If there was a callback registered for read rssi, call it */
+ btm_cb.devcb.p_tx_power_cmpl_cb = NULL;
+
+ if (p_cb) {
+ STREAM_TO_UINT8 (results.hci_status, p);
+
+ if (results.hci_status == HCI_SUCCESS) {
+ results.status = BTM_SUCCESS;
+
+ if (!is_ble) {
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT8 (results.tx_power, p);
+
+ /* Search through the list of active channels for the correct BD Addr */
+ p_acl_cb = btm_handle_to_acl(handle);
+ if (p_acl_cb) {
+ memcpy (results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN);
+ }
+ }
+#if BLE_INCLUDED == TRUE
+ else {
+ STREAM_TO_UINT8 (results.tx_power, p);
+ memcpy(results.rem_bda, btm_cb.devcb.read_tx_pwr_addr, BD_ADDR_LEN);
+ }
+#endif
+ BTM_TRACE_DEBUG ("BTM TX power Complete: tx_power %d, hci status 0x%02x\n",
+ results.tx_power, results.hci_status);
+ } else {
+ results.status = BTM_ERR_PROCESSING;
+ }
+
+ (*p_cb)(&results);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_read_rssi_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the read rssi request.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_rssi_complete (UINT8 *p)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_rssi_cmpl_cb;
+ tBTM_RSSI_RESULTS results;
+ UINT16 handle;
+ tACL_CONN *p_acl_cb = NULL;
+ BTM_TRACE_DEBUG ("btm_read_rssi_complete\n");
+ btu_stop_timer (&btm_cb.devcb.rssi_timer);
+
+ /* If there was a callback registered for read rssi, call it */
+ btm_cb.devcb.p_rssi_cmpl_cb = NULL;
+
+ if (p_cb) {
+ STREAM_TO_UINT8 (results.hci_status, p);
+
+ if (results.hci_status == HCI_SUCCESS) {
+ results.status = BTM_SUCCESS;
+
+ STREAM_TO_UINT16 (handle, p);
+
+ STREAM_TO_UINT8 (results.rssi, p);
+ BTM_TRACE_DEBUG ("BTM RSSI Complete: rssi %d, hci status 0x%02x\n",
+ results.rssi, results.hci_status);
+
+ /* Search through the list of active channels for the correct BD Addr */
+ p_acl_cb = btm_handle_to_acl(handle);
+ if (p_acl_cb) {
+ memcpy (results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN);
+ }
+ } else {
+ results.status = BTM_ERR_PROCESSING;
+ }
+
+ (*p_cb)(&results);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_read_link_quality_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the read link quality.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_link_quality_complete (UINT8 *p)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_lnk_qual_cmpl_cb;
+ tBTM_LINK_QUALITY_RESULTS results;
+ UINT16 handle;
+ tACL_CONN *p_acl_cb = NULL;
+ BTM_TRACE_DEBUG ("btm_read_link_quality_complete\n");
+ btu_stop_timer (&btm_cb.devcb.lnk_quality_timer);
+
+ /* If there was a callback registered for read rssi, call it */
+ btm_cb.devcb.p_lnk_qual_cmpl_cb = NULL;
+
+ if (p_cb) {
+ STREAM_TO_UINT8 (results.hci_status, p);
+
+ if (results.hci_status == HCI_SUCCESS) {
+ results.status = BTM_SUCCESS;
+
+ STREAM_TO_UINT16 (handle, p);
+
+ STREAM_TO_UINT8 (results.link_quality, p);
+ BTM_TRACE_DEBUG ("BTM Link Quality Complete: Link Quality %d, hci status 0x%02x\n",
+ results.link_quality, results.hci_status);
+
+ /* Search through the list of active channels for the correct BD Addr */
+ p_acl_cb = btm_handle_to_acl(handle);
+ if (p_acl_cb) {
+ memcpy (results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN);
+ }
+ } else {
+ results.status = BTM_ERR_PROCESSING;
+ }
+
+ (*p_cb)(&results);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_remove_acl
+**
+** Description This function is called to disconnect an ACL connection
+**
+** Returns BTM_SUCCESS if successfully initiated, otherwise BTM_NO_RESOURCES.
+**
+*******************************************************************************/
+tBTM_STATUS btm_remove_acl (BD_ADDR bd_addr, tBT_TRANSPORT transport)
+{
+ UINT16 hci_handle = BTM_GetHCIConnHandle(bd_addr, transport);
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ BTM_TRACE_DEBUG ("btm_remove_acl\n");
+#if BTM_DISC_DURING_RS == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+
+ /* Role Switch is pending, postpone until completed */
+ if (p_dev_rec && (p_dev_rec->rs_disc_pending == BTM_SEC_RS_PENDING)) {
+ p_dev_rec->rs_disc_pending = BTM_SEC_DISC_PENDING;
+ } else /* otherwise can disconnect right away */
+#endif
+ {
+ if (hci_handle != 0xFFFF && p_dev_rec &&
+ p_dev_rec->sec_state != BTM_SEC_STATE_DISCONNECTING) {
+ if (!btsnd_hcic_disconnect (hci_handle, HCI_ERR_PEER_USER)) {
+ status = BTM_NO_RESOURCES;
+ }
+ } else {
+ status = BTM_UNKNOWN_ADDR;
+ }
+ }
+
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetTraceLevel
+**
+** Description This function sets the trace level for BTM. If called with
+** a value of 0xFF, it simply returns the current trace level.
+**
+** Returns The new or current trace level
+**
+*******************************************************************************/
+UINT8 BTM_SetTraceLevel (UINT8 new_level)
+{
+ BTM_TRACE_DEBUG ("BTM_SetTraceLevel\n");
+ if (new_level != 0xFF) {
+ btm_cb.trace_level = new_level;
+ }
+
+ return (btm_cb.trace_level);
+}
+
+/*******************************************************************************
+**
+** Function btm_cont_rswitch
+**
+** Description This function is called to continue processing an active
+** role switch. It first disables encryption if enabled and
+** EPR is not supported
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_cont_rswitch (tACL_CONN *p, tBTM_SEC_DEV_REC *p_dev_rec,
+ UINT8 hci_status)
+{
+ BOOLEAN sw_ok = TRUE;
+ BTM_TRACE_DEBUG ("btm_cont_rswitch\n");
+ /* Check to see if encryption needs to be turned off if pending
+ change of link key or role switch */
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE) {
+ /* Must turn off Encryption first if necessary */
+ /* Some devices do not support switch or change of link key while encryption is on */
+ if (p_dev_rec != NULL && ((p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) != 0)
+ && !BTM_EPR_AVAILABLE(p)) {
+ if (btsnd_hcic_set_conn_encrypt (p->hci_handle, FALSE)) {
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF;
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE) {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF;
+ }
+ } else {
+ /* Error occurred; set states back to Idle */
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE) {
+ sw_ok = FALSE;
+ }
+ }
+ } else /* Encryption not used or EPR supported, continue with switch
+ and/or change of link key */
+ {
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE) {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IN_PROGRESS;
+#if BTM_DISC_DURING_RS == TRUE
+ if (p_dev_rec) {
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING;
+ }
+#endif
+ sw_ok = btsnd_hcic_switch_role (p->remote_addr, (UINT8)!p->link_role);
+ }
+ }
+
+ if (!sw_ok) {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+ btm_acl_report_role_change(hci_status, p->remote_addr);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_resubmit_page
+**
+** Description send pending page request
+**
+*******************************************************************************/
+void btm_acl_resubmit_page (void)
+{
+#if (SMP_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BT_HDR *p_buf;
+ UINT8 *pp;
+ BD_ADDR bda;
+ BTM_TRACE_DEBUG ("btm_acl_resubmit_page\n");
+ /* If there were other page request schedule can start the next one */
+ if ((p_buf = (BT_HDR *)fixed_queue_dequeue(btm_cb.page_queue, 0)) != NULL) {
+ /* skip 3 (2 bytes opcode and 1 byte len) to get to the bd_addr
+ * for both create_conn and rmt_name */
+ pp = (UINT8 *)(p_buf + 1) + p_buf->offset + 3;
+
+ STREAM_TO_BDADDR (bda, pp);
+
+ p_dev_rec = btm_find_or_alloc_dev (bda);
+
+ memcpy (btm_cb.connecting_bda, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ memcpy (btm_cb.connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p_buf);
+ } else {
+ btm_cb.paging = FALSE;
+ }
+#endif ///SMP_INCLUDED == TRUE
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_reset_paging
+**
+** Description set paging to FALSE and free the page queue - called at hci_reset
+**
+*******************************************************************************/
+void btm_acl_reset_paging (void)
+{
+ BT_HDR *p;
+ BTM_TRACE_DEBUG ("btm_acl_reset_paging\n");
+ /* If we sent reset we are definitely not paging any more */
+ while ((p = (BT_HDR *)fixed_queue_dequeue(btm_cb.page_queue, 0)) != NULL) {
+ osi_free (p);
+ }
+
+ btm_cb.paging = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_paging
+**
+** Description send a paging command or queue it in btm_cb
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE && CLASSIC_BT_INCLUDED == TRUE)
+void btm_acl_paging (BT_HDR *p, BD_ADDR bda)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_DEBUG ("btm_acl_paging discing:%d, paging:%d BDA: %06x%06x\n",
+ btm_cb.discing, btm_cb.paging,
+ (bda[0] << 16) + (bda[1] << 8) + bda[2], (bda[3] << 16) + (bda[4] << 8) + bda[5]);
+ if (btm_cb.discing) {
+ btm_cb.paging = TRUE;
+ fixed_queue_enqueue(btm_cb.page_queue, p, FIXED_QUEUE_MAX_TIMEOUT);
+ } else {
+ if (!BTM_ACL_IS_CONNECTED (bda)) {
+ BTM_TRACE_DEBUG ("connecting_bda: %06x%06x\n",
+ (btm_cb.connecting_bda[0] << 16) + (btm_cb.connecting_bda[1] << 8) +
+ btm_cb.connecting_bda[2],
+ (btm_cb.connecting_bda[3] << 16) + (btm_cb.connecting_bda[4] << 8) +
+ btm_cb.connecting_bda[5]);
+ if (btm_cb.paging &&
+ memcmp (bda, btm_cb.connecting_bda, BD_ADDR_LEN) != 0) {
+ fixed_queue_enqueue(btm_cb.page_queue, p, FIXED_QUEUE_MAX_TIMEOUT);
+ } else {
+ p_dev_rec = btm_find_or_alloc_dev (bda);
+ memcpy (btm_cb.connecting_bda, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ memcpy (btm_cb.connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ }
+
+ btm_cb.paging = TRUE;
+ } else { /* ACL is already up */
+ btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+ }
+ }
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_acl_notif_conn_collision
+**
+** Description Send connection collision event to upper layer if registered
+**
+** Returns TRUE if sent out to upper layer,
+** FALSE if no one needs the notification.
+**
+*******************************************************************************/
+BOOLEAN btm_acl_notif_conn_collision (BD_ADDR bda)
+{
+ tBTM_BL_EVENT_DATA evt_data;
+
+ /* Report possible collision to the upper layer. */
+ if (btm_cb.p_bl_changed_cb) {
+ BTM_TRACE_DEBUG ("btm_acl_notif_conn_collision: RemBdAddr: %02x%02x%02x%02x%02x%02x\n",
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+
+ evt_data.event = BTM_BL_COLLISION_EVT;
+ evt_data.conn.p_bda = bda;
+
+#if BLE_INCLUDED == TRUE
+ evt_data.conn.transport = BT_TRANSPORT_BR_EDR;
+ evt_data.conn.handle = BTM_INVALID_HCI_HANDLE;
+#endif
+ (*btm_cb.p_bl_changed_cb)(&evt_data);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_acl_chk_peer_pkt_type_support
+**
+** Description Check if peer supports requested packets
+**
+*******************************************************************************/
+void btm_acl_chk_peer_pkt_type_support (tACL_CONN *p, UINT16 *p_pkt_type)
+{
+ /* 3 and 5 slot packets? */
+ if (!HCI_3_SLOT_PACKETS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) {
+ *p_pkt_type &= ~(BTM_ACL_PKT_TYPES_MASK_DH3 + BTM_ACL_PKT_TYPES_MASK_DM3);
+ }
+
+ if (!HCI_5_SLOT_PACKETS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) {
+ *p_pkt_type &= ~(BTM_ACL_PKT_TYPES_MASK_DH5 + BTM_ACL_PKT_TYPES_MASK_DM5);
+ }
+
+ /* 2 and 3 MPS support? */
+ if (!HCI_EDR_ACL_2MPS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) {
+ /* Not supported. Add 'not_supported' mask for all 2MPS packet types */
+ *p_pkt_type |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH1 + BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 +
+ BTM_ACL_PKT_TYPES_MASK_NO_2_DH5);
+ }
+
+ if (!HCI_EDR_ACL_3MPS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) {
+ /* Not supported. Add 'not_supported' mask for all 3MPS packet types */
+ *p_pkt_type |= (BTM_ACL_PKT_TYPES_MASK_NO_3_DH1 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH3 +
+ BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+ }
+
+ /* EDR 3 and 5 slot support? */
+ if (HCI_EDR_ACL_2MPS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])
+ || HCI_EDR_ACL_3MPS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) {
+ if (!HCI_3_SLOT_EDR_ACL_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
+ /* Not supported. Add 'not_supported' mask for all 3-slot EDR packet types */
+ {
+ *p_pkt_type |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH3);
+ }
+
+ if (!HCI_5_SLOT_EDR_ACL_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
+ /* Not supported. Add 'not_supported' mask for all 5-slot EDR packet types */
+ {
+ *p_pkt_type |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH5 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_free
+**
+** Description Free acl specific lists from btm control block
+**
+*******************************************************************************/
+void btm_acl_free(void)
+{
+ list_free(btm_cb.p_acl_db_list);
+ list_free(btm_cb.p_pm_mode_db_list);
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_connected
+**
+** Description Handle ACL connection complete event
+**
+*******************************************************************************/
+void btm_acl_connected(BD_ADDR bda, UINT16 handle, UINT8 link_type, UINT8 enc_mode, UINT8 status)
+{
+#if BTM_SCO_INCLUDED == TRUE
+ tBTM_ESCO_DATA esco_data;
+#endif
+
+ if (link_type == HCI_LINK_TYPE_ACL) {
+#if SMP_INCLUDED == TRUE
+ btm_sec_connected (bda, handle, status, enc_mode);
+#endif /* SMP_INCLUDED == TRUE */
+ /* report acl connection result to upper layer */
+ do {
+ tBTM_ACL_LINK_STAT_EVENT_DATA evt_data = {
+ .event = BTM_ACL_CONN_CMPL_EVT,
+ .link_act.conn_cmpl.status = status,
+ .link_act.conn_cmpl.handle = handle,
+ };
+ bdcpy(evt_data.link_act.conn_cmpl.bd_addr, bda);
+ btm_acl_link_stat_report(&evt_data);
+ } while (0);
+
+ l2c_link_hci_conn_comp(status, handle, bda);
+ }
+#if BTM_SCO_INCLUDED == TRUE
+ else {
+ memset(&esco_data, 0, sizeof(tBTM_ESCO_DATA));
+ esco_data.link_type = HCI_LINK_TYPE_SCO;
+ memcpy (esco_data.bd_addr, bda, BD_ADDR_LEN);
+ btm_sco_connected(status, bda, handle, &esco_data);
+ }
+#endif /* BTM_SCO_INCLUDED == TRUE */
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_disconnected
+**
+** Description Handle ACL disconnection complete event
+**
+*******************************************************************************/
+void btm_acl_disconnected(UINT16 handle, UINT8 reason)
+{
+
+ /* Report BR/EDR ACL disconnection result to upper layer */
+ tACL_CONN *conn = btm_handle_to_acl(handle);
+ if (conn) {
+#if BLE_INCLUDED == TRUE
+ if (conn->transport == BT_TRANSPORT_BR_EDR)
+#endif
+ {
+ tBTM_ACL_LINK_STAT_EVENT_DATA evt_data = {
+ .event = BTM_ACL_DISCONN_CMPL_EVT,
+ .link_act.disconn_cmpl.reason = reason,
+ .link_act.disconn_cmpl.handle = handle,
+ };
+ bdcpy(evt_data.link_act.disconn_cmpl.bd_addr, conn->remote_addr);
+ btm_acl_link_stat_report(&evt_data);
+ }
+ }
+
+#if BTM_SCO_INCLUDED == TRUE
+ /* If L2CAP doesn't know about it, send it to SCO */
+ if (!l2c_link_hci_disc_comp (handle, reason)) {
+ btm_sco_removed (handle, reason);
+ }
+#else
+ l2c_link_hci_disc_comp(handle, reason);
+#endif /* BTM_SCO_INCLUDED */
+
+#if (SMP_INCLUDED == TRUE)
+ /* Notify security manager */
+ btm_sec_disconnected(handle, reason);
+#endif /* SMP_INCLUDED == TRUE */
+}
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_ble.c b/lib/bt/host/bluedroid/stack/btm/btm_ble.c
new file mode 100644
index 00000000..afa46b8a
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_ble.c
@@ -0,0 +1,2934 @@
+/******************************************************************************
+ *
+ * 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 functions for BLE device control utilities, and LE
+ * security functions.
+ *
+ ******************************************************************************/
+#include "common/bt_target.h"
+
+#include <string.h>
+
+#include "stack/bt_types.h"
+#include "stack/hcimsgs.h"
+#include "stack/btu.h"
+#include "btm_int.h"
+#include "stack/btm_ble_api.h"
+#include "stack/smp_api.h"
+#include "l2c_int.h"
+#include "stack/gap_api.h"
+//#include "bt_utils.h"
+#include "device/controller.h"
+
+//#define LOG_TAG "bt_btm_ble"
+//#include "osi/include/log.h"
+#if BLE_INCLUDED == TRUE
+extern void BTM_UpdateAddrInfor(uint8_t addr_type, BD_ADDR bda);
+#if SMP_INCLUDED == TRUE
+// The temp variable to pass parameter between functions when in the connected event callback.
+static BOOLEAN temp_enhanced = FALSE;
+extern BOOLEAN aes_cipher_msg_auth_code(BT_OCTET16 key, UINT8 *input, UINT16 length,
+ UINT16 tlen, UINT8 *p_signature);
+extern void smp_link_encrypted(BD_ADDR bda, UINT8 encr_enable);
+extern BOOLEAN smp_proc_ltk_request(BD_ADDR bda);
+#endif
+extern void gatt_notify_enc_cmpl(BD_ADDR bd_addr);
+/*******************************************************************************/
+/* External Function to be called by other modules */
+/*******************************************************************************/
+/********************************************************
+**
+** Function BTM_SecAddBleDevice
+**
+** Description Add/modify device. This function will be normally called
+** during host startup to restore all required information
+** for a LE device stored in the NVRAM.
+**
+** Parameters: bd_addr - BD address of the peer
+** bd_name - Name of the peer device. NULL if unknown.
+** dev_type - Remote device's device type.
+** addr_type - LE device address type.
+** auth_mode - auth mode
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+BOOLEAN BTM_SecAddBleDevice (BD_ADDR bd_addr, BD_NAME bd_name, tBT_DEVICE_TYPE dev_type,
+ tBLE_ADDR_TYPE addr_type, UINT32 auth_mode)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_INQ_INFO *p_info = NULL;
+
+ BTM_TRACE_DEBUG ("BTM_SecAddBleDevice dev_type=0x%x", dev_type);
+ p_dev_rec = btm_find_dev (bd_addr);
+
+ if (!p_dev_rec) {
+ BTM_TRACE_DEBUG("Add a new device");
+
+ /* There is no device record, allocate one.
+ * If we can not find an empty spot for this one, let it fail. */
+ if (list_length(btm_cb.p_sec_dev_rec_list) < BTM_SEC_MAX_DEVICE_RECORDS) {
+ p_dev_rec = (tBTM_SEC_DEV_REC *)osi_malloc(sizeof(tBTM_SEC_DEV_REC));
+ if(p_dev_rec) {
+ list_append(btm_cb.p_sec_dev_rec_list, p_dev_rec);
+ BTM_TRACE_DEBUG ("allocate a new dev rec idx=0x%x\n", list_length(btm_cb.p_sec_dev_rec_list));
+
+ /* Mark this record as in use and initialize */
+ memset (p_dev_rec, 0, sizeof (tBTM_SEC_DEV_REC));
+ p_dev_rec->sec_flags = BTM_SEC_IN_USE;
+ memcpy (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN);
+ p_dev_rec->hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_BR_EDR);
+ p_dev_rec->ble_hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_LE);
+
+ /* update conn params, use default value for background connection params */
+ p_dev_rec->conn_params.min_conn_int =
+ p_dev_rec->conn_params.max_conn_int =
+ p_dev_rec->conn_params.supervision_tout =
+ p_dev_rec->conn_params.slave_latency = BTM_BLE_CONN_PARAM_UNDEF;
+
+ BTM_TRACE_DEBUG ("hci_handl=0x%x ", p_dev_rec->ble_hci_handle );
+ }
+ }
+
+ if (!p_dev_rec) {
+ return (FALSE);
+ }
+ } else {
+ BTM_TRACE_DEBUG("Device already exist");
+ }
+
+ memset(p_dev_rec->sec_bd_name, 0, sizeof(tBTM_BD_NAME));
+
+ if (bd_name && bd_name[0]) {
+ p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
+ BCM_STRNCPY_S ((char *)p_dev_rec->sec_bd_name, (char *)bd_name, BTM_MAX_REM_BD_NAME_LEN);
+ }
+ p_dev_rec->device_type |= dev_type;
+ p_dev_rec->ble.ble_addr_type = addr_type;
+ p_dev_rec->ble.auth_mode = auth_mode;
+
+ memcpy (p_dev_rec->ble.pseudo_addr, bd_addr, BD_ADDR_LEN);
+ /* sync up with the Inq Data base*/
+ p_info = BTM_InqDbRead(bd_addr);
+ if (p_info) {
+ p_info->results.ble_addr_type = p_dev_rec->ble.ble_addr_type ;
+ p_info->results.device_type = p_dev_rec->device_type;
+ BTM_TRACE_DEBUG ("InqDb device_type =0x%x addr_type=0x%x",
+ p_info->results.device_type, p_info->results.ble_addr_type);
+ }
+ return (TRUE);
+}
+#endif ///SMP_INCLUDED == TRUE
+
+
+/*******************************************************************************
+**
+** Function BTM_SecAddBleKey
+**
+** Description Add/modify LE device information. This function will be
+** normally called during host startup to restore all required
+** information stored in the NVRAM.
+**
+** Parameters: bd_addr - BD address of the peer
+** p_le_key - LE key values.
+** key_type - LE SMP key type.
+*
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+#if SMP_INCLUDED == TRUE
+BOOLEAN BTM_SecAddBleKey (BD_ADDR bd_addr, tBTM_LE_KEY_VALUE *p_le_key, tBTM_LE_KEY_TYPE key_type)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BTM_TRACE_DEBUG ("BTM_SecAddBleKey");
+ p_dev_rec = btm_find_dev (bd_addr);
+ if (!p_dev_rec || !p_le_key ||
+ (key_type != BTM_LE_KEY_PENC && key_type != BTM_LE_KEY_PID &&
+ key_type != BTM_LE_KEY_PCSRK && key_type != BTM_LE_KEY_LENC &&
+ key_type != BTM_LE_KEY_LCSRK && key_type != BTM_LE_KEY_LID)) {
+ BTM_TRACE_WARNING ("BTM_SecAddBleKey() Wrong Type, or No Device record \
+ for bdaddr: %08x%04x, Type: %d",
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5], key_type);
+ return (FALSE);
+ }
+
+ BTM_TRACE_DEBUG ("BTM_SecAddLeKey() BDA: %08x%04x, Type: 0x%02x",
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5], key_type);
+
+ btm_sec_save_le_key (bd_addr, key_type, p_le_key, FALSE);
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ if (key_type == BTM_LE_KEY_PID || key_type == BTM_LE_KEY_LID) {
+ btm_ble_resolving_list_load_dev (p_dev_rec);
+ }
+#endif
+
+
+ return (TRUE);
+}
+#endif
+
+
+/*******************************************************************************
+**
+** Function BTM_BleLoadLocalKeys
+**
+** Description Local local identity key, encryption root or sign counter.
+**
+** Parameters: key_type: type of key, can be BTM_BLE_KEY_TYPE_ID, BTM_BLE_KEY_TYPE_ER
+** or BTM_BLE_KEY_TYPE_COUNTER.
+** p_key: pointer to the key.
+*
+** Returns non2.
+**
+*******************************************************************************/
+void BTM_BleLoadLocalKeys(UINT8 key_type, tBTM_BLE_LOCAL_KEYS *p_key)
+{
+ tBTM_DEVCB *p_devcb = &btm_cb.devcb;
+ BTM_TRACE_DEBUG ("%s", __func__);
+ if (p_key != NULL) {
+ switch (key_type) {
+ case BTM_BLE_KEY_TYPE_ID:
+ memcpy(&p_devcb->id_keys, &p_key->id_keys, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+ break;
+
+ case BTM_BLE_KEY_TYPE_ER:
+ memcpy(p_devcb->ble_encryption_key_value, p_key->er, sizeof(BT_OCTET16));
+ break;
+
+ default:
+ BTM_TRACE_ERROR("unknow local key type: %d", key_type);
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetDeviceEncRoot
+**
+** Description This function is called to read the local device encryption
+** root.
+**
+** Returns void
+** the local device ER is copied into ble_encr_key_value
+**
+*******************************************************************************/
+void BTM_GetDeviceEncRoot (BT_OCTET16 ble_encr_key_value)
+{
+ BTM_TRACE_DEBUG ("%s", __func__);
+ memcpy (ble_encr_key_value, btm_cb.devcb.ble_encryption_key_value, BT_OCTET16_LEN);
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetDeviceIDRoot
+**
+** Description This function is called to read the local device identity
+** root.
+**
+** Returns void
+** the local device IR is copied into irk
+**
+*******************************************************************************/
+void BTM_GetDeviceIDRoot (BT_OCTET16 irk)
+{
+ BTM_TRACE_DEBUG ("BTM_GetDeviceIDRoot ");
+
+ memcpy (irk, btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN);
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetDeviceDHK
+**
+** Description This function is called to read the local device DHK.
+**
+** Returns void
+** the local device DHK is copied into dhk
+**
+*******************************************************************************/
+void BTM_GetDeviceDHK (BT_OCTET16 dhk)
+{
+ BTM_TRACE_DEBUG ("BTM_GetDeviceDHK");
+ memcpy (dhk, btm_cb.devcb.id_keys.dhk, BT_OCTET16_LEN);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadConnectionAddr
+**
+** Description This function is called to get the local device address information
+** .
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_ReadConnectionAddr (BD_ADDR remote_bda, BD_ADDR local_conn_addr, tBLE_ADDR_TYPE *p_addr_type)
+{
+ tACL_CONN *p_acl = btm_bda_to_acl(remote_bda, BT_TRANSPORT_LE);
+
+ if (p_acl == NULL) {
+ BTM_TRACE_ERROR("No connection exist!");
+ return;
+ }
+ memcpy(local_conn_addr, p_acl->conn_addr, BD_ADDR_LEN);
+ * p_addr_type = p_acl->conn_addr_type;
+
+ BTM_TRACE_DEBUG ("BTM_ReadConnectionAddr address type: %d addr: 0x%02x",
+ p_acl->conn_addr_type, p_acl->conn_addr[0]);
+}
+
+/*******************************************************************************
+**
+** Function BTM_IsBleConnection
+**
+** Description This function is called to check if the connection handle
+** for an LE link
+**
+** Returns TRUE if connection is LE link, otherwise FALSE.
+**
+*******************************************************************************/
+BOOLEAN BTM_IsBleConnection (UINT16 conn_handle)
+{
+#if (BLE_INCLUDED == TRUE)
+ tACL_CONN *p;
+
+ BTM_TRACE_API ("BTM_IsBleConnection: conn_handle: %d", conn_handle);
+
+ p = btm_handle_to_acl(conn_handle);
+ if (!p) {
+ return FALSE;
+ }
+ return (p->transport == BT_TRANSPORT_LE);
+#else
+ return FALSE;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadRemoteConnectionAddr
+**
+** Description This function is read the remote device address currently used
+**
+** Parameters pseudo_addr: pseudo random address available
+** conn_addr:connection address used
+** p_addr_type : BD Address type, Public or Random of the address used
+**
+** Returns BOOLEAN , TRUE if connection to remote device exists, else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_ReadRemoteConnectionAddr(BD_ADDR pseudo_addr, BD_ADDR conn_addr,
+ tBLE_ADDR_TYPE *p_addr_type)
+{
+ BOOLEAN st = TRUE;
+#if (BLE_PRIVACY_SPT == TRUE)
+ tACL_CONN *p = btm_bda_to_acl (pseudo_addr, BT_TRANSPORT_LE);
+
+ if (p == NULL) {
+ BTM_TRACE_ERROR("BTM_ReadRemoteConnectionAddr can not find connection"
+ " with matching address");
+ return FALSE;
+ }
+
+ memcpy(conn_addr, p->active_remote_addr, BD_ADDR_LEN);
+ *p_addr_type = p->active_remote_addr_type;
+#else
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(pseudo_addr);
+
+ memcpy(conn_addr, pseudo_addr, BD_ADDR_LEN);
+ if (p_dev_rec != NULL) {
+ *p_addr_type = p_dev_rec->ble.ble_addr_type;
+ }
+#endif
+ return st;
+
+}
+/*******************************************************************************
+**
+** Function BTM_SecurityGrant
+**
+** Description This function is called to grant security process.
+**
+** Parameters bd_addr - peer device bd address.
+** res - result of the operation BTM_SUCCESS if success.
+** Otherwise, BTM_REPEATED_ATTEMPTS is too many attempts.
+**
+** Returns None
+**
+*******************************************************************************/
+void BTM_SecurityGrant(BD_ADDR bd_addr, UINT8 res)
+{
+#if SMP_INCLUDED == TRUE
+ tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_REPEATED_ATTEMPTS;
+ BTM_TRACE_DEBUG ("BTM_SecurityGrant");
+ SMP_SecurityGrant(bd_addr, res_smp);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_BlePasskeyReply
+**
+** Description This function is called after Security Manager submitted
+** passkey request to the application.
+**
+** Parameters: bd_addr - Address of the device for which passkey was requested
+** res - result of the operation BTM_SUCCESS if success
+** key_len - length in bytes of the Passkey
+** p_passkey - pointer to array with the passkey
+** trusted_mask - bitwise OR of trusted services (array of UINT32)
+**
+*******************************************************************************/
+void BTM_BlePasskeyReply (BD_ADDR bd_addr, UINT8 res, UINT32 passkey)
+{
+#if SMP_INCLUDED == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+ tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL;
+
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR("Passkey reply to Unknown device");
+ return;
+ }
+
+ p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED;
+ BTM_TRACE_DEBUG ("BTM_BlePasskeyReply");
+ SMP_PasskeyReply(bd_addr, res_smp, passkey);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleSetStaticPasskey
+**
+** Description This function is called to set static passkey
+**
+**
+** Parameters: add - set static passkey when add is TRUE
+** clear static passkey when add is FALSE
+** passkey - static passkey
+**
+**
+*******************************************************************************/
+void BTM_BleSetStaticPasskey(BOOLEAN add, UINT32 passkey)
+{
+#if SMP_INCLUDED == TRUE
+ SMP_SetStaticPasskey(add, passkey);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleConfirmReply
+**
+** Description This function is called after Security Manager submitted
+** numeric comparison request to the application.
+**
+** Parameters: bd_addr - Address of the device with which numeric
+** comparison was requested
+** res - comparison result BTM_SUCCESS if success
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+void BTM_BleConfirmReply (BD_ADDR bd_addr, UINT8 res)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+ tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL;
+
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR("Passkey reply to Unknown device");
+ return;
+ }
+
+ p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED;
+ BTM_TRACE_DEBUG ("%s\n", __func__);
+ SMP_ConfirmReply(bd_addr, res_smp);
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function BTM_BleOobDataReply
+**
+** Description This function is called to provide the OOB data for
+** SMP in response to BTM_LE_OOB_REQ_EVT
+**
+** Parameters: bd_addr - Address of the peer device
+** res - result of the operation SMP_SUCCESS if success
+** p_data - simple pairing Randomizer C.
+**
+*******************************************************************************/
+void BTM_BleOobDataReply(BD_ADDR bd_addr, UINT8 res, UINT8 len, UINT8 *p_data)
+{
+#if SMP_INCLUDED == TRUE
+ tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_OOB_FAIL;
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+
+ BTM_TRACE_DEBUG ("BTM_BleOobDataReply");
+
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR("BTM_BleOobDataReply() to Unknown device");
+ return;
+ }
+
+ p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED;
+ SMP_OobDataReply(bd_addr, res_smp, len, p_data);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleSecureConnectionOobDataReply
+**
+** Description This function is called to provide the OOB data for
+** SMP in response to BTM_LE_SC_OOB_REQ_EVT when secure connection
+**
+** Parameters: bd_addr - Address of the peer device
+** p_c - pointer to Confirmation
+** p_r - pointer to Randomizer
+**
+*******************************************************************************/
+void BTM_BleSecureConnectionOobDataReply(BD_ADDR bd_addr, UINT8 *p_c, UINT8 *p_r)
+{
+#if SMP_INCLUDED == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+
+ BTM_TRACE_DEBUG ("%s", __func__);
+
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR("%s Unknown device", __func__);
+ return;
+ }
+
+ p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED;
+
+ tSMP_SC_OOB_DATA oob;
+ memset(&oob, 0, sizeof(tSMP_SC_OOB_DATA));
+
+ oob.peer_oob_data.present = true;
+ memcpy(&oob.peer_oob_data.commitment, p_c, BT_OCTET16_LEN);
+ memcpy(&oob.peer_oob_data.randomizer, p_r, BT_OCTET16_LEN);
+ oob.peer_oob_data.addr_rcvd_from.type = p_dev_rec->ble.ble_addr_type;
+ memcpy(oob.peer_oob_data.addr_rcvd_from.bda, bd_addr, BD_ADDR_LEN);
+
+ SMP_SecureConnectionOobDataReply((UINT8 *)&oob);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleSecureConnectionCreateOobData
+**
+** Description This function is called to create the OOB data for
+** SMP when secure connection
+**
+*******************************************************************************/
+void BTM_BleSecureConnectionCreateOobData(void)
+{
+#if SMP_INCLUDED == TRUE
+ BTM_TRACE_DEBUG ("%s", __func__);
+
+ SMP_CreateLocalSecureConnectionsOobData();
+#endif
+}
+
+/******************************************************************************
+**
+** Function BTM_BleSetConnScanParams
+**
+** Description Set scan parameter used in BLE connection request
+**
+** Parameters: scan_interval: scan interval
+** scan_window: scan window
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleSetConnScanParams (UINT32 scan_interval, UINT32 scan_window)
+{
+#if SMP_INCLUDED == TRUE
+ tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb;
+ BOOLEAN new_param = FALSE;
+
+ if (BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN, BTM_BLE_SCAN_INT_MAX) &&
+ BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN, BTM_BLE_SCAN_WIN_MAX)) {
+ if (p_ble_cb->scan_int != scan_interval) {
+ p_ble_cb->scan_int = scan_interval;
+ new_param = TRUE;
+ }
+
+ if (p_ble_cb->scan_win != scan_window) {
+ p_ble_cb->scan_win = scan_window;
+ new_param = TRUE;
+ }
+
+ if (new_param && p_ble_cb->conn_state == BLE_BG_CONN) {
+ btm_ble_suspend_bg_conn();
+ }
+ } else {
+ BTM_TRACE_ERROR("Illegal Connection Scan Parameters");
+ }
+#endif
+}
+
+/********************************************************
+**
+** Function BTM_BleSetPrefConnParams
+**
+** Description Set a peripheral's preferred connection parameters
+**
+** Parameters: bd_addr - BD address of the peripheral
+** scan_interval: scan interval
+** scan_window: scan window
+** min_conn_int - minimum preferred connection interval
+** max_conn_int - maximum preferred connection interval
+** slave_latency - preferred slave latency
+** supervision_tout - preferred supervision timeout
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleSetPrefConnParams (BD_ADDR bd_addr,
+ UINT16 min_conn_int, UINT16 max_conn_int,
+ UINT16 slave_latency, UINT16 supervision_tout)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (bd_addr);
+
+ BTM_TRACE_API ("BTM_BleSetPrefConnParams min: %u max: %u latency: %u \
+ tout: %u",
+ min_conn_int, max_conn_int, slave_latency, supervision_tout);
+
+ if (BTM_BLE_ISVALID_PARAM(min_conn_int, BTM_BLE_CONN_INT_MIN, BTM_BLE_CONN_INT_MAX) &&
+ BTM_BLE_ISVALID_PARAM(max_conn_int, BTM_BLE_CONN_INT_MIN, BTM_BLE_CONN_INT_MAX) &&
+ BTM_BLE_ISVALID_PARAM(supervision_tout, BTM_BLE_CONN_SUP_TOUT_MIN, BTM_BLE_CONN_SUP_TOUT_MAX) &&
+ (slave_latency <= BTM_BLE_CONN_LATENCY_MAX || slave_latency == BTM_BLE_CONN_PARAM_UNDEF)) {
+ if (p_dev_rec) {
+ /* expect conn int and stout and slave latency to be updated all together */
+ if (min_conn_int != BTM_BLE_CONN_PARAM_UNDEF || max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) {
+ if (min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) {
+ p_dev_rec->conn_params.min_conn_int = min_conn_int;
+ } else {
+ p_dev_rec->conn_params.min_conn_int = max_conn_int;
+ }
+
+ if (max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) {
+ p_dev_rec->conn_params.max_conn_int = max_conn_int;
+ } else {
+ p_dev_rec->conn_params.max_conn_int = min_conn_int;
+ }
+
+ if (slave_latency != BTM_BLE_CONN_PARAM_UNDEF) {
+ p_dev_rec->conn_params.slave_latency = slave_latency;
+ } else {
+ p_dev_rec->conn_params.slave_latency = BTM_BLE_CONN_SLAVE_LATENCY_DEF;
+ }
+
+ if (supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) {
+ p_dev_rec->conn_params.supervision_tout = supervision_tout;
+ } else {
+ p_dev_rec->conn_params.supervision_tout = BTM_BLE_CONN_TIMEOUT_DEF;
+ }
+
+ }
+
+ } else {
+ BTM_TRACE_ERROR("Unknown Device, setting rejected");
+ }
+ } else {
+ BTM_TRACE_ERROR("Illegal Connection Parameters");
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadDevInfo
+**
+** Description This function is called to read the device/address type
+** of BD address.
+**
+** Parameter remote_bda: remote device address
+** p_dev_type: output parameter to read the device type.
+** p_addr_type: output parameter to read the address type.
+**
+*******************************************************************************/
+void BTM_ReadDevInfo (BD_ADDR remote_bda, tBT_DEVICE_TYPE *p_dev_type, tBLE_ADDR_TYPE *p_addr_type)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (remote_bda);
+ tBTM_INQ_INFO *p_inq_info = BTM_InqDbRead(remote_bda);
+ tBLE_ADDR_TYPE temp_addr_type = (*p_addr_type);
+
+ *p_addr_type = BLE_ADDR_PUBLIC;
+
+ if (!p_dev_rec) {
+ *p_dev_type = BT_DEVICE_TYPE_BREDR;
+ /* Check with the BT manager if details about remote device are known */
+ if (p_inq_info != NULL) {
+ *p_dev_type = p_inq_info->results.device_type ;
+ *p_addr_type = p_inq_info->results.ble_addr_type;
+ } else {
+ if(temp_addr_type <= BLE_ADDR_TYPE_MAX) {
+ *p_addr_type = temp_addr_type;
+ } else {
+ /* unknown device, assume BR/EDR */
+ BTM_TRACE_DEBUG ("btm_find_dev_type - unknown device, BR/EDR assumed");
+ }
+ }
+ } else { /* there is a security device record exisitng */
+ /* new inquiry result, overwrite device type in security device record */
+ if (p_inq_info) {
+ p_dev_rec->device_type = p_inq_info->results.device_type;
+ p_dev_rec->ble.ble_addr_type = p_inq_info->results.ble_addr_type;
+ }
+ if (memcmp(p_dev_rec->bd_addr, remote_bda, BD_ADDR_LEN) == 0 &&
+ memcmp(p_dev_rec->ble.pseudo_addr, remote_bda, BD_ADDR_LEN) == 0) {
+ *p_dev_type = p_dev_rec->device_type;
+ *p_addr_type = p_dev_rec->ble.ble_addr_type;
+ } else if (memcmp(p_dev_rec->ble.pseudo_addr, remote_bda, BD_ADDR_LEN) == 0) {
+ *p_dev_type = BT_DEVICE_TYPE_BLE;
+ *p_addr_type = p_dev_rec->ble.ble_addr_type;
+ } else { /* matching static adddress only */
+ *p_dev_type = BT_DEVICE_TYPE_BREDR;
+ *p_addr_type = BLE_ADDR_PUBLIC;
+ }
+
+ }
+
+ BTM_TRACE_DEBUG ("btm_find_dev_type - device_type = %d addr_type = %d", *p_dev_type , *p_addr_type);
+}
+#endif ///BLE_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function BTM_ReadConnectedTransportAddress
+**
+** Description This function is called to read the paired device/address type of other device paired
+** corresponding to the BD_address
+**
+** Parameter remote_bda: remote device address, carry out the transport address
+** transport: active transport
+**
+** Return TRUE if an active link is identified; FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN BTM_ReadConnectedTransportAddress(BD_ADDR remote_bda, tBT_TRANSPORT transport)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(remote_bda);
+
+ /* if no device can be located, return */
+ if (p_dev_rec == NULL) {
+ memset(remote_bda, 0, BD_ADDR_LEN);
+ return FALSE;
+ }
+
+ if (transport == BT_TRANSPORT_BR_EDR) {
+ if (btm_bda_to_acl(p_dev_rec->bd_addr, transport) != NULL) {
+ memcpy(remote_bda, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ return TRUE;
+ } else if (p_dev_rec->device_type & BT_DEVICE_TYPE_BREDR) {
+ memcpy(remote_bda, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ } else {
+ memset(remote_bda, 0, BD_ADDR_LEN);
+ }
+ return FALSE;
+ }
+#if (BLE_INCLUDED == TRUE)
+ if (transport == BT_TRANSPORT_LE) {
+ memcpy(remote_bda, p_dev_rec->ble.pseudo_addr, BD_ADDR_LEN);
+ if (btm_bda_to_acl(p_dev_rec->ble.pseudo_addr, transport) != NULL) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+#endif ///BLE_INCLUDED == TRUE
+ return FALSE;
+}
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function BTM_BleReceiverTest
+**
+** Description This function is called to start the LE Receiver test
+**
+** Parameter rx_freq - Frequency Range
+** p_cmd_cmpl_cback - Command Complete callback
+**
+*******************************************************************************/
+void BTM_BleReceiverTest(UINT8 rx_freq, tBTM_CMPL_CB *p_cmd_cmpl_cback)
+{
+ btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
+
+ if (btsnd_hcic_ble_receiver_test(rx_freq) == FALSE) {
+ BTM_TRACE_ERROR("%s: Unable to Trigger LE receiver test", __FUNCTION__);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleTransmitterTest
+**
+** Description This function is called to start the LE Transmitter test
+**
+** Parameter tx_freq - Frequency Range
+** test_data_len - Length in bytes of payload data in each packet
+** packet_payload - Pattern to use in the payload
+** p_cmd_cmpl_cback - Command Complete callback
+**
+*******************************************************************************/
+void BTM_BleTransmitterTest(UINT8 tx_freq, UINT8 test_data_len,
+ UINT8 packet_payload, tBTM_CMPL_CB *p_cmd_cmpl_cback)
+{
+ btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
+ if (btsnd_hcic_ble_transmitter_test(tx_freq, test_data_len, packet_payload) == FALSE) {
+ BTM_TRACE_ERROR("%s: Unable to Trigger LE transmitter test", __FUNCTION__);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleTestEnd
+**
+** Description This function is called to stop the in-progress TX or RX test
+**
+** Parameter p_cmd_cmpl_cback - Command complete callback
+**
+*******************************************************************************/
+void BTM_BleTestEnd(tBTM_CMPL_CB *p_cmd_cmpl_cback)
+{
+ btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
+
+ if (btsnd_hcic_ble_test_end() == FALSE) {
+ BTM_TRACE_ERROR("%s: Unable to End the LE TX/RX test", __FUNCTION__);
+ }
+}
+
+/*******************************************************************************
+** Internal Functions
+*******************************************************************************/
+void btm_ble_test_command_complete(UINT8 *p)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_le_test_cmd_cmpl_cb;
+
+ btm_cb.devcb.p_le_test_cmd_cmpl_cb = NULL;
+
+ if (p_cb) {
+ (*p_cb)(p);
+ }
+}
+
+
+#if (BLE_50_FEATURE_SUPPORT == TRUE)
+/*******************************************************************************
+**
+** Function BTM_BleEnhancedReceiverTest
+**
+** Description This function is called to start the LE Enhanced Receiver test
+**
+** Parameter rx_freq - Frequency Range
+** phy - The type of phy that receives data
+** modulation_index - modulation index
+** p_cmd_cmpl_cback - Command Complete callback
+**
+*******************************************************************************/
+void BTM_BleEnhancedReceiverTest(UINT8 rx_freq, UINT8 phy, UINT8 modulation_index, tBTM_CMPL_CB *p_cmd_cmpl_cback)
+{
+ btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
+
+ if (btsnd_hcic_ble_enhand_rx_test(rx_freq, phy, modulation_index) == FALSE) {
+ BTM_TRACE_ERROR("%s: Unable to Trigger LE enhanced receiver test", __FUNCTION__);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleEnhancedTransmitterTest
+**
+** Description This function is called to start the LE Enhanced Transmitter test
+**
+** Parameter tx_freq - Frequency Range
+** test_data_len - Length in bytes of payload data in each packet
+** packet_payload - Pattern to use in the payload
+** phy - The type of phy that sends data
+** p_cmd_cmpl_cback - Command Complete callback
+**
+*******************************************************************************/
+void BTM_BleEnhancedTransmitterTest(UINT8 tx_freq, UINT8 test_data_len,
+ UINT8 packet_payload, UINT8 phy, tBTM_CMPL_CB *p_cmd_cmpl_cback)
+{
+ btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
+ if (btsnd_hcic_ble_enhand_tx_test(tx_freq, test_data_len, packet_payload, phy) == FALSE) {
+ BTM_TRACE_ERROR("%s: Unable to Trigger LE enhanced transmitter test", __FUNCTION__);
+ }
+}
+#endif // BLE_50_FEATURE_SUPPORT
+
+/*******************************************************************************
+**
+** Function BTM_UseLeLink
+**
+** Description This function is to select the underneath physical link to use.
+**
+** Returns TRUE to use LE, FALSE use BR/EDR.
+**
+*******************************************************************************/
+BOOLEAN BTM_UseLeLink (BD_ADDR bd_addr)
+{
+ tACL_CONN *p;
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type = 0;
+ BOOLEAN use_le = FALSE;
+
+ if ((p = btm_bda_to_acl(bd_addr, BT_TRANSPORT_BR_EDR)) != NULL) {
+ return use_le;
+ } else if ((p = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE)) != NULL) {
+ use_le = TRUE;
+ } else {
+ BTM_ReadDevInfo(bd_addr, &dev_type, &addr_type);
+ use_le = (dev_type == BT_DEVICE_TYPE_BLE);
+ }
+ return use_le;
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetBleDataLength
+**
+** Description This function is to set maximum BLE transmission packet size
+**
+** Returns BTM_SUCCESS if success; otherwise failed.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetBleDataLength(BD_ADDR bd_addr, UINT16 tx_pdu_length)
+{
+ tACL_CONN *p_acl = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE);
+
+ BTM_TRACE_DEBUG("%s: tx_pdu_length =%d", __FUNCTION__, tx_pdu_length);
+
+ if (!controller_get_interface()->supports_ble_packet_extension()) {
+ BTM_TRACE_ERROR("%s failed, request not supported", __FUNCTION__);
+ return BTM_CONTROL_LE_DATA_LEN_UNSUPPORTED;
+ }
+
+ if (p_acl != NULL) {
+ if (!HCI_LE_DATA_LEN_EXT_SUPPORTED(p_acl->peer_le_features)) {
+ BTM_TRACE_ERROR("%s failed, peer does not support request", __FUNCTION__);
+ return BTM_PEER_LE_DATA_LEN_UNSUPPORTED;
+ }
+
+ if (tx_pdu_length > BTM_BLE_DATA_SIZE_MAX) {
+ tx_pdu_length = BTM_BLE_DATA_SIZE_MAX;
+ } else if (tx_pdu_length < BTM_BLE_DATA_SIZE_MIN) {
+ tx_pdu_length = BTM_BLE_DATA_SIZE_MIN;
+ }
+
+ /* always set the TxTime to be max, as controller does not care for now */
+ btsnd_hcic_ble_set_data_length(p_acl->hci_handle, tx_pdu_length,
+ BTM_BLE_DATA_TX_TIME_MAX);
+
+ return BTM_SUCCESS;
+ } else {
+ BTM_TRACE_ERROR("%s: Wrong mode: no LE link exist or LE not supported", __FUNCTION__);
+ return BTM_WRONG_MODE;
+ }
+}
+
+#if (SMP_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function btm_ble_determine_security_act
+**
+** Description This function checks the security of current LE link
+** and returns the appropriate action that needs to be
+** taken to achieve the required security.
+**
+** Parameter is_originator - True if outgoing connection
+** bdaddr: remote device address
+** security_required: Security required for the service.
+**
+** Returns The appropriate security action required.
+**
+*******************************************************************************/
+tBTM_SEC_ACTION btm_ble_determine_security_act(BOOLEAN is_originator, BD_ADDR bdaddr, UINT16 security_required)
+{
+ tBTM_LE_AUTH_REQ auth_req = 0x00;
+
+ if (is_originator)
+ {
+ if ((security_required & BTM_SEC_OUT_FLAGS) == 0 &&
+ (security_required & BTM_SEC_OUT_MITM) == 0)
+ {
+ BTM_TRACE_DEBUG ("%s No security required for outgoing connection", __func__);
+ return BTM_SEC_OK;
+ }
+
+ if (security_required & BTM_SEC_OUT_MITM) {
+ auth_req |= BTM_LE_AUTH_REQ_MITM;
+ }
+ }
+ else
+ {
+ if ((security_required & BTM_SEC_IN_FLAGS) == 0&& (security_required & BTM_SEC_IN_MITM) == 0)
+ {
+ BTM_TRACE_DEBUG ("%s No security required for incoming connection", __func__);
+ return BTM_SEC_OK;
+ }
+
+ if (security_required & BTM_SEC_IN_MITM) {
+ auth_req |= BTM_LE_AUTH_REQ_MITM;
+ }
+ }
+
+ tBTM_BLE_SEC_REQ_ACT ble_sec_act = BTM_BLE_SEC_REQ_ACT_NONE;
+ btm_ble_link_sec_check(bdaddr, auth_req, &ble_sec_act);
+
+ BTM_TRACE_DEBUG ("%s ble_sec_act %d", __func__ , ble_sec_act);
+
+ if (ble_sec_act == BTM_BLE_SEC_REQ_ACT_DISCARD) {
+ return BTM_SEC_ENC_PENDING;
+ }
+
+ if (ble_sec_act == BTM_BLE_SEC_REQ_ACT_NONE) {
+ return BTM_SEC_OK;
+ }
+
+ UINT8 sec_flag = 0;
+ BTM_GetSecurityFlagsByTransport(bdaddr, &sec_flag, BT_TRANSPORT_LE);
+
+ BOOLEAN is_link_encrypted = FALSE;
+ BOOLEAN is_key_mitm = FALSE;
+ if (sec_flag & (BTM_SEC_FLAG_ENCRYPTED| BTM_SEC_FLAG_LKEY_KNOWN))
+ {
+ if (sec_flag & BTM_SEC_FLAG_ENCRYPTED) {
+ is_link_encrypted = TRUE;
+ }
+
+ if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) {
+ is_key_mitm = TRUE;
+ }
+ }
+
+ if (auth_req & BTM_LE_AUTH_REQ_MITM)
+ {
+ if (!is_key_mitm)
+ {
+ return BTM_SEC_ENCRYPT_MITM;
+ } else {
+ if (is_link_encrypted) {
+ return BTM_SEC_OK;
+ } else {
+ return BTM_SEC_ENCRYPT;
+ }
+ }
+ } else {
+ if (is_link_encrypted) {
+ return BTM_SEC_OK;
+ } else {
+ return BTM_SEC_ENCRYPT_NO_MITM;
+ }
+ }
+
+ return BTM_SEC_OK;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_start_sec_check
+**
+** Description This function is to check and set the security required for
+** LE link for LE COC.
+**
+** Parameter bdaddr: remote device address.
+** psm : PSM of the LE COC sevice.
+** is_originator: TRUE if outgoing connection.
+** p_callback : Pointer to the callback function.
+** p_ref_data : Pointer to be returned along with the callback.
+**
+** Returns TRUE if link already meets the required security; otherwise FALSE.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_start_sec_check(BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_originator,
+ tBTM_SEC_CALLBACK *p_callback, void *p_ref_data)
+{
+ /* Find the service record for the PSM */
+ tBTM_SEC_SERV_REC *p_serv_rec = btm_sec_find_first_serv (is_originator, psm);
+
+ /* If there is no application registered with this PSM do not allow connection */
+ if (!p_serv_rec)
+ {
+ BTM_TRACE_WARNING ("%s PSM: %d no application registerd", __func__, psm);
+ (*p_callback) (bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_MODE_UNSUPPORTED);
+ return FALSE;
+ }
+
+ tBTM_SEC_ACTION sec_act = btm_ble_determine_security_act(is_originator,
+ bd_addr, p_serv_rec->security_flags);
+
+ tBTM_BLE_SEC_ACT ble_sec_act = BTM_BLE_SEC_NONE;
+ BOOLEAN status = FALSE;
+
+ switch (sec_act)
+ {
+ case BTM_SEC_OK:
+ BTM_TRACE_DEBUG ("%s Security met", __func__);
+ p_callback(bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_SUCCESS);
+ status = TRUE;
+ break;
+
+ case BTM_SEC_ENCRYPT:
+ BTM_TRACE_DEBUG ("%s Encryption needs to be done", __func__);
+ ble_sec_act = BTM_BLE_SEC_ENCRYPT;
+ break;
+
+ case BTM_SEC_ENCRYPT_MITM:
+ BTM_TRACE_DEBUG ("%s Pairing with MITM needs to be done", __func__);
+ ble_sec_act = BTM_BLE_SEC_ENCRYPT_MITM;
+ break;
+
+ case BTM_SEC_ENCRYPT_NO_MITM:
+ BTM_TRACE_DEBUG ("%s Pairing with No MITM needs to be done", __func__);
+ ble_sec_act = BTM_BLE_SEC_ENCRYPT_NO_MITM;
+ break;
+
+ case BTM_SEC_ENC_PENDING:
+ BTM_TRACE_DEBUG ("%s Ecryption pending", __func__);
+ break;
+ }
+
+ if (ble_sec_act == BTM_BLE_SEC_NONE) {
+ return status;
+ }
+
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
+ p_lcb->sec_act = sec_act;
+ BTM_SetEncryption(bd_addr, BT_TRANSPORT_LE, p_callback, p_ref_data);
+
+ return FALSE;
+}
+
+
+/*******************************************************************************
+**
+** Function btm_ble_rand_enc_complete
+**
+** Description This function is the callback functions for HCI_Rand command
+** and HCI_Encrypt command is completed.
+** This message is received from the HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_rand_enc_complete (UINT8 *p, UINT16 op_code, tBTM_RAND_ENC_CB *p_enc_cplt_cback)
+{
+ tBTM_RAND_ENC params;
+ UINT8 *p_dest = params.param_buf;
+
+ BTM_TRACE_DEBUG ("btm_ble_rand_enc_complete");
+
+ memset(&params, 0, sizeof(tBTM_RAND_ENC));
+
+ /* If there was a callback address for vcs complete, call it */
+ if (p_enc_cplt_cback && p) {
+ /* Pass paramters to the callback function */
+ STREAM_TO_UINT8(params.status, p); /* command status */
+
+ if (params.status == HCI_SUCCESS) {
+ params.opcode = op_code;
+
+ if (op_code == HCI_BLE_RAND) {
+ params.param_len = BT_OCTET8_LEN;
+ } else {
+ params.param_len = BT_OCTET16_LEN;
+ }
+
+ memcpy(p_dest, p, params.param_len); /* Fetch return info from HCI event message */
+ }
+ if (p_enc_cplt_cback) {
+ (*p_enc_cplt_cback)(&params); /* Call the Encryption complete callback function */
+ }
+ }
+}
+#endif ///SMP_INCLUDED == TRUE
+
+
+/*******************************************************************************
+**
+** Function btm_ble_get_enc_key_type
+**
+** Description This function is to increment local sign counter
+** Returns None
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+void btm_ble_increment_sign_ctr(BD_ADDR bd_addr, BOOLEAN is_local )
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_DEBUG ("btm_ble_increment_sign_ctr is_local=%d", is_local);
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL) {
+ if (is_local) {
+ p_dev_rec->ble.keys.local_counter++;
+ } else {
+ p_dev_rec->ble.keys.counter++;
+ }
+ BTM_TRACE_DEBUG ("is_local=%d local sign counter=%d peer sign counter=%d",
+ is_local,
+ p_dev_rec->ble.keys.local_counter,
+ p_dev_rec->ble.keys.counter);
+ }
+}
+#endif ///SMP_INCLUDED == TRUE
+#endif ///BLE_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_ble_get_enc_key_type
+**
+** Description This function is to get the BLE key type that has been exchanged
+** in betweem local device and peer device.
+**
+** Returns p_key_type: output parameter to carry the key type value.
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+#if (BLE_INCLUDED == TRUE)
+BOOLEAN btm_ble_get_enc_key_type(BD_ADDR bd_addr, UINT8 *p_key_types)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_DEBUG ("btm_ble_get_enc_key_type");
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL) {
+ *p_key_types = p_dev_rec->ble.key_type;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btm_get_local_div
+**
+** Description This function is called to read the local DIV
+**
+** Returns TRUE - if a valid DIV is availavle
+*******************************************************************************/
+BOOLEAN btm_get_local_div (BD_ADDR bd_addr, UINT16 *p_div)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BOOLEAN status = FALSE;
+ BTM_TRACE_DEBUG ("btm_get_local_div");
+
+ BTM_TRACE_DEBUG("bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0], bd_addr[1],
+ bd_addr[2], bd_addr[3],
+ bd_addr[4], bd_addr[5]);
+
+ *p_div = 0;
+ p_dev_rec = btm_find_dev (bd_addr);
+
+ if (p_dev_rec && p_dev_rec->ble.keys.div) {
+ status = TRUE;
+ *p_div = p_dev_rec->ble.keys.div;
+ }
+ BTM_TRACE_DEBUG ("btm_get_local_div status=%d (1-OK) DIV=0x%x", status, *p_div);
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_save_le_key
+**
+** Description This function is called by the SMP to update
+** an BLE key. SMP is internal, whereas all the keys shall
+** be sent to the application. The function is also called
+** when application passes ble key stored in NVRAM to the btm_sec.
+** pass_to_application parameter is false in this case.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY_VALUE *p_keys,
+ BOOLEAN pass_to_application)
+{
+ tBTM_SEC_DEV_REC *p_rec;
+ tBTM_LE_EVT_DATA cb_data;
+ UINT8 i;
+
+ BTM_TRACE_DEBUG ("btm_sec_save_le_key key_type=0x%x pass_to_application=%d", key_type, pass_to_application);
+ /* Store the updated key in the device database */
+
+ BTM_TRACE_DEBUG("bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0], bd_addr[1],
+ bd_addr[2], bd_addr[3],
+ bd_addr[4], bd_addr[5]);
+
+ if ((p_rec = btm_find_dev (bd_addr)) != NULL && (p_keys || key_type == BTM_LE_KEY_LID)) {
+ btm_ble_init_pseudo_addr (p_rec, bd_addr);
+
+ switch (key_type) {
+ case BTM_LE_KEY_PENC:
+ memcpy(p_rec->ble.keys.pltk, p_keys->penc_key.ltk, BT_OCTET16_LEN);
+ memcpy(p_rec->ble.keys.rand, p_keys->penc_key.rand, BT_OCTET8_LEN);
+ p_rec->ble.keys.sec_level = p_keys->penc_key.sec_level;
+ p_rec->ble.keys.ediv = p_keys->penc_key.ediv;
+ p_rec->ble.keys.key_size = p_keys->penc_key.key_size;
+ p_rec->ble.key_type |= BTM_LE_KEY_PENC;
+ p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN;
+ if (p_keys->penc_key.sec_level == SMP_SEC_AUTHENTICATED) {
+ p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_AUTHED;
+ } else {
+ p_rec->sec_flags &= ~BTM_SEC_LE_LINK_KEY_AUTHED;
+ }
+ BTM_TRACE_DEBUG("BTM_LE_KEY_PENC key_type=0x%x sec_flags=0x%x sec_leve=0x%x",
+ p_rec->ble.key_type,
+ p_rec->sec_flags,
+ p_rec->ble.keys.sec_level);
+ break;
+
+ case BTM_LE_KEY_PID:
+ for (i = 0; i < BT_OCTET16_LEN; i++) {
+ p_rec->ble.keys.irk[i] = p_keys->pid_key.irk[i];
+ }
+
+ //memcpy( p_rec->ble.keys.irk, p_keys->pid_key, BT_OCTET16_LEN); todo will crash the system
+ memcpy(p_rec->ble.static_addr, p_keys->pid_key.static_addr, BD_ADDR_LEN);
+ p_rec->ble.static_addr_type = p_keys->pid_key.addr_type;
+ p_rec->ble.key_type |= BTM_LE_KEY_PID;
+ BTM_TRACE_DEBUG("BTM_LE_KEY_PID key_type=0x%x save peer IRK", p_rec->ble.key_type);
+ /* update device record address as static address */
+ memcpy(p_rec->bd_addr, p_keys->pid_key.static_addr, BD_ADDR_LEN);
+ /* combine DUMO device security record if needed */
+ btm_consolidate_dev(p_rec);
+ break;
+
+ case BTM_LE_KEY_PCSRK:
+ memcpy(p_rec->ble.keys.pcsrk, p_keys->pcsrk_key.csrk, BT_OCTET16_LEN);
+ p_rec->ble.keys.srk_sec_level = p_keys->pcsrk_key.sec_level;
+ p_rec->ble.keys.counter = p_keys->pcsrk_key.counter;
+ p_rec->ble.key_type |= BTM_LE_KEY_PCSRK;
+ p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN;
+ if ( p_keys->pcsrk_key.sec_level == SMP_SEC_AUTHENTICATED) {
+ p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_AUTHED;
+ } else {
+ p_rec->sec_flags &= ~BTM_SEC_LE_LINK_KEY_AUTHED;
+ }
+
+ BTM_TRACE_DEBUG("BTM_LE_KEY_PCSRK key_type=0x%x sec_flags=0x%x sec_level=0x%x peer_counter=%d",
+ p_rec->ble.key_type,
+ p_rec->sec_flags,
+ p_rec->ble.keys.srk_sec_level,
+ p_rec->ble.keys.counter );
+ break;
+
+ case BTM_LE_KEY_LENC:
+ memcpy(p_rec->ble.keys.lltk, p_keys->lenc_key.ltk, BT_OCTET16_LEN);
+ p_rec->ble.keys.div = p_keys->lenc_key.div; /* update DIV */
+ p_rec->ble.keys.sec_level = p_keys->lenc_key.sec_level;
+ p_rec->ble.keys.key_size = p_keys->lenc_key.key_size;
+ p_rec->ble.key_type |= BTM_LE_KEY_LENC;
+
+ /* Set that link key is known since this shares field with BTM_SEC_FLAG_LKEY_KNOWN flag in stack/btm_api.h*/
+ p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN;
+ if ( p_keys->lenc_key.sec_level == SMP_SEC_AUTHENTICATED) {
+ p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_AUTHED;
+ } else {
+ p_rec->sec_flags &= ~BTM_SEC_LE_LINK_KEY_AUTHED;
+ }
+
+ BTM_TRACE_DEBUG("BTM_LE_KEY_LENC key_type=0x%x DIV=0x%x key_size=0x%x sec_level=0x%x",
+ p_rec->ble.key_type,
+ p_rec->ble.keys.div,
+ p_rec->ble.keys.key_size,
+ p_rec->ble.keys.sec_level );
+ break;
+
+ case BTM_LE_KEY_LCSRK:/* local CSRK has been delivered */
+ memcpy (p_rec->ble.keys.lcsrk, p_keys->lcsrk_key.csrk, BT_OCTET16_LEN);
+ p_rec->ble.keys.div = p_keys->lcsrk_key.div; /* update DIV */
+ p_rec->ble.keys.local_csrk_sec_level = p_keys->lcsrk_key.sec_level;
+ p_rec->ble.keys.local_counter = p_keys->lcsrk_key.counter;
+ p_rec->ble.key_type |= BTM_LE_KEY_LCSRK;
+ BTM_TRACE_DEBUG("BTM_LE_KEY_LCSRK key_type=0x%x DIV=0x%x scrk_sec_level=0x%x local_counter=%d",
+ p_rec->ble.key_type,
+ p_rec->ble.keys.div,
+ p_rec->ble.keys.local_csrk_sec_level,
+ p_rec->ble.keys.local_counter );
+ break;
+
+ case BTM_LE_KEY_LID:
+ p_rec->ble.key_type |= BTM_LE_KEY_LID;
+ break;
+ default:
+ BTM_TRACE_WARNING("btm_sec_save_le_key (Bad key_type 0x%02x)", key_type);
+ return;
+ }
+
+ BTM_TRACE_DEBUG ("BLE key type 0x%02x updated for BDA: %08x%04x (btm_sec_save_le_key)", key_type,
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5]);
+
+ /* Notify the application that one of the BLE keys has been updated
+ If link key is in progress, it will get sent later.*/
+ if (pass_to_application && btm_cb.api.p_le_callback) {
+ cb_data.key.p_key_value = p_keys;
+ cb_data.key.key_type = key_type;
+
+ (*btm_cb.api.p_le_callback) (BTM_LE_KEY_EVT, bd_addr, &cb_data);
+ }
+ return;
+ }
+
+ BTM_TRACE_WARNING ("BLE key type 0x%02x called for Unknown BDA or type: %08x%04x !! (btm_sec_save_le_key)", key_type,
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5]);
+
+ if (p_rec) {
+ BTM_TRACE_DEBUG ("sec_flags=0x%x", p_rec->sec_flags);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_update_sec_key_size
+**
+** Description update the current lin kencryption key size
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_update_sec_key_size(BD_ADDR bd_addr, UINT8 enc_key_size)
+{
+ tBTM_SEC_DEV_REC *p_rec;
+
+ BTM_TRACE_DEBUG("btm_ble_update_sec_key_size enc_key_size = %d", enc_key_size);
+
+ if ((p_rec = btm_find_dev (bd_addr)) != NULL ) {
+ p_rec->enc_key_size = enc_key_size;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_ble_read_sec_key_size
+**
+** Description update the current lin kencryption key size
+**
+** Returns void
+**
+*******************************************************************************/
+UINT8 btm_ble_read_sec_key_size(BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_rec;
+
+ if ((p_rec = btm_find_dev (bd_addr)) != NULL ) {
+ return p_rec->enc_key_size;
+ } else {
+ return 0;
+ }
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_link_sec_check
+**
+** Description Check BLE link security level match.
+**
+** Returns TRUE: check is OK and the *p_sec_req_act contain the action
+**
+*******************************************************************************/
+void btm_ble_link_sec_check(BD_ADDR bd_addr, tBTM_LE_AUTH_REQ auth_req, tBTM_BLE_SEC_REQ_ACT *p_sec_req_act)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+ UINT8 req_sec_level = BTM_LE_SEC_NONE, cur_sec_level = BTM_LE_SEC_NONE;
+
+ BTM_TRACE_DEBUG ("btm_ble_link_sec_check auth_req =0x%x", auth_req);
+
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR ("btm_ble_link_sec_check received for unknown device");
+ return;
+ }
+
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING ||
+ p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) {
+ /* race condition: discard the security request while master is encrypting the link */
+ *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_DISCARD;
+ } else {
+ req_sec_level = BTM_LE_SEC_UNAUTHENTICATE;
+ if (auth_req & BTM_LE_AUTH_REQ_MITM) {
+ req_sec_level = BTM_LE_SEC_AUTHENTICATED;
+ }
+
+ BTM_TRACE_DEBUG ("dev_rec sec_flags=0x%x", p_dev_rec->sec_flags);
+
+ /* currently encrpted */
+ if (p_dev_rec->sec_flags & BTM_SEC_LE_ENCRYPTED) {
+ if (p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED) {
+ cur_sec_level = BTM_LE_SEC_AUTHENTICATED;
+ } else {
+ cur_sec_level = BTM_LE_SEC_UNAUTHENTICATE;
+ }
+ } else { /* unencrypted link */
+ /* if bonded, get the key security level */
+ if (p_dev_rec->ble.key_type & BTM_LE_KEY_PENC) {
+ cur_sec_level = p_dev_rec->ble.keys.sec_level;
+ } else {
+ cur_sec_level = BTM_LE_SEC_NONE;
+ }
+ }
+
+ if (cur_sec_level >= req_sec_level) {
+ /* To avoid re-encryption on an encrypted link for an equal condition encryption */
+ *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_ENCRYPT;
+ } else {
+ *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_PAIR; /* start the pariring process to upgrade the keys*/
+ }
+ }
+
+ BTM_TRACE_DEBUG("cur_sec_level=%d req_sec_level=%d sec_req_act=%d",
+ cur_sec_level,
+ req_sec_level,
+ *p_sec_req_act);
+
+
+}
+#endif ///BLE_INCLUDED == TRUE
+#endif ///SMP_INCLUDED == TRUE
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function btm_ble_set_encryption
+**
+** Description This function is called to ensure that LE connection is
+** encrypted. Should be called only on an open connection.
+** Typically only needed for connections that first want to
+** bring up unencrypted links, then later encrypt them.
+**
+** Returns void
+** the local device ER is copied into er
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, void *p_ref_data, UINT8 link_role)
+{
+ tBTM_STATUS cmd = BTM_NO_RESOURCES;
+#if (SMP_INCLUDED == TRUE)
+ tBTM_BLE_SEC_ACT sec_act = *(tBTM_BLE_SEC_ACT *)p_ref_data ;
+ tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bd_addr);
+ tBTM_BLE_SEC_REQ_ACT sec_req_act;
+ tBTM_LE_AUTH_REQ auth_req;
+
+ if (p_rec == NULL) {
+ BTM_TRACE_WARNING ("btm_ble_set_encryption (NULL device record!! sec_act=0x%x", sec_act);
+ return (BTM_WRONG_MODE);
+ }
+
+ BTM_TRACE_DEBUG ("btm_ble_set_encryption sec_act=0x%x role_master=%d", sec_act, p_rec->role_master);
+
+ if (sec_act == BTM_BLE_SEC_ENCRYPT_MITM) {
+ p_rec->security_required |= BTM_SEC_IN_MITM;
+ }
+
+ switch (sec_act) {
+ case BTM_BLE_SEC_ENCRYPT:
+ if (link_role == BTM_ROLE_MASTER && (p_rec->ble.key_type & BTM_LE_KEY_PENC)) {
+ /* start link layer encryption using the security info stored */
+ cmd = btm_ble_start_encrypt(bd_addr, FALSE, NULL);
+ break;
+ }
+ /* if salve role then fall through to call SMP_Pair below which will send a
+ sec_request to request the master to encrypt the link */
+ case BTM_BLE_SEC_ENCRYPT_NO_MITM:
+ case BTM_BLE_SEC_ENCRYPT_MITM:
+ if ((link_role == BTM_ROLE_MASTER) && (sec_act != BTM_BLE_SEC_ENCRYPT)) {
+ auth_req = (sec_act == BTM_BLE_SEC_ENCRYPT_NO_MITM)
+ ? SMP_AUTH_GEN_BOND : (SMP_AUTH_GEN_BOND | SMP_AUTH_YN_BIT);
+ btm_ble_link_sec_check (bd_addr, auth_req, &sec_req_act);
+
+ if (sec_req_act == BTM_BLE_SEC_REQ_ACT_ENCRYPT) {
+ cmd = btm_ble_start_encrypt(bd_addr, FALSE, NULL);
+ break;
+ }
+ }
+#if (SMP_SLAVE_CON_PARAMS_UPD_ENABLE == TRUE)
+ // already have encrypted information, do not need to update connection parameters
+ if(link_role == BTM_ROLE_SLAVE && (p_rec->ble.key_type & BTM_LE_KEY_PENC)) {
+ p_rec->ble.skip_update_conn_param = true;
+ } else {
+ p_rec->ble.skip_update_conn_param = false;
+ }
+#endif
+ if (SMP_Pair(bd_addr) == SMP_STARTED) {
+ cmd = BTM_CMD_STARTED;
+ p_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+ }
+ break;
+
+ default:
+ cmd = BTM_WRONG_MODE;
+ break;
+ }
+#endif ///SMP_INCLUDED == TRUE
+ return cmd;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_ltk_request
+**
+** Description This function is called when encryption request is received
+** on a slave device.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+void btm_ble_ltk_request(UINT16 handle, UINT8 rand[8], UINT16 ediv)
+{
+ tBTM_CB *p_cb = &btm_cb;
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
+ BT_OCTET16 dummy_stk = {0};
+
+ BTM_TRACE_DEBUG ("btm_ble_ltk_request");
+
+ p_cb->ediv = ediv;
+
+ memcpy(p_cb->enc_rand, rand, BT_OCTET8_LEN);
+
+ if (p_dev_rec != NULL) {
+ if (!smp_proc_ltk_request(p_dev_rec->bd_addr)) {
+ btm_ble_ltk_request_reply(p_dev_rec->bd_addr, FALSE, dummy_stk);
+ }
+ }
+
+}
+#endif ///SMP_INCLUDED == TRUE
+
+
+/*******************************************************************************
+**
+** Function btm_ble_start_encrypt
+**
+** Description This function is called to start LE encryption.
+**
+**
+** Returns BTM_SUCCESS if encryption was started successfully
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_start_encrypt(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk)
+{
+#if (SMP_INCLUDED == TRUE)
+ tBTM_CB *p_cb = &btm_cb;
+ tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bda);
+ BT_OCTET8 dummy_rand = {0};
+#endif ///SMP_INCLUDED == TRUE
+
+ tBTM_STATUS rt = BTM_NO_RESOURCES;
+#if (SMP_INCLUDED == TRUE)
+ BTM_TRACE_DEBUG ("btm_ble_start_encrypt");
+
+ if (!p_rec ) {
+ BTM_TRACE_ERROR("Link is not active, can not encrypt!");
+ return BTM_WRONG_MODE;
+ }
+
+ if (p_rec->sec_state == BTM_SEC_STATE_ENCRYPTING) {
+ BTM_TRACE_WARNING("Link Encryption is active, Busy!");
+ return BTM_BUSY;
+ }
+
+ p_cb->enc_handle = p_rec->ble_hci_handle;
+
+ if (use_stk) {
+ if (btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, dummy_rand, 0, stk)) {
+ rt = BTM_CMD_STARTED;
+ }
+ } else if (p_rec->ble.key_type & BTM_LE_KEY_PENC) {
+ if (btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, p_rec->ble.keys.rand,
+ p_rec->ble.keys.ediv, p_rec->ble.keys.pltk)) {
+ rt = BTM_CMD_STARTED;
+ }
+ } else {
+ BTM_TRACE_ERROR("No key available to encrypt the link");
+ }
+ if (rt == BTM_CMD_STARTED) {
+ if (p_rec->sec_state == BTM_SEC_STATE_IDLE) {
+ p_rec->sec_state = BTM_SEC_STATE_ENCRYPTING;
+ }
+ }
+#endif ///SMP_INCLUDED == TRUE
+ return rt;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_link_encrypted
+**
+** Description This function is called when LE link encrption status is changed.
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+void btm_ble_link_encrypted(BD_ADDR bd_addr, UINT8 encr_enable)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+ BOOLEAN enc_cback;
+
+ if (!p_dev_rec) {
+ BTM_TRACE_WARNING ("btm_ble_link_encrypted (No Device Found!) encr_enable=%d", encr_enable);
+ return;
+ }
+
+ BTM_TRACE_DEBUG ("btm_ble_link_encrypted encr_enable=%d", encr_enable);
+
+ enc_cback = (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING);
+
+ smp_link_encrypted(bd_addr, encr_enable);
+
+ BTM_TRACE_DEBUG(" p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags);
+
+ if (encr_enable && p_dev_rec->enc_key_size == 0) {
+ p_dev_rec->enc_key_size = p_dev_rec->ble.keys.key_size;
+ }
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ if (p_dev_rec->p_callback && enc_cback) {
+ if (encr_enable) {
+ btm_sec_dev_rec_cback_event(p_dev_rec, BTM_SUCCESS, TRUE);
+ } else if (p_dev_rec->role_master) {
+ btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING, TRUE);
+ }
+
+ }
+ /* to notify GATT to send data if any request is pending */
+ gatt_notify_enc_cmpl(p_dev_rec->ble.pseudo_addr);
+}
+#endif ///SMP_INCLUDED == TRUE
+
+
+/*******************************************************************************
+**
+** Function btm_ble_ltk_request_reply
+**
+** Description This function is called to send a LTK request reply on a slave
+** device.
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+void btm_ble_ltk_request_reply(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk)
+{
+ tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bda);
+ tBTM_CB *p_cb = &btm_cb;
+
+ if (p_rec == NULL) {
+ BTM_TRACE_ERROR("btm_ble_ltk_request_reply received for unknown device");
+ return;
+ }
+
+ BTM_TRACE_DEBUG ("btm_ble_ltk_request_reply");
+ p_cb->enc_handle = p_rec->ble_hci_handle;
+ p_cb->key_size = p_rec->ble.keys.key_size;
+
+ BTM_TRACE_DEBUG("key size = %d", p_rec->ble.keys.key_size);
+ if (use_stk) {
+ btsnd_hcic_ble_ltk_req_reply(btm_cb.enc_handle, stk);
+ } else { /* calculate LTK using peer device */
+ if (p_rec->ble.key_type & BTM_LE_KEY_LENC) {
+ btsnd_hcic_ble_ltk_req_reply(btm_cb.enc_handle, p_rec->ble.keys.lltk);
+ } else {
+ btsnd_hcic_ble_ltk_req_neg_reply(btm_cb.enc_handle);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_io_capabilities_req
+**
+** Description This function is called to handle SMP get IO capability request.
+**
+** Returns void
+**
+*******************************************************************************/
+UINT8 btm_ble_io_capabilities_req(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_LE_IO_REQ *p_data)
+{
+ UINT8 callback_rc = BTM_SUCCESS;
+ BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req");
+ if (btm_cb.api.p_le_callback) {
+ /* the callback function implementation may change the IO capability... */
+ callback_rc = (*btm_cb.api.p_le_callback) (BTM_LE_IO_REQ_EVT, p_dev_rec->bd_addr, (tBTM_LE_EVT_DATA *)p_data);
+ }
+#if BTM_OOB_INCLUDED == TRUE
+ if ((callback_rc == BTM_SUCCESS) || (BTM_OOB_UNKNOWN != p_data->oob_data))
+#else
+ if (callback_rc == BTM_SUCCESS)
+#endif
+ {
+#if BTM_BLE_CONFORMANCE_TESTING == TRUE
+ if (btm_cb.devcb.keep_rfu_in_auth_req) {
+ BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req keep_rfu_in_auth_req = %u",
+ btm_cb.devcb.keep_rfu_in_auth_req);
+ p_data->auth_req &= BTM_LE_AUTH_REQ_MASK_KEEP_RFU;
+ btm_cb.devcb.keep_rfu_in_auth_req = FALSE;
+ } else {
+ /* default */
+ p_data->auth_req &= BTM_LE_AUTH_REQ_MASK;
+ }
+#else
+ p_data->auth_req &= BTM_LE_AUTH_REQ_MASK;
+#endif
+
+ BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 1: p_dev_rec->security_required = %d auth_req:%d",
+ p_dev_rec->security_required, p_data->auth_req);
+ BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 2: i_keys=0x%x r_keys=0x%x (bit 0-LTK 1-IRK 2-CSRK)",
+ p_data->init_keys,
+ p_data->resp_keys);
+
+ /* if authentication requires MITM protection, put on the mask */
+ if (p_dev_rec->security_required & BTM_SEC_IN_MITM) {
+ p_data->auth_req |= BTM_LE_AUTH_REQ_MITM;
+ }
+
+ if (!(p_data->auth_req & SMP_AUTH_BOND)) {
+ BTM_TRACE_DEBUG("Non bonding: No keys should be exchanged");
+ p_data->init_keys = 0;
+ p_data->resp_keys = 0;
+ }
+
+ BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 3: auth_req:%d\n", p_data->auth_req);
+ BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 4: i_keys=0x%x r_keys=0x%x\n",
+ p_data->init_keys,
+ p_data->resp_keys);
+
+ BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 5: p_data->io_cap = %d auth_req:%d\n",
+ p_data->io_cap, p_data->auth_req);
+
+ /* remove MITM protection requirement if IO cap does not allow it */
+ if ((p_data->io_cap == BTM_IO_CAP_NONE) && p_data->oob_data == SMP_OOB_NONE) {
+ p_data->auth_req &= ~BTM_LE_AUTH_REQ_MITM;
+ }
+
+ if (!(p_data->auth_req & SMP_SC_SUPPORT_BIT)) {
+ /* if Secure Connections are not supported then remove LK derivation,
+ ** and keypress notifications.
+ */
+ BTM_TRACE_DEBUG("%s-SC not supported -> No LK derivation, no keypress notifications",
+ __func__);
+ p_data->auth_req &= ~SMP_KP_SUPPORT_BIT;
+ p_data->init_keys &= ~SMP_SEC_KEY_TYPE_LK;
+ p_data->resp_keys &= ~SMP_SEC_KEY_TYPE_LK;
+ }
+
+ BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 6: IO_CAP:%d oob_data:%d auth_req:0x%02x\n",
+ p_data->io_cap, p_data->oob_data, p_data->auth_req);
+ }
+ return callback_rc;
+}
+#endif ///SMP_INCLUDED == TRUE
+
+
+/*******************************************************************************
+**
+** Function btm_ble_br_keys_req
+**
+** Description This function is called to handle SMP request for keys sent
+** over BR/EDR.
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+UINT8 btm_ble_br_keys_req(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_LE_IO_REQ *p_data)
+{
+ UINT8 callback_rc = BTM_SUCCESS;
+ BTM_TRACE_DEBUG ("%s\n", __func__);
+ if (btm_cb.api.p_le_callback) {
+ /* the callback function implementation may change the IO capability... */
+ callback_rc = (*btm_cb.api.p_le_callback) (BTM_LE_IO_REQ_EVT, p_dev_rec->bd_addr,
+ (tBTM_LE_EVT_DATA *)p_data);
+ }
+ return callback_rc;
+}
+#endif ///SMP_INCLUDED
+
+
+#if (BLE_PRIVACY_SPT == TRUE )
+/*******************************************************************************
+**
+** Function btm_ble_resolve_random_addr_on_conn_cmpl
+**
+** Description resolve random address complete on connection complete event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_resolve_random_addr_on_conn_cmpl(void *p_rec, void *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+ tBTM_SEC_DEV_REC *match_rec = (tBTM_SEC_DEV_REC *) p_rec;
+ UINT8 role, bda_type;
+ UINT16 handle;
+ BD_ADDR bda, local_rpa, peer_rpa;
+ UINT16 conn_interval, conn_latency, conn_timeout;
+ BOOLEAN match = FALSE;
+
+ ++p;
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT8 (role, p);
+ STREAM_TO_UINT8 (bda_type, p);
+ STREAM_TO_BDADDR (bda, p);
+ // if the enhanced is true, means the connection is enhanced connect,
+ // so the packet should include the local Resolvable Private Address and Peer Resolvable Private Address
+ if(temp_enhanced) {
+ STREAM_TO_BDADDR(local_rpa, p);
+ STREAM_TO_BDADDR(peer_rpa, p);
+ }
+ STREAM_TO_UINT16 (conn_interval, p);
+ STREAM_TO_UINT16 (conn_latency, p);
+ STREAM_TO_UINT16 (conn_timeout, p);
+
+ handle = HCID_GET_HANDLE (handle);
+ BTM_TRACE_EVENT ("%s\n", __func__);
+
+ if (match_rec) {
+ BTM_TRACE_DEBUG("%s matched and resolved random address", __func__);
+ match = TRUE;
+ match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA;
+ memcpy(match_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN);
+ if (!btm_ble_init_pseudo_addr (match_rec, bda)) {
+ /* assign the original address to be the current report address */
+ memcpy(bda, match_rec->ble.pseudo_addr, BD_ADDR_LEN);
+ } else {
+ memcpy(bda, match_rec->bd_addr, BD_ADDR_LEN);
+ }
+ } else {
+ BTM_TRACE_DEBUG("%s unable to match and resolve random address", __func__);
+ }
+
+ btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type, match);
+
+ l2cble_conn_comp (handle, role, bda, bda_type, conn_interval,
+ conn_latency, conn_timeout);
+
+ return;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function btm_ble_connected
+**
+** Description This function is when a LE connection to the peer device is
+** establsihed
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role,
+ tBLE_ADDR_TYPE addr_type, BOOLEAN addr_matched)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda);
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ UNUSED(addr_matched);
+
+ BTM_TRACE_EVENT ("btm_ble_connected");
+
+ /* Commenting out trace due to obf/compilation problems.
+ */
+#if (BT_USE_TRACES == TRUE)
+ if (p_dev_rec) {
+ BTM_TRACE_EVENT ("Security Manager: btm_ble_connected : handle:%d enc_mode:%d bda:%x RName:%s",
+ handle, enc_mode,
+ (bda[2] << 24) + (bda[3] << 16) + (bda[4] << 8) + bda[5],
+ p_dev_rec->sec_bd_name);
+
+ BTM_TRACE_DEBUG ("btm_ble_connected sec_flags=0x%x", p_dev_rec->sec_flags);
+ } else {
+ BTM_TRACE_EVENT ("Security Manager: btm_ble_connected: handle:%d enc_mode:%d bda:%x ",
+ handle, enc_mode,
+ (bda[2] << 24) + (bda[3] << 16) + (bda[4] << 8) + bda[5]);
+ }
+#endif
+
+ if (!p_dev_rec) {
+ /* There is no device record for new connection. Allocate one */
+ if ((p_dev_rec = btm_sec_alloc_dev (bda)) == NULL) {
+ return;
+ }
+ } else { /* Update the timestamp for this device */
+ p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+ }
+
+ /* update device information */
+ p_dev_rec->device_type |= BT_DEVICE_TYPE_BLE;
+ p_dev_rec->ble_hci_handle = handle;
+ p_dev_rec->ble.ble_addr_type = addr_type;
+ /* update pseudo address */
+ memcpy(p_dev_rec->ble.pseudo_addr, bda, BD_ADDR_LEN);
+
+ p_dev_rec->role_master = FALSE;
+ if (role == HCI_ROLE_MASTER) {
+ p_dev_rec->role_master = TRUE;
+ }
+
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+ if (!addr_matched) {
+ p_dev_rec->ble.active_addr_type = BTM_BLE_ADDR_PSEUDO;
+ }
+
+ if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_RANDOM && !addr_matched) {
+ memcpy(p_dev_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN);
+ }
+#endif
+
+ p_cb->inq_var.directed_conn = BTM_BLE_CONNECT_EVT;
+
+ return;
+}
+
+/*****************************************************************************
+** Function btm_ble_conn_complete
+**
+** Description LE connection complete.
+**
+******************************************************************************/
+void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced)
+{
+#if (BLE_PRIVACY_SPT == TRUE )
+ UINT8 *p_data = p, peer_addr_type;
+#endif ///BLE_PRIVACY_SPT == TRUE
+ UINT8 role, status, bda_type;
+ UINT16 handle;
+ BD_ADDR bda;
+ BD_ADDR local_rpa, peer_rpa;
+ UINT16 conn_interval, conn_latency, conn_timeout;
+ BOOLEAN match = FALSE;
+ UNUSED(evt_len);
+ STREAM_TO_UINT8 (status, p);
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT8 (role, p);
+ STREAM_TO_UINT8 (bda_type, p);
+ STREAM_TO_BDADDR (bda, p);
+ BTM_TRACE_DEBUG("status = %d, handle = %d, role = %d, bda_type = %d",status,handle,role,bda_type);
+ if (status == 0) {
+ if (enhanced) {
+ STREAM_TO_BDADDR (local_rpa, p);
+ STREAM_TO_BDADDR (peer_rpa, p);
+#if (CONTROLLER_RPA_LIST_ENABLE == TRUE)
+ BD_ADDR dummy_bda = {0};
+ /* For controller generates RPA, if resolving list contains no matching entry, it use identity address.
+ * So we should update own addr type in Host */
+ if (memcmp(local_rpa, dummy_bda, BD_ADDR_LEN)) {
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type |= (BLE_ADDR_TYPE_ID_BIT);
+ BTM_UpdateAddrInfor(btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, local_rpa);
+ } else {
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type &= (~BLE_ADDR_TYPE_ID_BIT);
+ }
+#endif
+ }
+#if (BLE_PRIVACY_SPT == TRUE )
+ peer_addr_type = bda_type;
+ match = btm_identity_addr_to_random_pseudo (bda, &bda_type, FALSE);
+
+ /* possiblly receive connection complete with resolvable random on
+ slave role while the device has been paired */
+
+ /* It will cause that scanner doesn't send scan request to advertiser
+ * which has sent IRK to us and we have stored the IRK in controller.
+ * It is a hardware limitation. The preliminary solution is not to
+ * send key to the controller, but to resolve the random address in host.
+ * so we need send the real address information to controller to connect.
+ * Once the connection is successful, resolve device address whether it is
+ * slave or master*/
+
+#if CONTROLLER_RPA_LIST_ENABLE
+ if (!match && role == HCI_ROLE_SLAVE && bda_type != BLE_ADDR_PUBLIC && BTM_BLE_IS_RESOLVE_BDA(bda)) {
+#else
+ if (!match && bda_type != BLE_ADDR_PUBLIC && BTM_BLE_IS_RESOLVE_BDA(bda)) {
+#endif
+ // save the enhanced value to used in btm_ble_resolve_random_addr_on_conn_cmpl func.
+ temp_enhanced = enhanced;
+ btm_ble_resolve_random_addr(bda, btm_ble_resolve_random_addr_on_conn_cmpl, p_data);
+ // set back the temp enhanced to default after used.
+ temp_enhanced = FALSE;
+ } else
+#endif
+ {
+ STREAM_TO_UINT16 (conn_interval, p);
+ STREAM_TO_UINT16 (conn_latency, p);
+ STREAM_TO_UINT16 (conn_timeout, p);
+ handle = HCID_GET_HANDLE (handle);
+
+ btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type, match);
+ l2cble_conn_comp (handle, role, bda, bda_type, conn_interval,
+ conn_latency, conn_timeout);
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ if (enhanced) {
+ btm_ble_refresh_local_resolvable_private_addr(bda, local_rpa);
+
+ if (peer_addr_type & BLE_ADDR_TYPE_ID_BIT) {
+ btm_ble_refresh_peer_resolvable_private_addr(bda, peer_rpa, BLE_ADDR_RANDOM);
+ }
+ }
+#endif
+ }
+ } else {
+ role = HCI_ROLE_UNKNOWN;
+ if (status != HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT) {
+ btm_ble_set_conn_st(BLE_CONN_IDLE);
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+ btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, TRUE);
+#endif
+ } else {
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+ btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+ btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, TRUE);
+#endif
+ }
+
+ }
+
+ BOOLEAN bg_con = btm_ble_update_mode_operation(role, bda, status);
+ if (status != HCI_SUCCESS && !bg_con) {
+ // notify connection failed
+ l2c_link_hci_disc_comp (handle, status);
+#if (SMP_INCLUDED == TRUE)
+ /* Notify security manager */
+ btm_sec_disconnected (handle, status);
+#endif ///SMP_INCLUDED == TRUE
+ }
+}
+
+
+
+/*****************************************************************************
+** Function btm_ble_create_ll_conn_complete
+**
+** Description LE connection complete.
+**
+******************************************************************************/
+void btm_ble_create_ll_conn_complete (UINT8 status)
+{
+ if (status != HCI_SUCCESS) {
+ btm_ble_set_conn_st(BLE_CONN_IDLE);
+ btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, NULL, status);
+ }
+}
+
+/*****************************************************************************
+** Function btm_ble_create_conn_cancel_complete
+**
+** Description LE connection cancel complete.
+**
+******************************************************************************/
+void btm_ble_create_conn_cancel_complete (UINT8 *p)
+{
+ UINT8 status;
+
+ STREAM_TO_UINT8 (status, p);
+
+ switch (status) {
+ case HCI_SUCCESS:
+ if (btm_ble_get_conn_st() == BLE_CONN_CANCEL) {
+ btm_ble_set_conn_st (BLE_CONN_IDLE);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/*****************************************************************************
+** Function btm_proc_smp_cback
+**
+** Description This function is the SMP callback handler.
+**
+******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+ UINT8 res = 0;
+
+ BTM_TRACE_DEBUG ("btm_proc_smp_cback event = %d", event);
+
+ if (p_dev_rec != NULL) {
+ switch (event) {
+ case SMP_IO_CAP_REQ_EVT:
+ btm_ble_io_capabilities_req(p_dev_rec, (tBTM_LE_IO_REQ *)&p_data->io_req);
+ break;
+
+ case SMP_BR_KEYS_REQ_EVT:
+ btm_ble_br_keys_req(p_dev_rec, (tBTM_LE_IO_REQ *)&p_data->io_req);
+ break;
+
+ case SMP_PASSKEY_REQ_EVT:
+ case SMP_PASSKEY_NOTIF_EVT:
+ case SMP_OOB_REQ_EVT:
+ case SMP_NC_REQ_EVT:
+ case SMP_SC_OOB_REQ_EVT:
+ /* fall through */
+ p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED;
+
+ case SMP_SEC_REQUEST_EVT:
+ if (event == SMP_SEC_REQUEST_EVT && btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) {
+ BTM_TRACE_DEBUG("%s: Ignoring SMP Security request", __func__);
+ break;
+ }
+ memcpy (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN);
+ p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_LE_ACTIVE;
+ /* fall through */
+
+ case SMP_COMPLT_EVT:
+ if (btm_cb.api.p_le_callback) {
+ /* the callback function implementation may change the IO capability... */
+ BTM_TRACE_DEBUG ("btm_cb.api.p_le_callback=%p", btm_cb.api.p_le_callback );
+ (*btm_cb.api.p_le_callback) (event, bd_addr, (tBTM_LE_EVT_DATA *)p_data);
+ }
+
+ if (event == SMP_COMPLT_EVT) {
+ BTM_TRACE_DEBUG ("evt=SMP_COMPLT_EVT before update sec_level=0x%x sec_flags=0x%x", p_data->cmplt.sec_level , p_dev_rec->sec_flags );
+
+ res = (p_data->cmplt.reason == SMP_SUCCESS) ? BTM_SUCCESS : BTM_ERR_PROCESSING;
+
+ BTM_TRACE_DEBUG ("after update result=%d sec_level=0x%x sec_flags=0x%x",
+ res, p_data->cmplt.sec_level , p_dev_rec->sec_flags );
+
+ if (p_data->cmplt.is_pair_cancel && btm_cb.api.p_bond_cancel_cmpl_callback ) {
+ BTM_TRACE_DEBUG ("Pairing Cancel completed");
+ (*btm_cb.api.p_bond_cancel_cmpl_callback)(BTM_SUCCESS);
+ }
+#if BTM_BLE_CONFORMANCE_TESTING == TRUE
+ if (res != BTM_SUCCESS) {
+ if (!btm_cb.devcb.no_disc_if_pair_fail && p_data->cmplt.reason != SMP_CONN_TOUT) {
+ BTM_TRACE_DEBUG ("Pairing failed - prepare to remove ACL");
+ l2cu_start_post_bond_timer(p_dev_rec->ble_hci_handle);
+ } else {
+ BTM_TRACE_DEBUG ("Pairing failed - Not Removing ACL");
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ }
+ }
+#else
+ if (res != BTM_SUCCESS && p_data->cmplt.reason != SMP_CONN_TOUT) {
+ BTM_TRACE_DEBUG ("Pairing failed - prepare to remove ACL");
+ l2cu_start_post_bond_timer(p_dev_rec->ble_hci_handle);
+ }
+#endif
+
+ BTM_TRACE_DEBUG ("btm_cb pairing_state=%x pairing_flags=%x",
+ btm_cb.pairing_state,
+ btm_cb.pairing_flags);
+ BTM_TRACE_DEBUG ("btm_cb.pairing_bda %02x:%02x:%02x:%02x:%02x:%02x",
+ btm_cb.pairing_bda[0], btm_cb.pairing_bda[1], btm_cb.pairing_bda[2],
+ btm_cb.pairing_bda[3], btm_cb.pairing_bda[4], btm_cb.pairing_bda[5]);
+
+ /* Reset btm state only if the callback address matches pairing address*/
+ if (memcmp(bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) {
+ memset (btm_cb.pairing_bda, 0xff, BD_ADDR_LEN);
+ btm_cb.pairing_state = BTM_PAIR_STATE_IDLE;
+ btm_cb.pairing_flags = 0;
+ }
+
+ if (res == BTM_SUCCESS) {
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+ /* add all bonded device into resolving list if IRK is available*/
+ btm_ble_resolving_list_load_dev(p_dev_rec);
+#endif
+ }
+
+ btm_sec_dev_rec_cback_event(p_dev_rec, res, TRUE);
+ }
+ break;
+
+ default:
+ BTM_TRACE_DEBUG ("unknown event = %d", event);
+ break;
+
+
+ }
+ } else {
+ if (event == SMP_SC_LOC_OOB_DATA_UP_EVT) {
+ tBTM_LE_EVT_DATA evt_data;
+ memcpy(&evt_data.local_oob_data, &p_data->loc_oob_data, sizeof(tSMP_LOC_OOB_DATA));
+ if (btm_cb.api.p_le_callback) {
+ (*btm_cb.api.p_le_callback)(event, bd_addr, &evt_data);
+ }
+ } else {
+ BTM_TRACE_ERROR("btm_proc_smp_cback received for unknown device");
+ }
+ }
+ return 0;
+}
+#endif ///SMP_INCLUDED == TRUE
+
+
+/*******************************************************************************
+**
+** Function BTM_BleDataSignature
+**
+** Description This function is called to sign the data using AES128 CMAC
+** algorith.
+**
+** Parameter bd_addr: target device the data to be signed for.
+** p_text: singing data
+** len: length of the data to be signed.
+** signature: output parameter where data signature is going to
+** be stored.
+**
+** Returns TRUE if signing sucessul, otherwise FALSE.
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+BOOLEAN BTM_BleDataSignature (BD_ADDR bd_addr, UINT8 *p_text, UINT16 len,
+ BLE_SIGNATURE signature)
+{
+ tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bd_addr);
+
+ BTM_TRACE_DEBUG ("%s", __func__);
+#endif ///SMP_INCLUDED == TRUE
+ BOOLEAN ret = FALSE;
+#if (SMP_INCLUDED == TRUE)
+ if (p_rec == NULL) {
+ BTM_TRACE_ERROR("%s-data signing can not be done from unknown device", __func__);
+ } else {
+ UINT8 *p_mac = (UINT8 *)signature;
+ UINT8 *p_buf, *pp;
+ if ((p_buf = (UINT8 *)osi_malloc((UINT16)(len + 4))) != NULL) {
+ BTM_TRACE_DEBUG("%s-Start to generate Local CSRK", __func__);
+ pp = p_buf;
+ /* prepare plain text */
+ if (p_text) {
+ memcpy(p_buf, p_text, len);
+ pp = (p_buf + len);
+ }
+
+ UINT32_TO_STREAM(pp, p_rec->ble.keys.local_counter);
+ UINT32_TO_STREAM(p_mac, p_rec->ble.keys.local_counter);
+
+ if ((ret = aes_cipher_msg_auth_code(p_rec->ble.keys.lcsrk, p_buf, (UINT16)(len + 4),
+ BTM_CMAC_TLEN_SIZE, p_mac)) == TRUE) {
+ btm_ble_increment_sign_ctr(bd_addr, TRUE);
+ }
+
+ BTM_TRACE_DEBUG("%s p_mac = %p", __func__, p_mac);
+ BTM_TRACE_DEBUG("p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = 0x%02x",
+ *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3));
+ BTM_TRACE_DEBUG("p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = 0x%02x",
+ *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7));
+ osi_free(p_buf);
+ }
+ }
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleVerifySignature
+**
+** Description This function is called to verify the data signature
+**
+** Parameter bd_addr: target device the data to be signed for.
+** p_orig: original data before signature.
+** len: length of the signing data
+** counter: counter used when doing data signing
+** p_comp: signature to be compared against.
+
+** Returns TRUE if signature verified correctly; otherwise FALSE.
+**
+*******************************************************************************/
+BOOLEAN BTM_BleVerifySignature (BD_ADDR bd_addr, UINT8 *p_orig, UINT16 len, UINT32 counter,
+ UINT8 *p_comp)
+{
+ BOOLEAN verified = FALSE;
+ tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bd_addr);
+ UINT8 p_mac[BTM_CMAC_TLEN_SIZE];
+
+ if (p_rec == NULL || (p_rec && !(p_rec->ble.key_type & BTM_LE_KEY_PCSRK))) {
+ BTM_TRACE_ERROR("can not verify signature for unknown device");
+ } else if (counter < p_rec->ble.keys.counter) {
+ BTM_TRACE_ERROR("signature received with out dated sign counter");
+ } else if (p_orig == NULL) {
+ BTM_TRACE_ERROR("No signature to verify");
+ } else {
+ BTM_TRACE_DEBUG ("%s rcv_cnt=%d >= expected_cnt=%d", __func__, counter,
+ p_rec->ble.keys.counter);
+
+ if (aes_cipher_msg_auth_code(p_rec->ble.keys.pcsrk, p_orig, len, BTM_CMAC_TLEN_SIZE, p_mac)) {
+ if (memcmp(p_mac, p_comp, BTM_CMAC_TLEN_SIZE) == 0) {
+ btm_ble_increment_sign_ctr(bd_addr, FALSE);
+ verified = TRUE;
+ }
+ }
+ }
+ return verified;
+}
+#endif /* SMP_INCLUDED */
+
+
+/*******************************************************************************
+**
+** Function BTM_GetLeSecurityState
+**
+** Description This function is called to get security mode 1 flags and
+** encryption key size for LE peer.
+**
+** Returns BOOLEAN TRUE if LE device is found, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN BTM_GetLeSecurityState (BD_ADDR bd_addr, UINT8 *p_le_dev_sec_flags, UINT8 *p_le_key_size)
+{
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ UINT16 dev_rec_sec_flags;
+#endif
+
+ *p_le_dev_sec_flags = 0;
+ *p_le_key_size = 0;
+
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL) {
+ BTM_TRACE_ERROR ("%s fails", __func__);
+ return (FALSE);
+ }
+
+ if (p_dev_rec->ble_hci_handle == BTM_SEC_INVALID_HANDLE) {
+ BTM_TRACE_ERROR ("%s-this is not LE device", __func__);
+ return (FALSE);
+ }
+
+ dev_rec_sec_flags = p_dev_rec->sec_flags;
+
+ if (dev_rec_sec_flags & BTM_SEC_LE_ENCRYPTED) {
+ /* link is encrypted with LTK or STK */
+ *p_le_key_size = p_dev_rec->enc_key_size;
+ *p_le_dev_sec_flags |= BTM_SEC_LE_LINK_ENCRYPTED;
+
+ *p_le_dev_sec_flags |= (dev_rec_sec_flags & BTM_SEC_LE_AUTHENTICATED)
+ ? BTM_SEC_LE_LINK_PAIRED_WITH_MITM /* set auth LTK flag */
+ : BTM_SEC_LE_LINK_PAIRED_WITHOUT_MITM; /* set unauth LTK flag */
+ } else if (p_dev_rec->ble.key_type & BTM_LE_KEY_PENC) {
+ /* link is unencrypted, still LTK is available */
+ *p_le_key_size = p_dev_rec->ble.keys.key_size;
+
+ *p_le_dev_sec_flags |= (dev_rec_sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED)
+ ? BTM_SEC_LE_LINK_PAIRED_WITH_MITM /* set auth LTK flag */
+ : BTM_SEC_LE_LINK_PAIRED_WITHOUT_MITM; /* set unauth LTK flag */
+ }
+
+ BTM_TRACE_DEBUG ("%s - le_dev_sec_flags: 0x%02x, le_key_size: %d",
+ __func__, *p_le_dev_sec_flags, *p_le_key_size);
+
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleSecurityProcedureIsRunning
+**
+** Description This function indicates if LE security procedure is
+** currently running with the peer.
+**
+** Returns BOOLEAN TRUE if security procedure is running, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN BTM_BleSecurityProcedureIsRunning(BD_ADDR bd_addr)
+{
+#if (BLE_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR ("%s device with BDA: %08x%04x is not found",
+ __func__, (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5]);
+ return FALSE;
+ }
+
+ return (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING ||
+ p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING);
+#else
+ return FALSE;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleGetSupportedKeySize
+**
+** Description This function gets the maximum encryption key size in bytes
+** the local device can suport.
+** record.
+**
+** Returns the key size or 0 if the size can't be retrieved.
+**
+*******************************************************************************/
+extern UINT8 BTM_BleGetSupportedKeySize (BD_ADDR bd_addr)
+{
+#ifndef L2CAP_LE_COC_INCLUDED
+#define L2CAP_LE_COC_INCLUDED FALSE
+#endif
+#if ((BLE_INCLUDED == TRUE) && (L2CAP_LE_COC_INCLUDED == TRUE))
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+ tBTM_LE_IO_REQ dev_io_cfg;
+ UINT8 callback_rc;
+
+ if (!p_dev_rec) {
+ BTM_TRACE_ERROR ("%s device with BDA: %08x%04x is not found",
+ __func__, (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5]);
+ return 0;
+ }
+
+ if (btm_cb.api.p_le_callback == NULL) {
+ BTM_TRACE_ERROR ("%s can't access supported key size", __func__);
+ return 0;
+ }
+
+ callback_rc = (*btm_cb.api.p_le_callback) (BTM_LE_IO_REQ_EVT, p_dev_rec->bd_addr,
+ (tBTM_LE_EVT_DATA *) &dev_io_cfg);
+
+ if (callback_rc != BTM_SUCCESS) {
+ BTM_TRACE_ERROR ("%s can't access supported key size", __func__);
+ return 0;
+ }
+
+ BTM_TRACE_DEBUG ("%s device supports key size = %d", __func__, dev_io_cfg.max_key_size);
+ return (dev_io_cfg.max_key_size);
+#else
+ return 0;
+#endif
+}
+
+/*******************************************************************************
+** Utility functions for LE device IR/ER generation
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function btm_notify_new_key
+**
+** Description This function is to notify application new keys have been
+** generated.
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static void btm_notify_new_key(UINT8 key_type)
+{
+ tBTM_BLE_LOCAL_KEYS *p_locak_keys = NULL;
+
+ BTM_TRACE_DEBUG ("btm_notify_new_key key_type=%d", key_type);
+
+ if (btm_cb.api.p_le_key_callback) {
+ switch (key_type) {
+ case BTM_BLE_KEY_TYPE_ID:
+ BTM_TRACE_DEBUG ("BTM_BLE_KEY_TYPE_ID");
+ p_locak_keys = (tBTM_BLE_LOCAL_KEYS *)&btm_cb.devcb.id_keys;
+ break;
+
+ case BTM_BLE_KEY_TYPE_ER:
+ BTM_TRACE_DEBUG ("BTM_BLE_KEY_TYPE_ER");
+ p_locak_keys = (tBTM_BLE_LOCAL_KEYS *)&btm_cb.devcb.ble_encryption_key_value;
+ break;
+
+ default:
+ BTM_TRACE_ERROR("unknown key type: %d", key_type);
+ break;
+ }
+ if (p_locak_keys != NULL) {
+ (*btm_cb.api.p_le_key_callback) (key_type, p_locak_keys);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_process_er2
+**
+** Description This function is called when ER is generated, store it in
+** local control block.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_process_er2(tBTM_RAND_ENC *p)
+{
+ BTM_TRACE_DEBUG ("btm_ble_process_er2");
+
+ if (p && p->opcode == HCI_BLE_RAND) {
+ memcpy(&btm_cb.devcb.ble_encryption_key_value[8], p->param_buf, BT_OCTET8_LEN);
+ btm_notify_new_key(BTM_BLE_KEY_TYPE_ER);
+ } else {
+ BTM_TRACE_ERROR("Generating ER2 exception.");
+ memset(&btm_cb.devcb.ble_encryption_key_value, 0, sizeof(BT_OCTET16));
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_process_er
+**
+** Description This function is called when ER is generated, store it in
+** local control block.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_process_er(tBTM_RAND_ENC *p)
+{
+ BTM_TRACE_DEBUG ("btm_ble_process_er");
+
+ if (p && p->opcode == HCI_BLE_RAND) {
+ memcpy(&btm_cb.devcb.ble_encryption_key_value[0], p->param_buf, BT_OCTET8_LEN);
+
+ if (!btsnd_hcic_ble_rand((void *)btm_ble_process_er2)) {
+ memset(&btm_cb.devcb.ble_encryption_key_value, 0, sizeof(BT_OCTET16));
+ BTM_TRACE_ERROR("Generating ER2 failed.");
+ }
+ } else {
+ BTM_TRACE_ERROR("Generating ER1 exception.");
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_process_irk
+**
+** Description This function is called when IRK is generated, store it in
+** local control block.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_process_irk(tSMP_ENC *p)
+{
+ BTM_TRACE_DEBUG ("btm_ble_process_irk");
+ if (p && p->opcode == HCI_BLE_ENCRYPT) {
+ memcpy(btm_cb.devcb.id_keys.irk, p->param_buf, BT_OCTET16_LEN);
+ btm_notify_new_key(BTM_BLE_KEY_TYPE_ID);
+
+#if (CONTROLLER_RPA_LIST_ENABLE == TRUE)
+ btm_ble_add_default_entry_to_resolving_list();
+#endif
+
+#if (BLE_PRIVACY_SPT == TRUE) && (CONTROLLER_RPA_LIST_ENABLE == FALSE)
+ /* if privacy is enabled, new RPA should be calculated */
+ if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) {
+ btm_gen_resolvable_private_addr((void *)btm_gen_resolve_paddr_low);
+ }
+#endif
+ } else {
+ BTM_TRACE_ERROR("Generating IRK exception.");
+ }
+
+ /* proceed generate ER */
+ if (!btsnd_hcic_ble_rand((void *)btm_ble_process_er)) {
+ BTM_TRACE_ERROR("Generating ER failed.");
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_ble_process_dhk
+**
+** Description This function is called when DHK is calculated, store it in
+** local control block, and proceed to generate ER, a 128-bits
+** random number.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_process_dhk(tSMP_ENC *p)
+{
+ UINT8 btm_ble_irk_pt = 0x01;
+ tSMP_ENC output;
+
+ BTM_TRACE_DEBUG ("btm_ble_process_dhk");
+
+ if (p && p->opcode == HCI_BLE_ENCRYPT) {
+ memcpy(btm_cb.devcb.id_keys.dhk, p->param_buf, BT_OCTET16_LEN);
+ BTM_TRACE_DEBUG("BLE DHK generated.");
+
+ /* IRK = D1(IR, 1) */
+ if (!SMP_Encrypt(btm_cb.devcb.id_keys.ir, BT_OCTET16_LEN, &btm_ble_irk_pt,
+ 1, &output)) {
+ /* reset all identity root related key */
+ memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+ } else {
+ btm_ble_process_irk(&output);
+ }
+ } else {
+ /* reset all identity root related key */
+ memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_process_ir2
+**
+** Description This function is called when IR is generated, proceed to calculate
+** DHK = Eir({0x03, 0, 0 ...})
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_process_ir2(tBTM_RAND_ENC *p)
+{
+ UINT8 btm_ble_dhk_pt = 0x03;
+ tSMP_ENC output;
+
+ BTM_TRACE_DEBUG ("btm_ble_process_ir2");
+
+ if (p && p->opcode == HCI_BLE_RAND) {
+ /* remembering in control block */
+ memcpy(&btm_cb.devcb.id_keys.ir[8], p->param_buf, BT_OCTET8_LEN);
+ /* generate DHK= Eir({0x03, 0x00, 0x00 ...}) */
+
+
+ SMP_Encrypt(btm_cb.devcb.id_keys.ir, BT_OCTET16_LEN, &btm_ble_dhk_pt,
+ 1, &output);
+ btm_ble_process_dhk(&output);
+
+ BTM_TRACE_DEBUG("BLE IR generated.");
+ } else {
+ memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_process_ir
+**
+** Description This function is called when IR is generated, proceed to calculate
+** DHK = Eir({0x02, 0, 0 ...})
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_process_ir(tBTM_RAND_ENC *p)
+{
+ BTM_TRACE_DEBUG ("btm_ble_process_ir");
+
+ if (p && p->opcode == HCI_BLE_RAND) {
+ /* remembering in control block */
+ memcpy(btm_cb.devcb.id_keys.ir, p->param_buf, BT_OCTET8_LEN);
+
+ if (!btsnd_hcic_ble_rand((void *)btm_ble_process_ir2)) {
+ BTM_TRACE_ERROR("Generating IR2 failed.");
+ memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_reset_id
+**
+** Description This function is called to reset LE device identity.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_reset_id( void )
+{
+ BTM_TRACE_DEBUG ("btm_ble_reset_id");
+
+ /* regenrate Identity Root*/
+ if (!btsnd_hcic_ble_rand((void *)btm_ble_process_ir)) {
+ BTM_TRACE_DEBUG("Generating IR failed.");
+ }
+}
+#endif ///SMP_INCLUDED == TRUE
+
+#if BTM_BLE_CONFORMANCE_TESTING == TRUE
+/*******************************************************************************
+**
+** Function btm_ble_set_no_disc_if_pair_fail
+**
+** Description This function indicates that whether no disconnect of the ACL
+** should be used if pairing failed
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_set_no_disc_if_pair_fail(BOOLEAN disable_disc )
+{
+ BTM_TRACE_DEBUG ("btm_ble_set_disc_enable_if_pair_fail disable_disc=%d", disable_disc);
+ btm_cb.devcb.no_disc_if_pair_fail = disable_disc;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_set_test_mac_value
+**
+** Description This function set test MAC value
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_set_test_mac_value(BOOLEAN enable, UINT8 *p_test_mac_val )
+{
+ BTM_TRACE_DEBUG ("btm_ble_set_test_mac_value enable=%d", enable);
+ btm_cb.devcb.enable_test_mac_val = enable;
+ memcpy(btm_cb.devcb.test_mac, p_test_mac_val, BT_OCTET8_LEN);
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_set_test_local_sign_cntr_value
+**
+** Description This function set test local sign counter value
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_set_test_local_sign_cntr_value(BOOLEAN enable, UINT32 test_local_sign_cntr )
+{
+ BTM_TRACE_DEBUG ("btm_ble_set_test_local_sign_cntr_value enable=%d local_sign_cntr=%d",
+ enable, test_local_sign_cntr);
+ btm_cb.devcb.enable_test_local_sign_cntr = enable;
+ btm_cb.devcb.test_local_sign_cntr = test_local_sign_cntr;
+}
+
+/*******************************************************************************
+**
+** Function btm_set_random_address
+**
+** Description This function set a random address to local controller.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_set_random_address(BD_ADDR random_bda)
+{
+ tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ BOOLEAN adv_mode = btm_cb.ble_ctr_cb.inq_var.adv_mode ;
+
+ BTM_TRACE_DEBUG ("btm_set_random_address");
+
+ if (adv_mode == BTM_BLE_ADV_ENABLE) {
+ btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE);
+ }
+
+ memcpy(p_cb->private_addr, random_bda, BD_ADDR_LEN);
+ btsnd_hcic_ble_set_random_addr(p_cb->private_addr);
+
+ if (adv_mode == BTM_BLE_ADV_ENABLE) {
+ btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE);
+ }
+
+
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_set_keep_rfu_in_auth_req
+**
+** Description This function indicates if RFU bits have to be kept as is
+** (by default they have to be set to 0 by the sender).
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_set_keep_rfu_in_auth_req(BOOLEAN keep_rfu)
+{
+ BTM_TRACE_DEBUG ("btm_ble_set_keep_rfu_in_auth_req keep_rfus=%d", keep_rfu);
+ btm_cb.devcb.keep_rfu_in_auth_req = keep_rfu;
+}
+
+#endif /* BTM_BLE_CONFORMANCE_TESTING */
+
+/*******************************************************************************
+**
+** Function btm_get_current_conn_params
+**
+** Description This function is called to get current connection parameters
+** information of the device
+**
+** Returns TRUE if the information is geted, else FALSE
+**
+*******************************************************************************/
+
+BOOLEAN btm_get_current_conn_params(BD_ADDR bda, UINT16 *interval, UINT16 *latency, UINT16 *timeout)
+{
+ if( (interval == NULL) || (latency == NULL) || (timeout == NULL) ) {
+ BTM_TRACE_ERROR("%s invalid parameters ", __func__);
+ return FALSE;
+ }
+
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(bda, BT_TRANSPORT_LE);
+ if(p_lcb != NULL) {
+ (*interval) = p_lcb->current_used_conn_interval;
+ (*latency) = p_lcb->current_used_conn_latency;
+ (*timeout) = p_lcb->current_used_conn_timeout;
+ return TRUE;
+ }
+ BTM_TRACE_WARNING("%s Device is not connected", __func__);
+
+ return FALSE;
+}
+
+uint8_t btm_ble_adv_active_count(void)
+{
+ uint8_t count = 0;
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ if (p_cb->state & BTM_BLE_ADVERTISING) {
+ count++;
+ }
+
+ return count;
+}
+
+uint8_t btm_ble_scan_active_count(void)
+{
+ uint8_t count = 0;
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ if (p_cb->state & BTM_BLE_SCANNING) {
+ count++;
+ }
+
+ return count;
+}
+
+#endif /* BLE_INCLUDED */
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c b/lib/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c
new file mode 100644
index 00000000..e5dc3b42
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c
@@ -0,0 +1,1455 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "btm_int.h"
+#include "stack/hcimsgs.h"
+#include "osi/allocator.h"
+#include "device/controller.h"
+#include <string.h>
+#include "l2c_int.h"
+#if (BLE_50_FEATURE_SUPPORT == TRUE)
+#define SET_BIT(t, n) (t |= 1UL << (n))
+tBTM_BLE_EXTENDED_CB extend_adv_cb;
+
+tBTM_BLE_5_HCI_CBACK ble_5_hci_cb;
+
+#define INVALID_VALUE 0XFF
+extern BOOLEAN BTM_GetLocalResolvablePrivateAddr(BD_ADDR bda);
+extern void BTM_UpdateAddrInfor(uint8_t addr_type, BD_ADDR bda);
+extern void BTM_BleSetStaticAddr(BD_ADDR rand_addr);
+extern uint32_t BTM_BleUpdateOwnType(uint8_t *own_bda_type, tBTM_START_ADV_CMPL_CBACK *cb);
+static tBTM_STATUS btm_ble_ext_adv_params_validate(tBTM_BLE_GAP_EXT_ADV_PARAMS *params);
+static tBTM_STATUS btm_ble_ext_adv_set_data_validate(UINT8 instance, UINT16 len, UINT8 *data);
+
+typedef struct {
+ uint16_t ter_con_handle;
+ bool invalid;
+ UINT8 instance;
+ int duration;
+ int max_events;
+ uint8_t retry_count;
+} tBTM_EXT_ADV_RECORD;
+
+tBTM_EXT_ADV_RECORD adv_record[MAX_BLE_ADV_INSTANCE] = {0};
+extern void btm_ble_inter_set(bool extble_inter);
+
+#if !UC_BT_STACK_NO_LOG
+static const char *btm_ble_hci_status_to_str(tHCI_STATUS status)
+{
+ switch(status) {
+ case HCI_SUCCESS:
+ return "HCI_SUCCESS";
+ case HCI_ERR_ILLEGAL_COMMAND:
+ return "HCI_ERR_ILLEGAL_COMMAND";
+ case HCI_ERR_NO_CONNECTION:
+ return "HCI_ERR_NO_CONNECTION";
+ case HCI_ERR_HW_FAILURE:
+ return "HCI_ERR_HW_FAILURE";
+ case HCI_ERR_PAGE_TIMEOUT:
+ return "HCI_ERR_PAGE_TIMEOUT";
+ case HCI_ERR_AUTH_FAILURE:
+ return "HCI_ERR_AUTH_FAILURE";
+ case HCI_ERR_KEY_MISSING:
+ return "HCI_ERR_KEY_MISSING";
+ case HCI_ERR_MEMORY_FULL:
+ return "HCI_ERR_MEMORY_FULL";
+ case HCI_ERR_CONNECTION_TOUT:
+ return "HCI_ERR_CONNECTION_TOUT";
+ case HCI_ERR_MAX_NUM_OF_CONNECTIONS:
+ return "HCI_ERR_MAX_NUM_OF_CONNECTIONS";
+ case HCI_ERR_MAX_NUM_OF_SCOS:
+ return "HCI_ERR_MAX_NUM_OF_SCOS";
+ case HCI_ERR_CONNECTION_EXISTS:
+ return "HCI_ERR_CONNECTION_EXISTS";
+ case HCI_ERR_COMMAND_DISALLOWED:
+ return "HCI_ERR_COMMAND_DISALLOWED";
+ case HCI_ERR_HOST_REJECT_RESOURCES:
+ return "HCI_ERR_HOST_REJECT_RESOURCES";
+ case HCI_ERR_HOST_REJECT_SECURITY:
+ return "HCI_ERR_HOST_REJECT_SECURITY";
+ case HCI_ERR_HOST_REJECT_DEVICE:
+ return "HCI_ERR_HOST_REJECT_DEVICE";
+ case HCI_ERR_HOST_TIMEOUT:
+ return "HCI_ERR_HOST_TIMEOUT";
+ case HCI_ERR_UNSUPPORTED_VALUE:
+ return "HCI_ERR_UNSUPPORTED_VALUE";
+ case HCI_ERR_ILLEGAL_PARAMETER_FMT:
+ return "HCI_ERR_ILLEGAL_PARAMETER_FMT";
+ case HCI_ERR_PEER_USER:
+ return "HCI_ERR_PEER_USER";
+ case HCI_ERR_PEER_LOW_RESOURCES:
+ return "HCI_ERR_PEER_LOW_RESOURCES";
+ case HCI_ERR_PEER_POWER_OFF:
+ return "HCI_ERR_PEER_POWER_OFF";
+ case HCI_ERR_CONN_CAUSE_LOCAL_HOST:
+ return "HCI_ERR_CONN_CAUSE_LOCAL_HOST";
+ case HCI_ERR_REPEATED_ATTEMPTS:
+ return "HCI_ERR_REPEATED_ATTEMPTS";
+ case HCI_ERR_PAIRING_NOT_ALLOWED:
+ return "HCI_ERR_PAIRING_NOT_ALLOWED";
+ case HCI_ERR_UNKNOWN_LMP_PDU:
+ return "HCI_ERR_UNKNOWN_LMP_PDU";
+ case HCI_ERR_UNSUPPORTED_REM_FEATURE:
+ return "HCI_ERR_UNSUPPORTED_REM_FEATURE";
+ case HCI_ERR_SCO_OFFSET_REJECTED:
+ return "HCI_ERR_SCO_OFFSET_REJECTED";
+ case HCI_ERR_SCO_INTERVAL_REJECTED:
+ return "HCI_ERR_SCO_INTERVAL_REJECTED";
+ case HCI_ERR_SCO_AIR_MODE:
+ return "HCI_ERR_SCO_AIR_MODE";
+ case HCI_ERR_INVALID_LMP_PARAM:
+ return "HCI_ERR_INVALID_LMP_PARAM";
+ case HCI_ERR_UNSPECIFIED:
+ return "HCI_ERR_UNSPECIFIED";
+ case HCI_ERR_UNSUPPORTED_LMP_PARAMETERS:
+ return "HCI_ERR_UNSUPPORTED_LMP_PARAMETERS";
+ case HCI_ERR_ROLE_CHANGE_NOT_ALLOWED:
+ return "HCI_ERR_ROLE_CHANGE_NOT_ALLOWED";
+ case HCI_ERR_LMP_RESPONSE_TIMEOUT:
+ return "HCI_ERR_LMP_RESPONSE_TIMEOUT";
+ case HCI_ERR_LMP_ERR_TRANS_COLLISION:
+ return "HCI_ERR_LMP_ERR_TRANS_COLLISION";
+ case HCI_ERR_LMP_PDU_NOT_ALLOWED:
+ return "HCI_ERR_LMP_PDU_NOT_ALLOWED";
+ case HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE:
+ return "HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE";
+ case HCI_ERR_UNIT_KEY_USED:
+ return "HCI_ERR_UNIT_KEY_USED";
+ case HCI_ERR_QOS_NOT_SUPPORTED:
+ return "HCI_ERR_QOS_NOT_SUPPORTED";
+ case HCI_ERR_INSTANT_PASSED:
+ return "HCI_ERR_INSTANT_PASSED";
+ case HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED:
+ return "HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED";
+ case HCI_ERR_DIFF_TRANSACTION_COLLISION:
+ return "HCI_ERR_DIFF_TRANSACTION_COLLISION";
+ case HCI_ERR_UNDEFINED_0x2B:
+ return "HCI_ERR_UNDEFINED_0x2B";
+ case HCI_ERR_QOS_UNACCEPTABLE_PARAM:
+ return "HCI_ERR_QOS_UNACCEPTABLE_PARAM";
+ case HCI_ERR_QOS_REJECTED:
+ return "HCI_ERR_QOS_REJECTED";
+ case HCI_ERR_CHAN_CLASSIF_NOT_SUPPORTED:
+ return "HCI_ERR_CHAN_CLASSIF_NOT_SUPPORTED";
+ case HCI_ERR_INSUFFCIENT_SECURITY:
+ return "HCI_ERR_INSUFFCIENT_SECURITY";
+ case HCI_ERR_PARAM_OUT_OF_RANGE:
+ return "HCI_ERR_PARAM_OUT_OF_RANGE";
+ case HCI_ERR_UNDEFINED_0x31:
+ return "HCI_ERR_UNDEFINED_0x31";
+ case HCI_ERR_ROLE_SWITCH_PENDING:
+ return "HCI_ERR_ROLE_SWITCH_PENDING";
+ case HCI_ERR_UNDEFINED_0x33:
+ return "HCI_ERR_UNDEFINED_0x33";
+ case HCI_ERR_RESERVED_SLOT_VIOLATION:
+ return "HCI_ERR_RESERVED_SLOT_VIOLATION";
+ case HCI_ERR_ROLE_SWITCH_FAILED:
+ return "HCI_ERR_ROLE_SWITCH_FAILED";
+ case HCI_ERR_INQ_RSP_DATA_TOO_LARGE:
+ return "HCI_ERR_INQ_RSP_DATA_TOO_LARGE";
+ case HCI_ERR_SIMPLE_PAIRING_NOT_SUPPORTED:
+ return "HCI_ERR_SIMPLE_PAIRING_NOT_SUPPORTED";
+ case HCI_ERR_HOST_BUSY_PAIRING:
+ return "HCI_ERR_HOST_BUSY_PAIRING";
+ case HCI_ERR_REJ_NO_SUITABLE_CHANNEL:
+ return "HCI_ERR_REJ_NO_SUITABLE_CHANNEL";
+ case HCI_ERR_CONTROLLER_BUSY:
+ return "HCI_ERR_CONTROLLER_BUSY";
+ case HCI_ERR_UNACCEPT_CONN_INTERVAL:
+ return "HCI_ERR_UNACCEPT_CONN_INTERVAL";
+ case HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT:
+ return "HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT";
+ case HCI_ERR_CONN_TOUT_DUE_TO_MIC_FAILURE:
+ return "HCI_ERR_CONN_TOUT_DUE_TO_MIC_FAILURE";
+ case HCI_ERR_CONN_FAILED_ESTABLISHMENT:
+ return "HCI_ERR_CONN_FAILED_ESTABLISHMENT";
+ case HCI_ERR_MAC_CONNECTION_FAILED:
+ return "HCI_ERR_MAC_CONNECTION_FAILED";
+ case HCI_ERR_LT_ADDR_ALREADY_IN_USE:
+ return "HCI_ERR_LT_ADDR_ALREADY_IN_USE";
+ case HCI_ERR_LT_ADDR_NOT_ALLOCATED:
+ return "HCI_ERR_LT_ADDR_NOT_ALLOCATED";
+ case HCI_ERR_CLB_NOT_ENABLED:
+ return "HCI_ERR_CLB_NOT_ENABLED";
+ case HCI_ERR_MAX_ERR:
+ return "HCI_ERR_MAX_ERR";
+ case HCI_ERR_ESP_VENDOR_FAIL:
+ return "HCI_ERR_ESP_VENDOR_FAIL";
+ case HCI_HINT_TO_RECREATE_AMP_PHYS_LINK:
+ return "HCI_HINT_TO_RECREATE_AMP_PHYS_LINK";
+ default:
+ return "Invalid HCI status code.";
+ }
+
+ return NULL;
+}
+#endif /* !UC_BT_STACK_NO_LOG */
+
+void btm_ble_extendadvcb_init(void)
+{
+ memset(&extend_adv_cb, 0, sizeof(tBTM_BLE_EXTENDED_CB));
+}
+
+void btm_ble_advrecod_init(void)
+{
+ memset(&adv_record[0], 0, sizeof(tBTM_EXT_ADV_RECORD)*MAX_BLE_ADV_INSTANCE);
+}
+
+void BTM_BleGapRegisterCallback(tBTM_BLE_5_HCI_CBACK cb)
+{
+ if (cb) {
+ ble_5_hci_cb = cb;
+ } else {
+ BTM_TRACE_ERROR("%s, register fail, the cb function is NULL.", __func__);
+ }
+}
+
+void BTM_ExtBleCallbackTrigger(tBTM_BLE_5_GAP_EVENT event, tBTM_BLE_5_GAP_CB_PARAMS *params)
+{
+ if(params && params->status == BTM_SUCCESS) {
+ btm_ble_inter_set(true);
+ }
+ if (ble_5_hci_cb) {
+ ble_5_hci_cb(event, params);
+ }
+}
+
+tBTM_STATUS BTM_BleReadPhy(BD_ADDR bd_addr, UINT8 *tx_phy, UINT8 *rx_phy)
+{
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (!tx_phy || !rx_phy || !p_lcb) {
+ cb_params.read_phy.status = BTM_ILLEGAL_VALUE;
+ memcpy(cb_params.read_phy.addr, bd_addr, BD_ADDR_LEN);
+
+ if (ble_5_hci_cb) {
+ ble_5_hci_cb(BTM_BLE_5_GAP_READ_PHY_COMPLETE_EVT, &cb_params);
+ }
+ BTM_TRACE_ERROR("%s, invalid parameters", __func__);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ btsnd_hcic_ble_read_phy(p_lcb->handle);
+
+ return BTM_SUCCESS;
+}
+
+tBTM_STATUS BTM_BleSetPreferDefaultPhy(UINT8 tx_phy_mask, UINT8 rx_phy_mask)
+{
+ UINT8 all_phys = 0;
+ tBTM_STATUS status = BTM_SUCCESS;
+ tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if ((err = btsnd_hcic_ble_set_prefered_default_phy(all_phys, tx_phy_mask, rx_phy_mask)) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = %s(0x%x)",
+ __func__, btm_ble_hci_status_to_str(err), err);
+ status = BTM_ILLEGAL_VALUE;
+ }
+
+ cb_params.set_perf_def_phy.status = err;
+
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_SET_PREFERED_DEFAULT_PHY_COMPLETE_EVT, &cb_params);
+
+ return status;
+
+}
+
+tBTM_STATUS BTM_BleSetPreferPhy(BD_ADDR bd_addr, UINT8 all_phys, UINT8 tx_phy_mask,
+ UINT8 rx_phy_mask, UINT16 phy_options)
+{
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (!p_lcb) {
+ cb_params.status = BTM_ILLEGAL_VALUE;
+ if (ble_5_hci_cb) {
+ ble_5_hci_cb(BTM_BLE_5_GAP_SET_PREFERED_PHY_COMPLETE_EVT, &cb_params);
+ }
+ BTM_TRACE_ERROR("%s, invalid parameters", __func__);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+
+
+ if (!btsnd_hcic_ble_set_phy(p_lcb->handle, all_phys, tx_phy_mask, rx_phy_mask, phy_options)) {
+ cb_params.status = BTM_ILLEGAL_VALUE;
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_SET_PREFERED_PHY_COMPLETE_EVT, &cb_params);
+ }
+
+
+ return BTM_SUCCESS;
+}
+
+tBTM_STATUS BTM_BleSetExtendedAdvRandaddr(UINT8 instance, BD_ADDR rand_addr)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+ tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (instance >= MAX_BLE_ADV_INSTANCE || rand_addr == NULL) {
+ status = BTM_ILLEGAL_VALUE;
+ goto end;
+ }
+
+ /*
+ A static address is a 48-bit randomly generated address and shall meet the following requirements:
+ • The two most significant bits of the address shall be equal to 1
+ • All bits of the random part of the address shall not be equal to 1
+ • All bits of the random part of the address shall not be equal to 0
+ */
+ BD_ADDR invalid_rand_addr_a, invalid_rand_addr_b;
+ memset(invalid_rand_addr_a, 0xff, sizeof(BD_ADDR));
+ memset(invalid_rand_addr_b, 0x00, sizeof(BD_ADDR));
+ if((rand_addr[0] & BT_STATIC_RAND_ADDR_MASK) == BT_STATIC_RAND_ADDR_MASK) {
+ invalid_rand_addr_b[0] = invalid_rand_addr_b[0] | BT_STATIC_RAND_ADDR_MASK;
+ if (memcmp(invalid_rand_addr_a, rand_addr, BD_ADDR_LEN) == 0
+ || memcmp(invalid_rand_addr_b, rand_addr, BD_ADDR_LEN) == 0) {
+ status = BTM_ILLEGAL_VALUE;
+ goto end;
+ }
+ } else if ((rand_addr[0] | BT_NON_RPA_MASK) == BT_NON_RPA_MASK) {
+ invalid_rand_addr_a[0] = invalid_rand_addr_a[0] & BT_NON_RPA_MASK;
+ if (memcmp(invalid_rand_addr_a, rand_addr, BD_ADDR_LEN) == 0
+ || memcmp(invalid_rand_addr_b, rand_addr, BD_ADDR_LEN) == 0) {
+ status = BTM_ILLEGAL_VALUE;
+ goto end;
+ }
+ } else {
+ BTM_TRACE_ERROR("%s invalid random address", __func__);
+ status = BTM_ILLEGAL_VALUE;
+ goto end;
+ }
+
+ // set random address
+ if((err = btsnd_hcic_ble_set_extend_rand_address(instance, rand_addr)) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("%s, fail to send the hci command, the error code = %s(0x%x)",
+ __func__, btm_ble_hci_status_to_str(err), err);
+ status = BTM_ILLEGAL_VALUE;
+ } else {
+ // set random address success, update address infor
+ if(extend_adv_cb.inst[instance].configured && extend_adv_cb.inst[instance].connetable) {
+ BTM_BleSetStaticAddr(rand_addr);
+ BTM_UpdateAddrInfor(BLE_ADDR_RANDOM, rand_addr);
+ }
+ }
+
+end:
+ cb_params.status = status;
+
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT, &cb_params);
+
+ return status;
+
+}
+tBTM_STATUS BTM_BleSetExtendedAdvParams(UINT8 instance, tBTM_BLE_GAP_EXT_ADV_PARAMS *params)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+ tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+ bool use_rpa_addr = false;
+ BD_ADDR rand_addr;
+
+ if (instance >= MAX_BLE_ADV_INSTANCE) {
+ status = BTM_ILLEGAL_VALUE;
+ BTM_TRACE_ERROR("%s invalid instance %d", __func__, instance);
+ goto end;
+ }
+
+ if ((status = btm_ble_ext_adv_params_validate(params)) != BTM_SUCCESS) {
+ BTM_TRACE_ERROR("%s, invalid extend adv params.", __func__);
+ }
+
+ if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_CONNECTABLE) {
+ extend_adv_cb.inst[instance].connetable = true;
+ } else {
+ extend_adv_cb.inst[instance].connetable = false;
+ }
+
+ if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_SCANNABLE) {
+ extend_adv_cb.inst[instance].scannable = true;
+ } else {
+ extend_adv_cb.inst[instance].scannable = false;
+ }
+
+ if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_LEGACY) {
+ extend_adv_cb.inst[instance].legacy_pdu = true;
+ } else {
+ extend_adv_cb.inst[instance].legacy_pdu = false;
+ }
+
+#if (CONTROLLER_RPA_LIST_ENABLE == FALSE)
+ // if own_addr_type == BLE_ADDR_PUBLIC_ID or BLE_ADDR_RANDOM_ID,
+ if((params->own_addr_type == BLE_ADDR_PUBLIC_ID || params->own_addr_type == BLE_ADDR_RANDOM_ID) && BTM_GetLocalResolvablePrivateAddr(rand_addr)) {
+ params->own_addr_type = BLE_ADDR_RANDOM;
+ use_rpa_addr = true;
+ } else if(params->own_addr_type == BLE_ADDR_PUBLIC_ID){
+ params->own_addr_type = BLE_ADDR_PUBLIC;
+ } else if (params->own_addr_type == BLE_ADDR_RANDOM_ID) {
+ params->own_addr_type = BLE_ADDR_RANDOM;
+ }
+#else
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type = params->own_addr_type;
+#endif
+
+ if ((err = btsnd_hcic_ble_set_ext_adv_params(instance, params->type, params->interval_min, params->interval_max,
+ params->channel_map, params->own_addr_type, params->peer_addr_type,
+ params->peer_addr, params->filter_policy, params->tx_power,
+ params->primary_phy, params->max_skip,
+ params->secondary_phy, params->sid, params->scan_req_notif)) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE EA SetParams: cmd err=0x%x", err);
+ status = BTM_ILLEGAL_VALUE;
+ goto end;
+ }
+
+ extend_adv_cb.inst[instance].configured = true;
+
+end:
+ if(use_rpa_addr) {
+ // update RPA address
+ if((err = btsnd_hcic_ble_set_extend_rand_address(instance, rand_addr)) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE EA SetParams: cmd err=0x%x", err);
+ status = BTM_ILLEGAL_VALUE;
+ } else {
+ // set addr success, update address infor
+ BTM_UpdateAddrInfor(BLE_ADDR_RANDOM, rand_addr);
+ }
+ }
+ cb_params.status = status;
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_EXT_ADV_SET_PARAMS_COMPLETE_EVT, &cb_params);
+
+ return status;
+}
+
+tBTM_STATUS BTM_BleConfigExtendedAdvDataRaw(BOOLEAN is_scan_rsp, UINT8 instance, UINT16 len, UINT8 *data)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+ tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+ UINT16 rem_len = len;
+ UINT8 operation = 0;
+ UINT16 data_offset = 0;
+
+
+ if ((status = btm_ble_ext_adv_set_data_validate(instance, len, data)) != BTM_SUCCESS) {
+ BTM_TRACE_ERROR("%s, invalid extend adv data.", __func__);
+ goto end;
+ }
+
+ do {
+ UINT8 send_data_len = (rem_len > BTM_BLE_EXT_ADV_DATA_LEN_MAX) ? BTM_BLE_EXT_ADV_DATA_LEN_MAX : rem_len;
+ if (len <= BTM_BLE_EXT_ADV_DATA_LEN_MAX) {
+ operation = BTM_BLE_ADV_DATA_OP_COMPLETE;
+ } else {
+ if (rem_len == len) {
+ operation = BTM_BLE_ADV_DATA_OP_FIRST_FRAG;
+ } else if (rem_len <= BTM_BLE_EXT_ADV_DATA_LEN_MAX) {
+ operation = BTM_BLE_ADV_DATA_OP_LAST_FRAG;
+ } else {
+ operation = BTM_BLE_ADV_DATA_OP_INTERMEDIATE_FRAG;
+ }
+ }
+ if (!is_scan_rsp) {
+ if ((err = btsnd_hcic_ble_set_ext_adv_data(instance, operation, 0, send_data_len, &data[data_offset])) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE EA SetAdvData: cmd err=0x%x", err);
+ status = BTM_ILLEGAL_VALUE;
+ }
+ } else {
+ if ((err = btsnd_hcic_ble_set_ext_adv_scan_rsp_data(instance, operation, 0, send_data_len, &data[data_offset])) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE EA SetScanRspData: cmd err=0x%x", err);
+ status = BTM_ILLEGAL_VALUE;
+ }
+ }
+
+ rem_len -= send_data_len;
+ data_offset += send_data_len;
+ } while (rem_len);
+
+end:
+ cb_params.status = status;
+ BTM_ExtBleCallbackTrigger(is_scan_rsp ? BTM_BLE_5_GAP_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT : BTM_BLE_5_GAP_EXT_ADV_DATA_SET_COMPLETE_EVT, &cb_params);
+
+ return status;
+}
+
+tBTM_STATUS BTM_BleStartExtAdv(BOOLEAN enable, UINT8 num, tBTM_BLE_EXT_ADV *ext_adv)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+ tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ UINT8 *instance = NULL;
+ UINT16 *duration = NULL;
+ UINT8 *max_events = NULL;
+
+ // when enable = true, ext_adv = NULL or num = 0, goto end
+ if ((!ext_adv || num == 0) && enable) {
+ status = BTM_ILLEGAL_VALUE;
+ BTM_TRACE_ERROR("%s invalid parameters", __func__);
+ goto end;
+ }
+
+ if (num != 0 && ext_adv != NULL) {
+ instance = osi_malloc(num);
+ duration = osi_malloc(num*sizeof(UINT16));
+ max_events = osi_malloc(num*sizeof(UINT8));
+
+ if (!instance || !duration || !max_events) {
+ status = BTM_NO_RESOURCES;
+ BTM_TRACE_ERROR("%s invalid parameters", __func__);
+ goto end;
+ }
+
+ for (int i = 0; i < num; i++) {
+ instance[i] = ext_adv[i].instance;
+ duration[i] = ext_adv[i].duration;
+ max_events[i] = ext_adv[i].max_events;
+ }
+
+ if ((err = btsnd_hcic_ble_ext_adv_enable(enable, num, instance,
+ duration, max_events)) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE EA En=%d: cmd err=0x%x", enable, err);
+ status = BTM_ILLEGAL_VALUE;
+ }
+
+ osi_free(instance);
+ osi_free(duration);
+ osi_free(max_events);
+ } else {
+ // enable = false, num == 0 or ext_adv = NULL
+
+ if ((err = btsnd_hcic_ble_ext_adv_enable(enable, num, NULL, NULL, NULL)) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE EA En=%d: cmd err=0x%x", enable, err);
+ status = BTM_ILLEGAL_VALUE;
+ }
+ goto end;
+ }
+
+
+
+end:
+
+ if (!enable && status == BTM_SUCCESS) {
+ // disable all ext adv
+ if(num == 0) {
+
+ for (uint8_t i = 0; i < MAX_BLE_ADV_INSTANCE; i++)
+ {
+ adv_record[i].invalid = false;
+ adv_record[i].instance = INVALID_VALUE;
+ adv_record[i].duration = INVALID_VALUE;
+ adv_record[i].max_events = INVALID_VALUE;
+ adv_record[i].retry_count = 0;
+ }
+ } else {
+ for (uint8_t i = 0; i < num; i++)
+ {
+ uint8_t index = ext_adv[i].instance;
+ adv_record[index].invalid = false;
+ adv_record[index].instance = INVALID_VALUE;
+ adv_record[index].duration = INVALID_VALUE;
+ adv_record[index].max_events = INVALID_VALUE;
+ adv_record[index].retry_count = 0;
+ }
+ }
+ }
+ // start extend adv success, save the adv information
+ if(enable && status == BTM_SUCCESS) {
+ for (uint8_t i = 0; i < num; i++)
+ {
+ uint8_t index = ext_adv[i].instance;
+ adv_record[index].invalid = true;
+ adv_record[index].instance = ext_adv[i].instance;
+ adv_record[index].duration = ext_adv[i].duration;
+ adv_record[index].max_events = ext_adv[i].max_events;
+ adv_record[index].retry_count = 0;
+ }
+ }
+
+ cb_params.status = status;
+ BTM_ExtBleCallbackTrigger(enable ? BTM_BLE_5_GAP_EXT_ADV_START_COMPLETE_EVT : BTM_BLE_5_GAP_EXT_ADV_STOP_COMPLETE_EVT, &cb_params);
+
+ return status;
+}
+
+tBTM_STATUS BTM_BleStartExtAdvRestart(uint8_t con_handle)
+{
+ tBTM_BLE_EXT_ADV ext_adv;
+ uint8_t index = INVALID_VALUE;
+ for (uint8_t i = 0; i < MAX_BLE_ADV_INSTANCE; i++)
+ {
+ if(adv_record[i].ter_con_handle == con_handle) {
+ index = i;
+ break;
+ }
+ }
+
+ if((index >= MAX_BLE_ADV_INSTANCE) || (!adv_record[index].invalid) || (adv_record[index].retry_count > GATTC_CONNECT_RETRY_COUNT)) {
+ return BTM_WRONG_MODE;
+ }
+
+ adv_record[index].retry_count ++;
+ BTM_TRACE_DEBUG("remote device did not reveive aux connect response, retatrt the extend adv to reconnect, adv handle %d con_handle %d\n", index, con_handle);
+ ext_adv.instance = adv_record[index].instance;
+ ext_adv.duration = adv_record[index].duration;
+ ext_adv.max_events = adv_record[index].max_events;
+ return BTM_BleStartExtAdv(true, 1, &ext_adv);
+}
+
+tBTM_STATUS BTM_BleExtAdvSetRemove(UINT8 instance)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+ tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (instance >= MAX_BLE_ADV_INSTANCE) {
+ status = BTM_ILLEGAL_VALUE;
+ BTM_TRACE_ERROR("%s invalid instance %d", __func__, instance);
+ goto end;
+ }
+
+ if ((err = btsnd_hcic_ble_remove_adv_set(instance)) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE EAS Rm: cmd err=0x%x", err);
+ status = BTM_ILLEGAL_VALUE;
+ } else {
+ extend_adv_cb.inst[instance].configured = false;
+ extend_adv_cb.inst[instance].legacy_pdu = false;
+ extend_adv_cb.inst[instance].directed = false;
+ extend_adv_cb.inst[instance].scannable = false;
+ extend_adv_cb.inst[instance].connetable = false;
+ }
+
+end:
+
+ cb_params.status = status;
+
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_EXT_ADV_SET_REMOVE_COMPLETE_EVT, &cb_params);
+
+ return status;
+}
+
+tBTM_STATUS BTM_BleExtAdvSetClear(void)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+ tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if ((err = btsnd_hcic_ble_clear_adv_set()) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE EAS Clr: cmd err=0x%x", err);
+ status = BTM_ILLEGAL_VALUE;
+ } else {
+ for (uint8_t i = 0; i < MAX_BLE_ADV_INSTANCE; i++) {
+ extend_adv_cb.inst[i].configured = false;
+ extend_adv_cb.inst[i].legacy_pdu = false;
+ extend_adv_cb.inst[i].directed = false;
+ extend_adv_cb.inst[i].scannable = false;
+ extend_adv_cb.inst[i].connetable = false;
+ }
+ }
+
+ cb_params.status = status;
+
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_EXT_ADV_SET_CLEAR_COMPLETE_EVT, &cb_params);
+
+ return status;
+}
+
+tBTM_STATUS BTM_BlePeriodicAdvSetParams(UINT8 instance, tBTM_BLE_Periodic_Adv_Params *params)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+ tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+ //ext_adv_flag = true;
+
+ if (instance >= MAX_BLE_ADV_INSTANCE) {
+ status = BTM_ILLEGAL_VALUE;
+ BTM_TRACE_ERROR("%s invalid instance %d", __func__, instance);
+ goto end;
+ }
+
+ if (!extend_adv_cb.inst[instance].configured ||
+ extend_adv_cb.inst[instance].scannable ||
+ extend_adv_cb.inst[instance].connetable ||
+ extend_adv_cb.inst[instance].legacy_pdu) {
+ BTM_TRACE_ERROR("%s, instance = %d, Before set the periodic adv parameters, please configure the the \
+ extend adv to nonscannable and nonconnectable first, and it shouldn't include the legacy bit.", __func__, instance);
+ status = BTM_ILLEGAL_VALUE;
+ goto end;
+ }
+
+ if ((err= btsnd_hcic_ble_set_periodic_adv_params(instance, params->interval_min,
+ params->interval_max, params->properties)) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE PA SetParams: cmd err=0x%x", err);
+ status = BTM_ILLEGAL_VALUE;
+ }
+
+end:
+
+ cb_params.status = status;
+
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT, &cb_params);
+
+ return status;
+}
+
+tBTM_STATUS BTM_BlePeriodicAdvCfgDataRaw(UINT8 instance, UINT16 len, UINT8 *data,BOOLEAN only_update_did)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+ tHCI_STATUS err = HCI_SUCCESS;
+ uint16_t rem_len = len;
+ UINT8 operation = 0;
+ UINT16 data_offset = 0;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+ if (only_update_did)
+ {
+ len = 0;
+ data = NULL;
+ rem_len = 0;
+ operation = BTM_BLE_ADV_DATA_OP_UNCHANGED_DATA;
+ }
+
+ if ((status = btm_ble_ext_adv_set_data_validate(instance, len, data)) != BTM_SUCCESS) {
+ BTM_TRACE_ERROR("%s, invalid extend adv data.", __func__);
+ goto end;
+ }
+
+ do {
+ UINT8 send_data_len = (rem_len > BTM_BLE_PERIODIC_ADV_DATA_LEN_MAX) ? BTM_BLE_PERIODIC_ADV_DATA_LEN_MAX : rem_len;
+
+ if (len <= BTM_BLE_PERIODIC_ADV_DATA_LEN_MAX) {
+ if (!only_update_did) {
+ operation = BTM_BLE_ADV_DATA_OP_COMPLETE;
+ }
+ } else {
+ if (rem_len == len) {
+ operation = BTM_BLE_ADV_DATA_OP_FIRST_FRAG;
+ } else if (rem_len <= BTM_BLE_PERIODIC_ADV_DATA_LEN_MAX) {
+ operation = BTM_BLE_ADV_DATA_OP_LAST_FRAG;
+ } else {
+ operation = BTM_BLE_ADV_DATA_OP_INTERMEDIATE_FRAG;
+ }
+ }
+
+ if ((err = btsnd_hcic_ble_set_periodic_adv_data(instance, operation, send_data_len, &data[data_offset])) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE PA SetData: cmd err=0x%x", err);
+ status = BTM_ILLEGAL_VALUE;
+ }
+ rem_len -= send_data_len;
+ data_offset += send_data_len;
+ } while(rem_len);
+
+end:
+ cb_params.status = status;
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_PERIODIC_ADV_DATA_SET_COMPLETE_EVT, &cb_params);
+
+ return status;
+}
+
+tBTM_STATUS BTM_BlePeriodicAdvEnable(UINT8 instance, UINT8 enable)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+ tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (instance >= MAX_BLE_ADV_INSTANCE) {
+ BTM_TRACE_ERROR("%s, invalid instance %d", __func__, instance);
+ status = BTM_ILLEGAL_VALUE;
+ goto end;
+ }
+
+ if ((err = btsnd_hcic_ble_periodic_adv_enable(enable, instance)) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE PA En=%d: cmd err=0x%x", enable, err);
+ status = BTM_ILLEGAL_VALUE;
+ }
+
+end:
+
+ cb_params.status = status;
+
+ BTM_ExtBleCallbackTrigger(enable ? BTM_BLE_5_GAP_PERIODIC_ADV_START_COMPLETE_EVT : BTM_BLE_5_GAP_PERIODIC_ADV_STOP_COMPLETE_EVT, &cb_params);
+
+ return status;
+
+}
+
+tBTM_STATUS BTM_BlePeriodicAdvCreateSync(tBTM_BLE_Periodic_Sync_Params *params)
+{
+ //tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_STATUS status = BTM_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (!params) {
+ status = BTM_ILLEGAL_VALUE;
+ BTM_TRACE_ERROR("%s, the parameter is NULL.", __func__);
+ goto end;
+ }
+
+ if ((params->sync_timeout < 0x0a || params->sync_timeout > 0x4000)
+ || (params->filter_policy > 0x01)
+ #if (CONFIG_BT_BLE_FEAT_CREATE_SYNC_ENH)
+ || (params->reports_disabled > 0x01)
+ || (params->filter_duplicates > 0x01)
+ #endif
+ || (params->addr_type > 0x01) ||
+ (params->sid > 0xf) || (params->skip > 0x01F3)) {
+ status = BTM_ILLEGAL_VALUE;
+ BTM_TRACE_ERROR("%s, The sync parameters is invalid.", __func__);
+ goto end;
+ }
+ uint8_t option = 0x00;
+ if (params->filter_policy) {
+ SET_BIT(option, 0);
+ }
+
+ #if (CONFIG_BT_BLE_FEAT_CREATE_SYNC_ENH)
+ if (params->reports_disabled) {
+ SET_BIT(option, 1);
+ }
+ if (params->filter_duplicates) {
+ SET_BIT(option, 2);
+ }
+ #endif
+
+ if (!btsnd_hcic_ble_periodic_adv_create_sync(option, params->sid, params->addr_type,
+ params->addr, params->sync_timeout, 0)) {
+ BTM_TRACE_ERROR("LE PA CreateSync cmd failed");
+ status = BTM_ILLEGAL_VALUE;
+ }
+
+end:
+ if(status != BTM_SUCCESS) {
+ cb_params.status = status;
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_PERIODIC_ADV_CREATE_SYNC_COMPLETE_EVT, &cb_params);
+ }
+
+ return status;
+}
+void btm_set_phy_callback(UINT8 status)
+{
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+ cb_params.status = status;
+
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_SET_PREFERED_PHY_COMPLETE_EVT, &cb_params);
+
+}
+void btm_create_sync_callback(UINT8 status)
+{
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+ cb_params.status = status;
+
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_PERIODIC_ADV_CREATE_SYNC_COMPLETE_EVT, &cb_params);
+}
+
+void btm_read_phy_callback(uint8_t hci_status, uint16_t conn_handle, uint8_t tx_phy, uint8_t rx_phy)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_handle(conn_handle);
+ if(hci_status != HCI_SUCCESS) {
+ status = BTM_ILLEGAL_VALUE;
+ BTM_TRACE_ERROR("%s error status %d", __func__, hci_status);
+ }
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+ if(p_lcb) {
+ memcpy(cb_params.read_phy.addr, p_lcb->remote_bd_addr, BD_ADDR_LEN);
+ }
+ cb_params.read_phy.status = status;
+ cb_params.read_phy.tx_phy = tx_phy;
+ cb_params.read_phy.rx_phy = rx_phy;
+
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_READ_PHY_COMPLETE_EVT, &cb_params);
+}
+
+tBTM_STATUS BTM_BlePeriodicAdvSyncCancel(void)
+{
+ tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_STATUS status = BTM_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if ((err = btsnd_hcic_ble_periodic_adv_create_sync_cancel()) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE PA SyncCancel, cmd err=0x%x", err);
+ status = BTM_ILLEGAL_VALUE;
+ }
+
+ cb_params.status = status;
+
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_PERIODIC_ADV_SYNC_CANCEL_COMPLETE_EVT, &cb_params);
+
+ return status;
+}
+
+tBTM_STATUS BTM_BlePeriodicAdvSyncTerm(UINT16 sync_handle)
+{
+ tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_STATUS status = BTM_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (( err = btsnd_hcic_ble_periodic_adv_term_sync(sync_handle)) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE PA SyncTerm: cmd err=0x%x", err);
+ status = BTM_ILLEGAL_VALUE;
+ }
+
+ cb_params.status = status;
+
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_PERIODIC_ADV_SYNC_TERMINATE_COMPLETE_EVT, &cb_params);
+
+ return status;
+}
+
+tBTM_STATUS BTM_BlePeriodicAdvAddDevToList(tBLE_ADDR_TYPE addr_type, BD_ADDR addr, UINT16 sid)
+{
+ tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_STATUS status = BTM_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (addr_type > BLE_ADDR_TYPE_MAX) {
+ status = BTM_ILLEGAL_VALUE;
+ BTM_TRACE_ERROR("%s invalid addr_type %d", __func__, addr_type);
+ goto end;
+ }
+
+ if ((err = btsnd_hcic_ble_add_dev_to_periodic_adv_list(addr_type, addr, sid)) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE PA AddDevToList: cmd err=0x%x", err);
+ status = BTM_ILLEGAL_VALUE;
+ }
+
+end:
+ cb_params.status = status;
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_PERIODIC_ADV_ADD_DEV_COMPLETE_EVT, &cb_params);
+
+ return status;
+}
+
+tBTM_STATUS BTM_BlePeriodicAdvRemoveDevFromList(tBLE_ADDR_TYPE addr_type, BD_ADDR addr, UINT16 sid)
+{
+ tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_STATUS status = BTM_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (addr_type > BLE_ADDR_TYPE_MAX) {
+ status = BTM_ILLEGAL_VALUE;
+ BTM_TRACE_ERROR("%s invalid addr_type %d", __func__, addr_type);
+ goto end;
+ }
+
+ if ((err = btsnd_hcic_ble_rm_dev_from_periodic_adv_list(addr_type, addr, sid)) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE PA RmDevFromList: cmd err=0x%x", err);
+ status = BTM_ILLEGAL_VALUE;
+ }
+
+end:
+
+ cb_params.status = status;
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_PERIODIC_ADV_REMOVE_DEV_COMPLETE_EVT, &cb_params);
+ return status;
+}
+
+tBTM_STATUS BTM_BlePeriodicAdvClearDev(void)
+{
+ tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_STATUS status = BTM_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if ((err = btsnd_hcic_ble_clear_periodic_adv_list()) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE PA ClrDev: cmd err=0x%x", err);
+ status = BTM_ILLEGAL_VALUE;
+ }
+
+ cb_params.status = status;
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_PERIODIC_ADV_CLEAR_DEV_COMPLETE_EVT, &cb_params);
+
+ return status;
+}
+
+tBTM_STATUS BTM_BleSetExtendedScanParams(tBTM_BLE_EXT_SCAN_PARAMS *params)
+{
+ UINT8 phy_mask = 0;
+ tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_STATUS status = BTM_SUCCESS;
+ tHCI_EXT_SCAN_PARAMS hci_params[2];
+ int phy_count = 0;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (!params) {
+ status = BTM_ILLEGAL_VALUE;
+ BTM_TRACE_ERROR("%s invalid parameters", __func__);
+ goto end;
+ }
+
+ if (params->own_addr_type > BLE_ADDR_TYPE_MAX) {
+ status = BTM_ILLEGAL_VALUE;
+ goto end;
+ }
+
+ if (params->cfg_mask & BTM_BLE_GAP_EXT_SCAN_UNCODE_MASK) {
+ phy_mask |= 0x01;
+ memcpy(&hci_params[phy_count], &params->uncoded_cfg, sizeof(tHCI_EXT_SCAN_PARAMS));
+ phy_count++;
+ }
+
+ if (params->cfg_mask & BTM_BLE_GAP_EXT_SCAN_CODE_MASK) {
+ phy_mask |= 0x04;
+ memcpy(&hci_params[phy_count], &params->coded_cfg, sizeof(tHCI_EXT_SCAN_PARAMS));
+ phy_count++;
+ }
+
+ if (BTM_BleUpdateOwnType(&params->own_addr_type, NULL) != 0 ) {
+ status = BTM_ILLEGAL_VALUE;
+ BTM_TRACE_ERROR("LE UpdateOwnType err");
+ goto end;
+ }
+
+ extend_adv_cb.scan_duplicate = params->scan_duplicate;
+
+ if ((err = btsnd_hcic_ble_set_ext_scan_params(params->own_addr_type, params->filter_policy, phy_mask, phy_count,
+ hci_params)) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE ES SetParams: cmd err=0x%x", err);
+ status = BTM_ILLEGAL_VALUE;
+ }
+
+end:
+
+ cb_params.status = status;
+
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_SET_EXT_SCAN_PARAMS_COMPLETE_EVT, &cb_params);
+
+ return cb_params.status;
+}
+
+tBTM_STATUS BTM_BleExtendedScan(BOOLEAN enable, UINT16 duration, UINT16 period)
+{
+ tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ if (extend_adv_cb.scan_duplicate > 0x03) {
+ status = BTM_ILLEGAL_VALUE;
+ BTM_TRACE_ERROR("%s invalid scan_duplicate %d", __func__, extend_adv_cb.scan_duplicate);
+ goto end;
+ }
+
+ if ((err = btsnd_hcic_ble_ext_scan_enable(enable, extend_adv_cb.scan_duplicate, duration, period)) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("LE ES En=%d: cmd err=0x%x", enable, err);
+ status = BTM_ILLEGAL_VALUE;
+ }
+
+end:
+
+ cb_params.status = status;
+
+ BTM_ExtBleCallbackTrigger(enable ? BTM_BLE_5_GAP_EXT_SCAN_START_COMPLETE_EVT : BTM_BLE_5_GAP_EXT_SCAN_STOP_COMPLETE_EVT, &cb_params);
+
+ return status;
+}
+
+void BTM_BleSetPreferExtenedConnParams (BD_ADDR bd_addr, tBTM_EXT_CONN_PARAMS *params)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (bd_addr);
+
+ if (p_dev_rec) {
+ if (params) {
+ memcpy(&p_dev_rec->ext_conn_params, params, sizeof(tBTM_EXT_CONN_PARAMS));
+ } else {
+ BTM_TRACE_ERROR("Invalid Extand connection parameters");
+ }
+ } else {
+ BTM_TRACE_ERROR("Unknown Device, setting rejected");
+ }
+
+ return;
+}
+
+void btm_ble_extended_init(void)
+{
+
+}
+
+void btm_ble_extended_cleanup(void)
+{
+
+}
+
+static tBTM_STATUS btm_ble_ext_adv_params_validate(tBTM_BLE_GAP_EXT_ADV_PARAMS *params)
+{
+ if (!params) {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ if (params->own_addr_type > BLE_ADDR_TYPE_MAX) {
+ BTM_TRACE_ERROR("%s, invalid own address type, line %d, addr type %d", __func__, __LINE__, params->own_addr_type);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_LEGACY) {
+ /* Not allowed for legacy PDUs. */
+ if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_INCLUDE_TX_PWR) {
+ BTM_TRACE_ERROR("%s, The Legacy adv can't include tx power bit, line %d", __func__, __LINE__);
+ return BTM_ILLEGAL_VALUE;
+ }
+ }
+
+ if (!(params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_LEGACY)) {
+ /* Not allowed for extended advertising PDUs */
+ if ((params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_CONNECTABLE) &&
+ (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_SCANNABLE)) {
+ BTM_TRACE_ERROR("%s, For the Extend adv, the properties can't be connectable and scannable at the same time, line %d", __func__, __LINE__);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ /* HD directed advertising allowed only for legacy PDUs */
+ if (params->type & BTM_BLE_GAP_SET_EXT_ADV_PROP_HD_DIRECTED) {
+ BTM_TRACE_ERROR("%s, HD directed advertising allowed only for legacy PDUs. line %d", __func__, __LINE__);
+ return BTM_ILLEGAL_VALUE;
+ }
+ }
+
+ return BTM_SUCCESS;
+}
+
+static tBTM_STATUS btm_ble_ext_adv_set_data_validate(UINT8 instance, UINT16 len, UINT8 *data)
+{
+ if (data == NULL && len > 0) {
+ BTM_TRACE_ERROR("%s, the extend adv data is NULL. line %d", __func__, __LINE__);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ if (instance >= MAX_BLE_ADV_INSTANCE) {
+ BTM_TRACE_ERROR("%s, adv instance is %d, Exceeded the maximum. line %d", __func__, instance, __LINE__);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ if (!extend_adv_cb.inst[instance].configured) {
+ BTM_TRACE_ERROR("%s, The extend adv hasn't configured, please use the set_ext_adv_params API to set the ext adv parameters first. line %d", __func__, __LINE__);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ /* Not allowed with the direted advertising for legacy */
+ if (extend_adv_cb.inst[instance].legacy_pdu && extend_adv_cb.inst[instance].directed) {
+ BTM_TRACE_ERROR("%s, Not allowed with the direted advertising for legacy. line %d", __func__, __LINE__);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ /* Always allowed with legacy PDU but limited to legacy length */
+ if (extend_adv_cb.inst[instance].legacy_pdu) {
+ if (len > 31) {
+ BTM_TRACE_ERROR("%s, for the legacy adv, the adv data length can't exceed 31. line %d", __func__, __LINE__);
+ return BTM_ILLEGAL_VALUE;
+ }
+ } else {
+ if (len > controller_get_interface()->ble_get_ext_adv_data_max_len()) {
+ BTM_TRACE_ERROR("%s, The adv data len(%d) is longer then the controller adv max len(%d)",
+ __func__, len, controller_get_interface()->ble_get_ext_adv_data_max_len());
+ return BTM_ILLEGAL_VALUE;
+ }
+ }
+
+ return BTM_SUCCESS;
+}
+
+void btm_ble_update_phy_evt(tBTM_BLE_UPDATE_PHY *params)
+{
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (!params) {
+ BTM_TRACE_ERROR("%s, Invalid params.", __func__);
+ return;
+ }
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_handle(params->conn_idx);
+ if(!p_lcb) {
+ BTM_TRACE_ERROR("%s, Invalid params.", __func__);
+ return;
+ }
+
+ cb_params.phy_update.status = params->status;
+ cb_params.phy_update.tx_phy = params->tx_phy;
+ cb_params.phy_update.rx_phy = params->rx_phy;
+ memcpy(cb_params.phy_update.addr, p_lcb->remote_bd_addr, BD_ADDR_LEN);
+
+ // If the user has register the callback function, should callback it to the application.
+
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_PHY_UPDATE_COMPLETE_EVT, &cb_params);
+
+ return;
+}
+
+void btm_ble_scan_timeout_evt(void)
+{
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_SCAN_TIMEOUT_EVT, NULL);
+}
+
+void btm_ble_adv_set_terminated_evt(tBTM_BLE_ADV_TERMINAT *params)
+{
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (!params) {
+ BTM_TRACE_ERROR("%s, Invalid params.", __func__);
+ return;
+ }
+
+ // adv terminated due to connection, save the adv handle and connection handle
+ if(params->completed_event == 0x00) {
+ adv_record[params->adv_handle].ter_con_handle = params->conn_handle;
+ } else {
+ adv_record[params->adv_handle].ter_con_handle = INVALID_VALUE;
+ adv_record[params->adv_handle].invalid = false;
+ }
+
+ memcpy(&cb_params.adv_term, params, sizeof(tBTM_BLE_ADV_TERMINAT));
+
+ // If the user has register the callback function, should callback it to the application.
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_ADV_TERMINATED_EVT, &cb_params);
+
+ return;
+}
+
+void btm_ble_ext_adv_report_evt(tBTM_BLE_EXT_ADV_REPORT *params)
+{
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (!params) {
+ BTM_TRACE_ERROR("%s, Invalid params.", __func__);
+ return;
+ }
+
+ memcpy(&cb_params.ext_adv_report, params, sizeof(tBTM_BLE_EXT_ADV_REPORT));
+
+ // If the user has register the callback function, should callback it to the application.
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_EXT_ADV_REPORT_EVT, &cb_params);
+
+ return;
+
+}
+
+void btm_ble_scan_req_received_evt(tBTM_BLE_SCAN_REQ_RECEIVED *params)
+{
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (!params) {
+ BTM_TRACE_ERROR("%s, Invalid params.", __func__);
+ return;
+ }
+
+ memcpy(&cb_params.scan_req, params, sizeof(tBTM_BLE_SCAN_REQ_RECEIVED));
+
+ // If the user has register the callback function, should callback it to the application.
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_SCAN_REQ_RECEIVED_EVT, &cb_params);
+
+ return;
+}
+
+void btm_ble_channel_select_algorithm_evt(tBTM_BLE_CHANNEL_SEL_ALG *params)
+{
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (!params) {
+ BTM_TRACE_ERROR("%s, Invalid params.", __func__);
+ return;
+ }
+
+ memcpy(&cb_params.channel_sel, params, sizeof(tBTM_BLE_CHANNEL_SEL_ALG));
+
+ // If the user has register the callback function, should callback it to the application.
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_CHANNEL_SELETE_ALGORITHM_EVT, &cb_params);
+
+ return;
+}
+
+void btm_ble_periodic_adv_report_evt(tBTM_PERIOD_ADV_REPORT *params)
+{
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (!params) {
+ BTM_TRACE_ERROR("%s, Invalid params.", __func__);
+ return;
+ }
+
+ memcpy(&cb_params.period_adv_report, params, sizeof(tBTM_PERIOD_ADV_REPORT));
+
+ // If the user has register the callback function, should callback it to the application.
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_PERIODIC_ADV_REPORT_EVT, &cb_params);
+
+ return;
+
+}
+
+void btm_ble_periodic_adv_sync_lost_evt(tBTM_BLE_PERIOD_ADV_SYNC_LOST *params)
+{
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (!params) {
+ BTM_TRACE_ERROR("%s, Invalid params.", __func__);
+ return;
+ }
+
+ memcpy(&cb_params.sync_lost, params, sizeof(tBTM_BLE_PERIOD_ADV_SYNC_LOST));
+
+ // If the user has register the callback function, should callback it to the application.
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_PERIODIC_ADV_SYNC_LOST_EVT, &cb_params);
+
+ return;
+
+}
+
+void btm_ble_periodic_adv_sync_establish_evt(tBTM_BLE_PERIOD_ADV_SYNC_ESTAB *params)
+{
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (!params) {
+ BTM_TRACE_ERROR("%s, Invalid params.", __func__);
+ return;
+ }
+
+ memcpy(&cb_params.sync_estab, params, sizeof(tBTM_BLE_PERIOD_ADV_SYNC_ESTAB));
+
+ // If the user has register the callback function, should callback it to the application.
+ BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_PERIODIC_ADV_SYNC_ESTAB_EVT, &cb_params);
+
+ return;
+
+}
+
+#endif // #if (BLE_50_FEATURE_SUPPORT == TRUE)
+
+#if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE)
+void btm_ble_periodic_adv_sync_trans_complete(UINT16 op_code, UINT8 hci_status, UINT16 conn_handle)
+{
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+ UINT8 evt = BTM_BLE_5_GAP_UNKNOWN_EVT;
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_handle(conn_handle);
+
+ switch (op_code) {
+ case HCI_BLE_PERIOD_ADV_SYNC_TRANS:
+ evt = BTM_BLE_GAP_PERIODIC_ADV_SYNC_TRANS_COMPLETE_EVT;
+ break;
+ case HCI_BLE_PERIOD_ADV_SET_INFO_TRANS:
+ evt = BTM_BLE_GAP_PERIODIC_ADV_SET_INFO_TRANS_COMPLETE_EVT;
+ break;
+ case HCI_BLE_SET_PAST_PARAMS:
+ evt = BTM_BLE_GAP_SET_PAST_PARAMS_COMPLETE_EVT;
+ break;
+ default:
+ return;
+ }
+
+ cb_params.per_adv_sync_trans.status = BTM_SUCCESS;
+ if(hci_status != HCI_SUCCESS) {
+ cb_params.per_adv_sync_trans.status = BTM_ILLEGAL_VALUE;
+ BTM_TRACE_ERROR("%s error status %d", __func__, hci_status);
+ }
+
+ if(p_lcb) {
+ memcpy(cb_params.per_adv_sync_trans.addr, p_lcb->remote_bd_addr, BD_ADDR_LEN);
+ }
+
+ BTM_ExtBleCallbackTrigger(evt, &cb_params);
+}
+
+void BTM_BlePeriodicAdvRecvEnable(UINT16 sync_handle, UINT8 enable)
+{
+ tHCI_STATUS err = HCI_SUCCESS;
+ tBTM_STATUS status = BTM_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if ((err = btsnd_hcic_ble_set_periodic_adv_recv_enable(sync_handle, enable)) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("%s cmd err=0x%x", __func__, err);
+ status = BTM_ILLEGAL_VALUE;
+ }
+
+ cb_params.status = status;
+ BTM_ExtBleCallbackTrigger(BTM_BLE_GAP_PERIODIC_ADV_RECV_ENABLE_COMPLETE_EVT, &cb_params);
+}
+
+void BTM_BlePeriodicAdvSyncTrans(BD_ADDR bd_addr, UINT16 service_data, UINT16 sync_handle)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
+ if (!p_lcb) {
+ BTM_TRACE_ERROR("%s, invalid parameters", __func__);
+ status = BTM_ILLEGAL_VALUE;
+ }
+
+ if (status != BTM_SUCCESS) {
+ cb_params.per_adv_sync_trans.status = status;
+ memcpy(cb_params.per_adv_sync_trans.addr, bd_addr, sizeof(BD_ADDR));
+ BTM_ExtBleCallbackTrigger(BTM_BLE_GAP_PERIODIC_ADV_SYNC_TRANS_COMPLETE_EVT, &cb_params);
+ return;
+ }
+
+ btsnd_hcic_ble_periodic_adv_sync_trans(p_lcb->handle, service_data, sync_handle);
+}
+
+void BTM_BlePeriodicAdvSetInfoTrans(BD_ADDR bd_addr, UINT16 service_data, UINT8 adv_handle)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
+
+ if (!p_lcb) {
+ BTM_TRACE_ERROR("%s, invalid parameters", __func__);
+ status = BTM_ILLEGAL_VALUE;
+ }
+
+ if (status != BTM_SUCCESS) {
+ cb_params.per_adv_sync_trans.status = status;
+ memcpy(cb_params.per_adv_sync_trans.addr, bd_addr, sizeof(BD_ADDR));
+ BTM_ExtBleCallbackTrigger(BTM_BLE_GAP_PERIODIC_ADV_SET_INFO_TRANS_COMPLETE_EVT, &cb_params);
+ return;
+ }
+
+ btsnd_hcic_ble_periodic_adv_set_info_trans(p_lcb->handle, service_data, adv_handle);
+}
+
+void BTM_BleSetPeriodicAdvSyncTransParams(BD_ADDR bd_addr, UINT8 mode, UINT16 skip, UINT16 sync_timeout, UINT8 cte_type)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ // Set default past params
+ if (bdaddr_is_empty((bt_bdaddr_t *)bd_addr)) {
+ tHCI_STATUS err = HCI_SUCCESS;
+ if ((err = btsnd_hcic_ble_set_default_periodic_adv_sync_trans_params(mode, skip, sync_timeout, cte_type)) != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("%s cmd err=0x%x", __func__, err);
+ status = BTM_ILLEGAL_VALUE;
+ }
+
+ cb_params.set_past_params.status = status;
+ memset(cb_params.set_past_params.addr, 0, sizeof(BD_ADDR));
+ BTM_ExtBleCallbackTrigger(BTM_BLE_GAP_SET_PAST_PARAMS_COMPLETE_EVT, &cb_params);
+ return;
+ }
+
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
+ if (!p_lcb) {
+ BTM_TRACE_ERROR("%s, invalid parameters", __func__);
+ status = BTM_ILLEGAL_VALUE;
+ }
+
+ if (status != BTM_SUCCESS) {
+ cb_params.set_past_params.status = status;
+ memcpy(cb_params.set_past_params.addr, bd_addr, sizeof(BD_ADDR));
+ BTM_ExtBleCallbackTrigger(BTM_BLE_GAP_SET_PAST_PARAMS_COMPLETE_EVT, &cb_params);
+ return;
+ }
+
+ btsnd_hcic_ble_set_periodic_adv_sync_trans_params(p_lcb->handle, mode, skip, sync_timeout, cte_type);
+}
+
+void btm_ble_periodic_adv_sync_trans_recv_evt(tBTM_BLE_PERIOD_ADV_SYNC_TRANS_RECV *params)
+{
+ tBTM_BLE_5_GAP_CB_PARAMS cb_params = {0};
+
+ if (!params) {
+ BTM_TRACE_ERROR("%s, Invalid params.", __func__);
+ return;
+ }
+
+ memcpy(&cb_params.past_recv, params, sizeof(tBTM_BLE_PERIOD_ADV_SYNC_TRANS_RECV));
+
+ BTM_ExtBleCallbackTrigger(BTM_BLE_GAP_PERIODIC_ADV_SYNC_TRANS_RECV_EVT, &cb_params);
+}
+#endif // #if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE)
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_ble_addr.c b/lib/bt/host/bluedroid/stack/btm/btm_ble_addr.c
new file mode 100644
index 00000000..d7ed2095
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_ble_addr.c
@@ -0,0 +1,608 @@
+/******************************************************************************
+ *
+ * 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 functions for BLE address management.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "stack/bt_types.h"
+#include "stack/hcimsgs.h"
+#include "stack/btu.h"
+#include "btm_int.h"
+#include "stack/gap_api.h"
+#include "device/controller.h"
+
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+#include "btm_ble_int.h"
+#include "stack/smp_api.h"
+
+
+/*******************************************************************************
+**
+** Function btm_gen_resolve_paddr_cmpl
+**
+** Description This is callback functioin when resolvable private address
+** generation is complete.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_gen_resolve_paddr_cmpl(tSMP_ENC *p)
+{
+ tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ BTM_TRACE_EVENT ("btm_gen_resolve_paddr_cmpl");
+
+ if (p) {
+ /* set hash to be LSB of rpAddress */
+ p_cb->private_addr[5] = p->param_buf[0];
+ p_cb->private_addr[4] = p->param_buf[1];
+ p_cb->private_addr[3] = p->param_buf[2];
+
+ /* set it to controller */
+ btm_ble_set_random_addr(p_cb->private_addr);
+
+ p_cb->exist_addr_bit |= BTM_BLE_GAP_ADDR_BIT_RESOLVABLE;
+ memcpy(p_cb->resolvale_addr, p_cb->private_addr, BD_ADDR_LEN);
+ if (p_cb->set_local_privacy_cback){
+ (*p_cb->set_local_privacy_cback)(BTM_SET_PRIVACY_SUCCESS);
+ p_cb->set_local_privacy_cback = NULL;
+ }
+
+ /* start a periodical timer to refresh random addr */
+ btu_stop_timer_oneshot(&p_cb->raddr_timer_ent);
+#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
+ btu_start_timer_oneshot(&p_cb->raddr_timer_ent, BTU_TTYPE_BLE_RANDOM_ADDR,
+ btm_cb.ble_ctr_cb.rpa_tout);
+#else
+ btu_start_timer_oneshot(&p_cb->raddr_timer_ent, BTU_TTYPE_BLE_RANDOM_ADDR,
+ BTM_BLE_PRIVATE_ADDR_INT);
+#endif
+ } else {
+ /* random address set failure */
+ BTM_TRACE_DEBUG("set random address failed");
+ if (p_cb->set_local_privacy_cback){
+ (*p_cb->set_local_privacy_cback)(BTM_SET_PRIVACY_FAIL);
+ p_cb->set_local_privacy_cback = NULL;
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function btm_gen_resolve_paddr_low
+**
+** Description This function is called when random address has generate the
+** random number base for low 3 byte bd address.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_gen_resolve_paddr_low(tBTM_RAND_ENC *p)
+{
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tSMP_ENC output;
+
+ BTM_TRACE_EVENT ("btm_gen_resolve_paddr_low");
+ if (p) {
+ p->param_buf[2] &= (~BLE_RESOLVE_ADDR_MASK);
+ p->param_buf[2] |= BLE_RESOLVE_ADDR_MSB;
+
+ p_cb->private_addr[2] = p->param_buf[0];
+ p_cb->private_addr[1] = p->param_buf[1];
+ p_cb->private_addr[0] = p->param_buf[2];
+
+ /* encrypt with ur IRK */
+ if (!SMP_Encrypt(btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN, p->param_buf, 3, &output)) {
+ btm_gen_resolve_paddr_cmpl(NULL);
+ } else {
+ btm_gen_resolve_paddr_cmpl(&output);
+ }
+ }
+#endif
+}
+/*******************************************************************************
+**
+** Function btm_gen_resolvable_private_addr
+**
+** Description This function generate a resolvable private address.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_gen_resolvable_private_addr (void *p_cmd_cplt_cback)
+{
+ BTM_TRACE_EVENT ("btm_gen_resolvable_private_addr");
+ /* generate 3B rand as BD LSB, SRK with it, get BD MSB */
+ if (!btsnd_hcic_ble_rand((void *)p_cmd_cplt_cback)) {
+ btm_gen_resolve_paddr_cmpl(NULL);
+ }
+}
+/*******************************************************************************
+**
+** Function btm_gen_non_resolve_paddr_cmpl
+**
+** Description This is the callback function when non-resolvable private
+** function is generated and write to controller.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_gen_non_resolve_paddr_cmpl(tBTM_RAND_ENC *p)
+{
+ tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tBTM_BLE_ADDR_CBACK *p_cback = p_cb->p_generate_cback;
+ void *p_data = p_cb->p;
+ UINT8 *pp;
+ BD_ADDR static_random;
+
+ BTM_TRACE_EVENT ("btm_gen_non_resolve_paddr_cmpl");
+
+ p_cb->p_generate_cback = NULL;
+ if (p) {
+
+ pp = p->param_buf;
+ STREAM_TO_BDADDR(static_random, pp);
+ /* mask off the 2 MSB */
+ static_random[0] &= BLE_STATIC_PRIVATE_MSB_MASK;
+
+ /* report complete */
+ if (p_cback) {
+ (* p_cback)(static_random, p_data);
+ }
+ } else {
+ BTM_TRACE_DEBUG("btm_gen_non_resolvable_private_addr failed");
+ if (p_cback) {
+ (* p_cback)(NULL, p_data);
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function btm_gen_non_resolvable_private_addr
+**
+** Description This function generate a non-resolvable private address.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_gen_non_resolvable_private_addr (tBTM_BLE_ADDR_CBACK *p_cback, void *p)
+{
+ tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+
+ BTM_TRACE_EVENT ("btm_gen_non_resolvable_private_addr");
+
+ if (p_mgnt_cb->p_generate_cback != NULL) {
+ return;
+ }
+
+ p_mgnt_cb->p_generate_cback = p_cback;
+ p_mgnt_cb->p = p;
+ if (!btsnd_hcic_ble_rand((void *)btm_gen_non_resolve_paddr_cmpl)) {
+ btm_gen_non_resolve_paddr_cmpl(NULL);
+ }
+
+}
+
+/*******************************************************************************
+** Utility functions for Random address resolving
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function btm_ble_resolve_address_cmpl
+**
+** Description This function sends the random address resolving complete
+** callback.
+**
+** Returns None.
+**
+*******************************************************************************/
+#if SMP_INCLUDED == TRUE
+static void btm_ble_resolve_address_cmpl(void)
+{
+ tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+
+ BTM_TRACE_EVENT ("btm_ble_resolve_address_cmpl p_mgnt_cb->p_dev_rec = 0x%08x", (uint32_t)p_mgnt_cb->p_dev_rec);
+
+ p_mgnt_cb->busy = FALSE;
+
+ (* p_mgnt_cb->p_resolve_cback)(p_mgnt_cb->p_dev_rec, p_mgnt_cb->p);
+}
+/*******************************************************************************
+**
+** Function btm_ble_proc_resolve_x
+**
+** Description This function compares the X with random address 3 MSO bytes
+** to find a match, if not match, continue for next record.
+**
+** Returns None.
+**
+*******************************************************************************/
+static BOOLEAN btm_ble_proc_resolve_x(tSMP_ENC *p)
+{
+ tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ UINT8 comp[3];
+ BTM_TRACE_EVENT ("btm_ble_proc_resolve_x");
+ /* compare the hash with 3 LSB of bd address */
+ comp[0] = p_mgnt_cb->random_bda[5];
+ comp[1] = p_mgnt_cb->random_bda[4];
+ comp[2] = p_mgnt_cb->random_bda[3];
+
+ if (p) {
+ if (!memcmp(p->param_buf, &comp[0], 3)) {
+ /* match is found */
+ BTM_TRACE_EVENT ("match is found");
+ btm_ble_resolve_address_cmpl();
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_ble_init_pseudo_addr
+**
+** Description This function is used to initialize pseudo address.
+** If pseudo address is not available, use dummy address
+**
+** Returns TRUE is updated; FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_init_pseudo_addr (tBTM_SEC_DEV_REC *p_dev_rec, BD_ADDR new_pseudo_addr)
+{
+#if (SMP_INCLUDED == TRUE)
+ BD_ADDR dummy_bda = {0};
+
+ if (memcmp(p_dev_rec->ble.pseudo_addr, dummy_bda, BD_ADDR_LEN) == 0) {
+ memcpy(p_dev_rec->ble.pseudo_addr, new_pseudo_addr, BD_ADDR_LEN);
+ return TRUE;
+ }
+#endif ///SMP_INCLUDED == TRUE
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_addr_resolvable
+**
+** Description This function checks if a RPA is resolvable by the device key.
+**
+** Returns TRUE is resolvable; FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_addr_resolvable (BD_ADDR rpa, tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ BOOLEAN rt = FALSE;
+#if (SMP_INCLUDED == TRUE)
+ if (!BTM_BLE_IS_RESOLVE_BDA(rpa)) {
+ return rt;
+ }
+
+ UINT8 rand[3];
+ tSMP_ENC output;
+ if ((p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) &&
+ (p_dev_rec->ble.key_type & BTM_LE_KEY_PID)) {
+ BTM_TRACE_DEBUG("%s try to resolve", __func__);
+ /* use the 3 MSB of bd address as prand */
+ rand[0] = rpa[2];
+ rand[1] = rpa[1];
+ rand[2] = rpa[0];
+
+ /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */
+ SMP_Encrypt(p_dev_rec->ble.keys.irk, BT_OCTET16_LEN,
+ &rand[0], 3, &output);
+
+ rand[0] = rpa[5];
+ rand[1] = rpa[4];
+ rand[2] = rpa[3];
+
+ if (!memcmp(output.param_buf, &rand[0], 3)) {
+ btm_ble_init_pseudo_addr (p_dev_rec, rpa);
+ rt = TRUE;
+ }
+ }
+#endif ///SMP_INCLUDED == TRUE
+ return rt;
+}
+
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function btm_ble_match_random_bda
+**
+** Description This function match the random address to the appointed device
+** record, starting from calculating IRK. If record index exceed
+** the maximum record number, matching failed and send callback.
+**
+** Returns None.
+**
+*******************************************************************************/
+static BOOLEAN btm_ble_match_random_bda(tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ /* use the 3 MSB of bd address as prand */
+
+ tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ UINT8 rand[3];
+ rand[0] = p_mgnt_cb->random_bda[2];
+ rand[1] = p_mgnt_cb->random_bda[1];
+ rand[2] = p_mgnt_cb->random_bda[0];
+
+ BTM_TRACE_EVENT("%s p_dev_rec = 0x%08x", __func__, (uint32_t)p_dev_rec);
+
+ {
+ tSMP_ENC output;
+
+ BTM_TRACE_DEBUG("sec_flags = %02x device_type = %d", p_dev_rec->sec_flags,
+ p_dev_rec->device_type);
+
+ if ((p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) &&
+ (p_dev_rec->ble.key_type & BTM_LE_KEY_PID)) {
+ /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */
+ SMP_Encrypt(p_dev_rec->ble.keys.irk, BT_OCTET16_LEN,
+ &rand[0], 3, &output);
+ return btm_ble_proc_resolve_x(&output);
+ } else {
+ // not completed
+ return FALSE;
+ }
+ }
+}
+#endif ///BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_ble_resolve_random_addr
+**
+** Description This function is called to resolve a random address.
+**
+** Returns pointer to the security record of the device whom a random
+** address is matched to.
+**
+*******************************************************************************/
+void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK *p_cback, void *p)
+{
+#if (SMP_INCLUDED == TRUE)
+ tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ list_node_t *p_node = NULL;
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+
+ BTM_TRACE_EVENT ("btm_ble_resolve_random_addr");
+ if ( !p_mgnt_cb->busy) {
+ p_mgnt_cb->p = p;
+ p_mgnt_cb->busy = TRUE;
+ p_mgnt_cb->p_dev_rec = NULL;
+ p_mgnt_cb->p_resolve_cback = p_cback;
+ memcpy(p_mgnt_cb->random_bda, random_bda, BD_ADDR_LEN);
+ /* start to resolve random address */
+ /* check for next security record */
+ for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
+ p_dev_rec = list_node(p_node);
+ p_mgnt_cb->p_dev_rec = p_dev_rec;
+ if (btm_ble_match_random_bda(p_dev_rec)) {
+ break;
+ }
+ p_mgnt_cb->p_dev_rec = NULL;
+ }
+ btm_ble_resolve_address_cmpl();
+ } else {
+ (*p_cback)(NULL, p);
+ }
+#endif
+
+}
+
+
+/*******************************************************************************
+** address mapping between pseudo address and real connection address
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function btm_find_dev_by_identity_addr
+**
+** Description find the security record whose LE static address is matching
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_find_dev_by_identity_addr(BD_ADDR bd_addr, UINT8 addr_type)
+{
+#if BLE_PRIVACY_SPT == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+ list_node_t *p_node = NULL;
+ tSecDevContext context;
+ context.type = SEC_DEV_ID_ADDR;
+ context.context.p_bd_addr = bd_addr;
+ context.free_check = FALSE;
+ p_node = list_foreach(btm_cb.p_sec_dev_rec_list, btm_find_sec_dev_in_list, &context);
+ if (p_node) {
+ p_dev_rec = list_node(p_node);
+ if ((p_dev_rec->ble.static_addr_type & (~BLE_ADDR_TYPE_ID_BIT)) !=
+ (addr_type & (~BLE_ADDR_TYPE_ID_BIT))) {
+ BTM_TRACE_WARNING("%s find pseudo->random match with diff addr type: %d vs %d",
+ __func__, p_dev_rec->ble.static_addr_type, addr_type);
+ }
+ }
+ return p_dev_rec;
+#endif
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function btm_identity_addr_to_random_pseudo
+**
+** Description This function map a static BD address to a pseudo random address
+** in security database.
+**
+*******************************************************************************/
+BOOLEAN btm_identity_addr_to_random_pseudo(BD_ADDR bd_addr, UINT8 *p_addr_type, BOOLEAN refresh)
+{
+#if BLE_PRIVACY_SPT == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_identity_addr(bd_addr, *p_addr_type);
+
+ BTM_TRACE_EVENT ("%s", __func__);
+ /* evt reported on static address, map static address to random pseudo */
+ if (p_dev_rec != NULL) {
+ /* if RPA offloading is supported, or 4.2 controller, do RPA refresh */
+ if (refresh && controller_get_interface()->get_ble_resolving_list_max_size() != 0) {
+ btm_ble_read_resolving_list_entry(p_dev_rec);
+ }
+
+ /* assign the original address to be the current report address */
+ if (!btm_ble_init_pseudo_addr (p_dev_rec, bd_addr)) {
+ memcpy(bd_addr, p_dev_rec->ble.pseudo_addr, BD_ADDR_LEN);
+ }
+
+ *p_addr_type = p_dev_rec->ble.ble_addr_type;
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btm_random_pseudo_to_identity_addr
+**
+** Description This function map a random pseudo address to a public address
+** random_pseudo is input and output parameter
+**
+*******************************************************************************/
+BOOLEAN btm_random_pseudo_to_identity_addr(BD_ADDR random_pseudo, UINT8 *p_static_addr_type)
+{
+#if BLE_PRIVACY_SPT == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (random_pseudo);
+
+ if (p_dev_rec != NULL) {
+ if (p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) {
+ * p_static_addr_type = p_dev_rec->ble.static_addr_type;
+ memcpy(random_pseudo, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
+ if (controller_get_interface()->supports_ble_privacy() && p_dev_rec->ble.ble_addr_type != BLE_ADDR_PUBLIC) {
+ *p_static_addr_type |= BLE_ADDR_TYPE_ID_BIT;
+ }
+ return TRUE;
+ }
+ }
+#endif
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_refresh_peer_resolvable_private_addr
+**
+** Description This function refresh the currently used resolvable remote private address into security
+** database and set active connection address.
+**
+*******************************************************************************/
+void btm_ble_refresh_peer_resolvable_private_addr(BD_ADDR pseudo_bda, BD_ADDR rpa,
+ UINT8 rra_type)
+{
+#if BLE_PRIVACY_SPT == TRUE
+ UINT8 rra_dummy = FALSE;
+ BD_ADDR dummy_bda = {0};
+
+ if (memcmp(dummy_bda, rpa, BD_ADDR_LEN) == 0) {
+ rra_dummy = TRUE;
+ }
+
+ /* update security record here, in adv event or connection complete process */
+ tBTM_SEC_DEV_REC *p_sec_rec = btm_find_dev(pseudo_bda);
+ if (p_sec_rec != NULL) {
+ memcpy(p_sec_rec->ble.cur_rand_addr, rpa, BD_ADDR_LEN);
+
+ /* unknown, if dummy address, set to static */
+ if (rra_type == BTM_BLE_ADDR_PSEUDO) {
+ p_sec_rec->ble.active_addr_type = rra_dummy ? BTM_BLE_ADDR_STATIC : BTM_BLE_ADDR_RRA;
+ } else {
+ p_sec_rec->ble.active_addr_type = rra_type;
+ }
+ } else {
+ BTM_TRACE_ERROR("No matching known device in record");
+ return;
+ }
+
+ BTM_TRACE_DEBUG("%s: active_addr_type: %d ",
+ __func__, p_sec_rec->ble.active_addr_type);
+
+ /* connection refresh remote address */
+ tACL_CONN *p_acl = btm_bda_to_acl(p_sec_rec->bd_addr, BT_TRANSPORT_LE);
+ if (p_acl == NULL) {
+ p_acl = btm_bda_to_acl(p_sec_rec->ble.pseudo_addr, BT_TRANSPORT_LE);
+ }
+
+ if (p_acl != NULL) {
+ if (rra_type == BTM_BLE_ADDR_PSEUDO) {
+ /* use static address, resolvable_private_addr is empty */
+ if (rra_dummy) {
+ p_acl->active_remote_addr_type = p_sec_rec->ble.static_addr_type;
+ memcpy(p_acl->active_remote_addr, p_sec_rec->ble.static_addr, BD_ADDR_LEN);
+ } else {
+ p_acl->active_remote_addr_type = BLE_ADDR_RANDOM;
+ memcpy(p_acl->active_remote_addr, rpa, BD_ADDR_LEN);
+ }
+ } else {
+ p_acl->active_remote_addr_type = rra_type;
+ memcpy(p_acl->active_remote_addr, rpa, BD_ADDR_LEN);
+ }
+
+ BTM_TRACE_DEBUG("p_acl->active_remote_addr_type: %d ", p_acl->active_remote_addr_type);
+ BTM_TRACE_DEBUG("%s conn_addr: %02x:%02x:%02x:%02x:%02x:%02x",
+ __func__, p_acl->active_remote_addr[0], p_acl->active_remote_addr[1],
+ p_acl->active_remote_addr[2], p_acl->active_remote_addr[3],
+ p_acl->active_remote_addr[4], p_acl->active_remote_addr[5]);
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_refresh_local_resolvable_private_addr
+**
+** Description This function refresh the currently used resolvable private address for the
+** active link to the remote device
+**
+*******************************************************************************/
+void btm_ble_refresh_local_resolvable_private_addr(BD_ADDR pseudo_addr,
+ BD_ADDR local_rpa)
+{
+#if BLE_PRIVACY_SPT == TRUE
+ tACL_CONN *p = btm_bda_to_acl(pseudo_addr, BT_TRANSPORT_LE);
+ BD_ADDR dummy_bda = {0};
+
+ if (p != NULL) {
+ if (btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type >= BLE_ADDR_RANDOM) {
+ p->conn_addr_type = BLE_ADDR_RANDOM;
+ if (memcmp(local_rpa, dummy_bda, BD_ADDR_LEN)) {
+ memcpy(p->conn_addr, local_rpa, BD_ADDR_LEN);
+ } else {
+ memcpy(p->conn_addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr, BD_ADDR_LEN);
+ }
+ } else {
+ p->conn_addr_type = BLE_ADDR_PUBLIC;
+ memcpy(p->conn_addr, &controller_get_interface()->get_address()->address, BD_ADDR_LEN);
+ }
+ }
+#endif
+}
+#endif
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c b/lib/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c
new file mode 100644
index 00000000..c0ae0aaa
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c
@@ -0,0 +1,1306 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 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.
+ *
+ ******************************************************************************/
+
+//#define LOG_TAG "bt_btm_ble"
+
+#include <string.h>
+#include "common/bt_target.h"
+
+#if (BLE_INCLUDED == TRUE)
+#include "stack/bt_types.h"
+#include "stack/hcimsgs.h"
+#include "stack/btu.h"
+#include "btm_int.h"
+#include "osi/allocator.h"
+#include "stack/hcidefs.h"
+#include "stack/btm_ble_api.h"
+#include "device/controller.h"
+
+#define BTM_BLE_ADV_FILT_META_HDR_LENGTH 3
+#define BTM_BLE_ADV_FILT_FEAT_SELN_LEN 13
+#define BTM_BLE_ADV_FILT_TRACK_NUM 2
+
+#define BTM_BLE_PF_SELECT_NONE 0
+
+/* BLE meta vsc header: 1 bytes of sub_code, 1 byte of PCF action */
+#define BTM_BLE_META_HDR_LENGTH 3
+#define BTM_BLE_PF_FEAT_SEL_LEN 18
+#define BTM_BLE_PCF_ENABLE_LEN 2
+
+#define BTM_BLE_META_ADDR_LEN 7
+#define BTM_BLE_META_UUID_LEN 40
+
+#define BTM_BLE_PF_BIT_TO_MASK(x) (UINT16)(1 << (x))
+
+
+#if BTM_DYNAMIC_MEMORY == FALSE
+tBTM_BLE_ADV_FILTER_CB btm_ble_adv_filt_cb;
+tBTM_BLE_VSC_CB cmn_ble_adv_vsc_cb;
+#else
+tBTM_BLE_ADV_FILTER_CB *btm_ble_adv_filt_cb_ptr;
+tBTM_BLE_VSC_CB *cmn_ble_adv_vsc_cb_ptr;
+#define btm_ble_adv_filt_cb (*btm_ble_adv_filt_cb_ptr)
+#define cmn_ble_adv_vsc_cb (*cmn_ble_adv_vsc_cb_ptr)
+#endif
+
+static const BD_ADDR na_bda = {0};
+
+static UINT8 btm_ble_cs_update_pf_counter(tBTM_BLE_SCAN_COND_OP action,
+ UINT8 cond_type, tBLE_BD_ADDR *p_bd_addr, UINT8 num_available);
+
+#define BTM_BLE_SET_SCAN_PF_OPCODE(x, y) (((x)<<4)|y)
+#define BTM_BLE_GET_SCAN_PF_SUBCODE(x) ((x) >> 4)
+#define BTM_BLE_GET_SCAN_PF_ACTION(x) ((x) & 0x0f)
+#define BTM_BLE_INVALID_COUNTER 0xff
+
+
+/* length of each multi adv sub command */
+#define BTM_BLE_ADV_FILTER_ENB_LEN 3
+
+/* length of each batch scan command */
+#define BTM_BLE_ADV_FILTER_CLEAR_LEN 3
+#define BTM_BLE_ADV_FILTER_LEN 2
+
+#define BTM_BLE_ADV_FILT_CB_EVT_MASK 0xF0
+#define BTM_BLE_ADV_FILT_SUBCODE_MASK 0x0F
+
+/*******************************************************************************
+**
+** Function btm_ble_obtain_vsc_details
+**
+** Description This function obtains the VSC details
+**
+** Parameters
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_obtain_vsc_details(void)
+{
+ tBTM_STATUS st = BTM_SUCCESS;
+
+#if BLE_VND_INCLUDED == TRUE
+ BTM_BleGetVendorCapabilities(&cmn_ble_adv_vsc_cb);
+ if (0 == cmn_ble_adv_vsc_cb.max_filter) {
+ st = BTM_MODE_UNSUPPORTED;
+ return st;
+ }
+#else
+ cmn_ble_adv_vsc_cb.max_filter = BTM_BLE_MAX_FILTER_COUNTER;
+#endif
+ return st;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_advfilt_enq_op_q
+**
+** Description enqueue an adv filter operation in q to check command complete
+** status
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_advfilt_enq_op_q(UINT8 action, UINT8 ocf, tBTM_BLE_FILT_CB_EVT cb_evt,
+ tBTM_BLE_REF_VALUE ref, tBTM_BLE_PF_CFG_CBACK *p_cmpl_cback,
+ tBTM_BLE_PF_PARAM_CBACK *p_filt_param_cback)
+{
+ btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.next_idx] = (action | (ocf << 4));
+ btm_ble_adv_filt_cb.op_q.ref_value[btm_ble_adv_filt_cb.op_q.next_idx] = ref;
+ btm_ble_adv_filt_cb.op_q.cb_evt[btm_ble_adv_filt_cb.op_q.next_idx] = cb_evt;
+ btm_ble_adv_filt_cb.op_q.p_scan_cfg_cback[btm_ble_adv_filt_cb.op_q.next_idx] = p_cmpl_cback;
+ btm_ble_adv_filt_cb.op_q.p_filt_param_cback[btm_ble_adv_filt_cb.op_q.next_idx]
+ = p_filt_param_cback;
+ BTM_TRACE_DEBUG("btm_ble_advfilt_enq_op_q: act_ocf:%d, action:%d, ocf:%d,cb_evt;%d, cback:%p",
+ btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.next_idx], action,
+ ocf, cb_evt, p_cmpl_cback);
+ btm_ble_adv_filt_cb.op_q.next_idx = (btm_ble_adv_filt_cb.op_q.next_idx + 1)
+ % BTM_BLE_PF_TYPE_MAX;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_advfilt_deq_op_q
+**
+** Description dequeue an adv filter operation from q when command complete
+** is received
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_advfilt_deq_op_q(UINT8 *p_action, UINT8 *p_ocf, tBTM_BLE_FILT_CB_EVT *p_cb_evt,
+ tBTM_BLE_REF_VALUE *p_ref, tBTM_BLE_PF_CFG_CBACK **p_cmpl_cback,
+ tBTM_BLE_PF_PARAM_CBACK **p_filt_param_cback)
+{
+ *p_ocf = (btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.pending_idx] >> 4);
+ *p_action = (btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.pending_idx]
+ & BTM_BLE_ADV_FILT_SUBCODE_MASK);
+ *p_ref = btm_ble_adv_filt_cb.op_q.ref_value[btm_ble_adv_filt_cb.op_q.pending_idx];
+ *p_cb_evt = btm_ble_adv_filt_cb.op_q.cb_evt[btm_ble_adv_filt_cb.op_q.pending_idx];
+ *p_cmpl_cback = btm_ble_adv_filt_cb.op_q.p_scan_cfg_cback[btm_ble_adv_filt_cb.op_q.pending_idx];
+ *p_filt_param_cback =
+ btm_ble_adv_filt_cb.op_q.p_filt_param_cback[btm_ble_adv_filt_cb.op_q.pending_idx];
+
+ btm_ble_adv_filt_cb.op_q.pending_idx = (btm_ble_adv_filt_cb.op_q.pending_idx + 1)
+ % BTM_BLE_PF_TYPE_MAX;
+ BTM_TRACE_DEBUG("btm_ble_advfilt_deq_op_q: ocf:%d, action:%d, ref_value:%d, cb_evt:%x",
+ *p_ocf, *p_action, *p_ref, *p_cb_evt);
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_condtype_to_ocf
+**
+** Description Convert cond_type to OCF
+**
+** Returns Returns ocf value
+**
+*******************************************************************************/
+UINT8 btm_ble_condtype_to_ocf(UINT8 cond_type)
+{
+ UINT8 ocf = 0;
+
+ switch (cond_type) {
+ case BTM_BLE_PF_ADDR_FILTER:
+ ocf = BTM_BLE_META_PF_ADDR;
+ break;
+ case BTM_BLE_PF_SRVC_UUID:
+ ocf = BTM_BLE_META_PF_UUID;
+ break;
+ case BTM_BLE_PF_SRVC_SOL_UUID:
+ ocf = BTM_BLE_META_PF_SOL_UUID;
+ break;
+ case BTM_BLE_PF_LOCAL_NAME:
+ ocf = BTM_BLE_META_PF_LOCAL_NAME;
+ break;
+ case BTM_BLE_PF_MANU_DATA:
+ ocf = BTM_BLE_META_PF_MANU_DATA;
+ break;
+ case BTM_BLE_PF_SRVC_DATA_PATTERN:
+ ocf = BTM_BLE_META_PF_SRVC_DATA;
+ break;
+ case BTM_BLE_PF_TYPE_ALL:
+ ocf = BTM_BLE_META_PF_ALL;
+ break;
+ default:
+ ocf = BTM_BLE_PF_TYPE_MAX;
+ break;
+ }
+ return ocf;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_ocf_to_condtype
+**
+** Description Convert OCF to cond type
+**
+** Returns Returns condtype value
+**
+*******************************************************************************/
+UINT8 btm_ble_ocf_to_condtype(UINT8 ocf)
+{
+ UINT8 cond_type = 0;
+
+ switch (ocf) {
+ case BTM_BLE_META_PF_FEAT_SEL:
+ cond_type = BTM_BLE_META_PF_FEAT_SEL;
+ break;
+ case BTM_BLE_META_PF_ADDR:
+ cond_type = BTM_BLE_PF_ADDR_FILTER;
+ break;
+ case BTM_BLE_META_PF_UUID:
+ cond_type = BTM_BLE_PF_SRVC_UUID;
+ break;
+ case BTM_BLE_META_PF_SOL_UUID:
+ cond_type = BTM_BLE_PF_SRVC_SOL_UUID;
+ break;
+ case BTM_BLE_META_PF_LOCAL_NAME:
+ cond_type = BTM_BLE_PF_LOCAL_NAME;
+ break;
+ case BTM_BLE_META_PF_MANU_DATA:
+ cond_type = BTM_BLE_PF_MANU_DATA;
+ break;
+ case BTM_BLE_META_PF_SRVC_DATA:
+ cond_type = BTM_BLE_PF_SRVC_DATA_PATTERN;
+ break;
+ case BTM_BLE_META_PF_ALL:
+ cond_type = BTM_BLE_PF_TYPE_ALL;
+ break;
+ default:
+ cond_type = BTM_BLE_PF_TYPE_MAX;
+ break;
+ }
+ return cond_type;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_scan_pf_cmpl_cback
+**
+** Description the BTM BLE customer feature VSC complete callback for ADV PF filtering
+**
+** Returns pointer to the counter if found; NULL otherwise.
+**
+*******************************************************************************/
+void btm_ble_scan_pf_cmpl_cback(tBTM_VSC_CMPL *p_params)
+{
+ UINT8 status = 0;
+ UINT8 *p = p_params->p_param_buf, op_subcode = 0, action = 0xff;
+ UINT16 evt_len = p_params->param_len;
+ UINT8 ocf = BTM_BLE_META_PF_ALL, cond_type = 0;
+ UINT8 num_avail = 0, cb_evt = 0;
+ tBTM_BLE_REF_VALUE ref_value = 0;
+ tBTM_BLE_PF_CFG_CBACK *p_scan_cfg_cback = NULL;
+ tBTM_BLE_PF_PARAM_CBACK *p_filt_param_cback = NULL;
+
+ if (evt_len < 3 || evt_len > 4) {
+ BTM_TRACE_ERROR("%s cannot interpret APCF callback status = %d, length = %d",
+ __func__, status, evt_len);
+ btm_ble_advfilt_deq_op_q(&action, &ocf, &cb_evt, &ref_value, &p_scan_cfg_cback,
+ &p_filt_param_cback);
+ return;
+ }
+
+ btm_ble_advfilt_deq_op_q(&action, &ocf, &cb_evt, &ref_value, &p_scan_cfg_cback,
+ &p_filt_param_cback);
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT8(op_subcode, p);
+ STREAM_TO_UINT8(action, p);
+
+ /* Ignore the event, if it is not the same one expected */
+ if (3 == evt_len) {
+ if (ocf != op_subcode) {
+ BTM_TRACE_ERROR("btm_ble_scan_pf_cmpl_cback:3-Incorrect opcode :%d, %d, %d, %d, %d, %d",
+ ocf, op_subcode, action, evt_len, ref_value, status);
+ return;
+ } else {
+ if (NULL != btm_ble_adv_filt_cb.p_filt_stat_cback) {
+ btm_ble_adv_filt_cb.p_filt_stat_cback(action, status, ref_value);
+ }
+ BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback enabled/disabled, %d, %d, %d, %d",
+ ocf, action, status, ref_value);
+ return;
+ }
+ }
+
+ if (4 == evt_len && ocf != op_subcode) {
+ BTM_TRACE_ERROR("btm_ble_scan_pf_cmpl_cback:4-Incorrect opcode: %d, %d, %d, %d, %d",
+ ocf, op_subcode, action, status, ref_value);
+ return;
+ }
+
+ STREAM_TO_UINT8(num_avail, p);
+ switch (op_subcode) {
+ case BTM_BLE_META_PF_ADDR:
+ case BTM_BLE_META_PF_UUID:
+ case BTM_BLE_META_PF_SOL_UUID:
+ case BTM_BLE_META_PF_LOCAL_NAME:
+ case BTM_BLE_META_PF_MANU_DATA:
+ case BTM_BLE_META_PF_SRVC_DATA:
+ cond_type = btm_ble_ocf_to_condtype(ocf);
+ BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback Recd: %d, %d, %d, %d, %d, %d", op_subcode,
+ ocf, action, status, ref_value, num_avail);
+ if (HCI_SUCCESS == status) {
+ if (memcmp(&btm_ble_adv_filt_cb.cur_filter_target.bda, &na_bda, BD_ADDR_LEN) == 0) {
+ btm_ble_cs_update_pf_counter(action, cond_type, NULL, num_avail);
+ } else {
+ btm_ble_cs_update_pf_counter(action, cond_type,
+ &btm_ble_adv_filt_cb.cur_filter_target, num_avail);
+ }
+ }
+
+ /* send ADV PF operation complete */
+ btm_ble_adv_filt_cb.op_type = 0;
+ break;
+
+ case BTM_BLE_META_PF_FEAT_SEL:
+ BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback-Feat sel event: %d, %d, %d, %d",
+ action, status, ref_value, num_avail);
+ break;
+
+ default:
+ BTM_TRACE_ERROR("btm_ble_scan_pf_cmpl_cback: unknown operation: %d", op_subcode);
+ break;
+ }
+
+ BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback: calling the cback: %d", cb_evt);
+ switch (cb_evt) {
+ case BTM_BLE_FILT_CFG:
+ if (NULL != p_scan_cfg_cback) {
+ p_scan_cfg_cback(action, cond_type, num_avail, status, ref_value);
+ }
+ break;
+ case BTM_BLE_FILT_ADV_PARAM:
+ if (NULL != p_filt_param_cback) {
+ p_filt_param_cback(action, num_avail, ref_value, status);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_find_addr_filter_counter
+**
+** Description find the per bd address ADV payload filter counter by BD_ADDR.
+**
+** Returns pointer to the counter if found; NULL otherwise.
+**
+*******************************************************************************/
+tBTM_BLE_PF_COUNT *btm_ble_find_addr_filter_counter(tBLE_BD_ADDR *p_le_bda)
+{
+ UINT8 i;
+ tBTM_BLE_PF_COUNT *p_addr_filter = &btm_ble_adv_filt_cb.p_addr_filter_count[1];
+
+ if (p_le_bda == NULL) {
+ return &btm_ble_adv_filt_cb.p_addr_filter_count[0];
+ }
+
+ for (i = 0; i < cmn_ble_adv_vsc_cb.max_filter; i ++, p_addr_filter ++) {
+ if (p_addr_filter->in_use &&
+ memcmp(p_le_bda->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0) {
+ return p_addr_filter;
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_alloc_addr_filter_counter
+**
+** Description allocate the per device adv payload filter counter.
+**
+** Returns pointer to the counter if allocation succeed; NULL otherwise.
+**
+*******************************************************************************/
+tBTM_BLE_PF_COUNT *btm_ble_alloc_addr_filter_counter(BD_ADDR bd_addr)
+{
+ UINT8 i;
+ tBTM_BLE_PF_COUNT *p_addr_filter = &btm_ble_adv_filt_cb.p_addr_filter_count[1];
+
+ for (i = 0; i < cmn_ble_adv_vsc_cb.max_filter; i ++, p_addr_filter ++) {
+ if (memcmp(na_bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0) {
+ memcpy(p_addr_filter->bd_addr, bd_addr, BD_ADDR_LEN);
+ p_addr_filter->in_use = TRUE;
+ return p_addr_filter;
+ }
+ }
+ return NULL;
+}
+/*******************************************************************************
+**
+** Function btm_ble_dealloc_addr_filter_counter
+**
+** Description de-allocate the per device adv payload filter counter.
+**
+** Returns TRUE if deallocation succeed; FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_dealloc_addr_filter_counter(tBLE_BD_ADDR *p_bd_addr, UINT8 filter_type)
+{
+ UINT8 i;
+ tBTM_BLE_PF_COUNT *p_addr_filter = &btm_ble_adv_filt_cb.p_addr_filter_count[1];
+ BOOLEAN found = FALSE;
+
+ if (BTM_BLE_PF_TYPE_ALL == filter_type && NULL == p_bd_addr) {
+ memset(&btm_ble_adv_filt_cb.p_addr_filter_count[0], 0, sizeof(tBTM_BLE_PF_COUNT));
+ }
+
+ for (i = 0; i < cmn_ble_adv_vsc_cb.max_filter; i ++, p_addr_filter ++) {
+ if ((p_addr_filter->in_use) && (NULL == p_bd_addr ||
+ (NULL != p_bd_addr &&
+ memcmp(p_bd_addr->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0))) {
+ found = TRUE;
+ memset(p_addr_filter, 0, sizeof(tBTM_BLE_PF_COUNT));
+
+ if (NULL != p_bd_addr) {
+ break;
+ }
+ }
+ }
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_update_pf_local_name
+**
+** Description this function update(add,delete or clear) the adv lcoal name filtering condition.
+**
+**
+** Returns BTM_SUCCESS if sucessful,
+** BTM_ILLEGAL_VALUE if paramter is not valid.
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_update_pf_local_name(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBTM_BLE_PF_COND_PARAM *p_cond)
+{
+ tBTM_BLE_PF_LOCAL_NAME_COND *p_local_name = (p_cond == NULL) ? NULL : &p_cond->local_name;
+ UINT8 param[BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_ADV_FILT_META_HDR_LENGTH],
+ *p = param,
+ len = BTM_BLE_ADV_FILT_META_HDR_LENGTH;
+ tBTM_STATUS st = BTM_ILLEGAL_VALUE;
+
+ memset(param, 0, BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_ADV_FILT_META_HDR_LENGTH);
+
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_LOCAL_NAME);
+ UINT8_TO_STREAM(p, action);
+
+ /* Filter index */
+ UINT8_TO_STREAM(p, filt_index);
+
+ if (BTM_BLE_SCAN_COND_ADD == action ||
+ BTM_BLE_SCAN_COND_DELETE == action) {
+ if (NULL == p_local_name) {
+ return st;
+ }
+
+ if (p_local_name->data_len > BTM_BLE_PF_STR_LEN_MAX) {
+ p_local_name->data_len = BTM_BLE_PF_STR_LEN_MAX;
+ }
+
+ ARRAY_TO_STREAM(p, p_local_name->p_data, p_local_name->data_len);
+ len += p_local_name->data_len;
+ }
+
+ /* send local name filter */
+ if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF,
+ len,
+ param,
+ btm_ble_scan_pf_cmpl_cback))
+ != BTM_NO_RESOURCES) {
+ memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
+ } else {
+ BTM_TRACE_ERROR("Local Name PF filter update failed");
+ }
+
+ return st;
+}
+
+
+/*******************************************************************************
+**
+** Function btm_ble_update_srvc_data_change
+**
+** Description this function update(add/remove) service data change filter.
+**
+**
+** Returns BTM_SUCCESS if sucessful,
+** BTM_ILLEGAL_VALUE if paramter is not valid.
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_update_srvc_data_change(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBTM_BLE_PF_COND_PARAM *p_cond)
+{
+ tBTM_STATUS st = BTM_ILLEGAL_VALUE;
+ tBLE_BD_ADDR *p_bd_addr = p_cond ? &p_cond->target_addr : NULL;
+ UINT8 num_avail = (action == BTM_BLE_SCAN_COND_ADD) ? 0 : 1;
+
+ if (btm_ble_cs_update_pf_counter (action, BTM_BLE_PF_SRVC_DATA, p_bd_addr, num_avail)
+ != BTM_BLE_INVALID_COUNTER) {
+ st = BTM_SUCCESS;
+ }
+
+ return st;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_update_pf_manu_data
+**
+** Description this function update(add,delete or clear) the adv manufacturer
+** data filtering condition.
+**
+**
+** Returns BTM_SUCCESS if sucessful,
+** BTM_ILLEGAL_VALUE if paramter is not valid.
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_update_pf_manu_data(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBTM_BLE_PF_COND_PARAM *p_data,
+ tBTM_BLE_PF_COND_TYPE cond_type,
+ tBTM_BLE_FILT_CB_EVT cb_evt,
+ tBTM_BLE_REF_VALUE ref_value)
+{
+ tBTM_BLE_PF_MANU_COND *p_manu_data = (p_data == NULL) ? NULL : &p_data->manu_data;
+ tBTM_BLE_PF_SRVC_PATTERN_COND *p_srvc_data = (p_data == NULL) ? NULL : &p_data->srvc_data;
+
+ UINT8 param[BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_ADV_FILT_META_HDR_LENGTH],
+ *p = param,
+ len = BTM_BLE_ADV_FILT_META_HDR_LENGTH;
+ tBTM_STATUS st = BTM_ILLEGAL_VALUE;
+
+ if (NULL == p_data) {
+ return st;
+ }
+
+ memset(param, 0, BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_PF_STR_LEN_MAX
+ + BTM_BLE_ADV_FILT_META_HDR_LENGTH);
+
+ if (BTM_BLE_PF_SRVC_DATA_PATTERN == cond_type) {
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_SRVC_DATA);
+ } else {
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_MANU_DATA);
+ }
+
+ UINT8_TO_STREAM(p, action);
+
+ /* Filter index */
+ UINT8_TO_STREAM(p, filt_index);
+
+ if (BTM_BLE_SCAN_COND_ADD == action || BTM_BLE_SCAN_COND_DELETE == action) {
+ if (BTM_BLE_PF_SRVC_DATA_PATTERN == cond_type) {
+ if (NULL == p_srvc_data) {
+ return st;
+ }
+ if (p_srvc_data->data_len > (BTM_BLE_PF_STR_LEN_MAX - 2)) {
+ p_srvc_data->data_len = (BTM_BLE_PF_STR_LEN_MAX - 2);
+ }
+
+ if (p_srvc_data->data_len > 0) {
+ ARRAY_TO_STREAM(p, p_srvc_data->p_pattern, p_srvc_data->data_len);
+ len += (p_srvc_data->data_len);
+ ARRAY_TO_STREAM(p, p_srvc_data->p_pattern_mask, p_srvc_data->data_len);
+ }
+
+ len += (p_srvc_data->data_len);
+ BTM_TRACE_DEBUG("Service data length: %d", len);
+ } else {
+ if (NULL == p_manu_data) {
+ BTM_TRACE_ERROR("btm_ble_update_pf_manu_data - No manuf data");
+ return st;
+ }
+ BTM_TRACE_EVENT("btm_ble_update_pf_manu_data length: %d",
+ p_manu_data->data_len);
+ if (p_manu_data->data_len > (BTM_BLE_PF_STR_LEN_MAX - 2)) {
+ p_manu_data->data_len = (BTM_BLE_PF_STR_LEN_MAX - 2);
+ }
+
+ UINT16_TO_STREAM(p, p_manu_data->company_id);
+ if (p_manu_data->data_len > 0 && p_manu_data->p_pattern_mask != NULL) {
+ ARRAY_TO_STREAM(p, p_manu_data->p_pattern, p_manu_data->data_len);
+ len += (p_manu_data->data_len + 2);
+ } else {
+ len += 2;
+ }
+
+ if (p_manu_data->company_id_mask != 0) {
+ UINT16_TO_STREAM (p, p_manu_data->company_id_mask);
+ } else {
+ memset(p, 0xff, 2);
+ p += 2;
+ }
+ len += 2;
+
+ if (p_manu_data->data_len > 0 && p_manu_data->p_pattern_mask != NULL) {
+ ARRAY_TO_STREAM(p, p_manu_data->p_pattern_mask, p_manu_data->data_len);
+ len += (p_manu_data->data_len);
+ }
+
+ BTM_TRACE_DEBUG("Manuf data length: %d", len);
+ }
+ }
+
+ /* send manufacturer*/
+ if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF,
+ len,
+ param,
+ btm_ble_scan_pf_cmpl_cback)) != BTM_NO_RESOURCES) {
+ memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
+ } else {
+ BTM_TRACE_ERROR("manufacturer data PF filter update failed");
+ }
+
+ return st;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_cs_update_pf_counter
+**
+** Description this function is to update the adv data payload filter counter
+**
+** Returns current number of the counter; BTM_BLE_INVALID_COUNTER if
+** counter update failed.
+**
+*******************************************************************************/
+UINT8 btm_ble_cs_update_pf_counter(tBTM_BLE_SCAN_COND_OP action,
+ UINT8 cond_type, tBLE_BD_ADDR *p_bd_addr,
+ UINT8 num_available)
+{
+ tBTM_BLE_PF_COUNT *p_addr_filter = NULL;
+ UINT8 *p_counter = NULL;
+
+ btm_ble_obtain_vsc_details();
+
+ if (cond_type > BTM_BLE_PF_TYPE_ALL) {
+ BTM_TRACE_ERROR("unknown PF filter condition type %d", cond_type);
+ return BTM_BLE_INVALID_COUNTER;
+ }
+
+ /* for these three types of filter, always generic */
+ if (BTM_BLE_PF_ADDR_FILTER == cond_type ||
+ BTM_BLE_PF_MANU_DATA == cond_type ||
+ BTM_BLE_PF_LOCAL_NAME == cond_type ||
+ BTM_BLE_PF_SRVC_DATA_PATTERN == cond_type) {
+ p_bd_addr = NULL;
+ }
+
+ if ((p_addr_filter = btm_ble_find_addr_filter_counter(p_bd_addr)) == NULL &&
+ BTM_BLE_SCAN_COND_ADD == action) {
+ p_addr_filter = btm_ble_alloc_addr_filter_counter(p_bd_addr->bda);
+ }
+
+ if (NULL != p_addr_filter) {
+ /* all filter just cleared */
+ if ((BTM_BLE_PF_TYPE_ALL == cond_type && BTM_BLE_SCAN_COND_CLEAR == action) ||
+ /* or bd address filter been deleted */
+ (BTM_BLE_PF_ADDR_FILTER == cond_type &&
+ (BTM_BLE_SCAN_COND_DELETE == action || BTM_BLE_SCAN_COND_CLEAR == action))) {
+ btm_ble_dealloc_addr_filter_counter(p_bd_addr, cond_type);
+ }
+ /* if not feature selection, update new addition/reduction of the filter counter */
+ else if (cond_type != BTM_BLE_PF_TYPE_ALL) {
+ p_counter = p_addr_filter->pf_counter;
+ if (num_available > 0) {
+ p_counter[cond_type] += 1;
+ }
+
+ BTM_TRACE_DEBUG("counter = %d, maxfilt = %d, num_avbl=%d",
+ p_counter[cond_type], cmn_ble_adv_vsc_cb.max_filter, num_available);
+ return p_counter[cond_type];
+ }
+ } else {
+ BTM_TRACE_ERROR("no matching filter counter found");
+ }
+ /* no matching filter located and updated */
+ return BTM_BLE_INVALID_COUNTER;
+}
+
+
+/*******************************************************************************
+**
+** Function btm_ble_update_addr_filter
+**
+** Description this function update(add,delete or clear) the address filter of adv.
+**
+**
+** Returns BTM_SUCCESS if sucessful,
+** BTM_ILLEGAL_VALUE if paramter is not valid.
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_update_addr_filter(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBTM_BLE_PF_COND_PARAM *p_cond)
+{
+ UINT8 param[BTM_BLE_META_ADDR_LEN + BTM_BLE_ADV_FILT_META_HDR_LENGTH],
+ * p = param;
+ tBTM_STATUS st = BTM_ILLEGAL_VALUE;
+ tBLE_BD_ADDR *p_addr = (p_cond == NULL) ? NULL : &p_cond->target_addr;
+
+ memset(param, 0, BTM_BLE_META_ADDR_LEN + BTM_BLE_ADV_FILT_META_HDR_LENGTH);
+
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_ADDR);
+ UINT8_TO_STREAM(p, action);
+
+ /* Filter index */
+ UINT8_TO_STREAM(p, filt_index);
+
+ if (BTM_BLE_SCAN_COND_ADD == action ||
+ BTM_BLE_SCAN_COND_DELETE == action) {
+ if (NULL == p_addr) {
+ return st;
+ }
+
+ BDADDR_TO_STREAM(p, p_addr->bda);
+ UINT8_TO_STREAM(p, p_addr->type);
+ }
+ /* send address filter */
+ if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF,
+ (UINT8)(BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_META_ADDR_LEN),
+ param,
+ btm_ble_scan_pf_cmpl_cback)) != BTM_NO_RESOURCES) {
+ memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
+ } else {
+ BTM_TRACE_ERROR("Broadcaster Address Filter Update failed");
+ }
+ return st;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_update_uuid_filter
+**
+** Description this function update(add,delete or clear) service UUID filter.
+**
+**
+** Returns BTM_SUCCESS if sucessful,
+** BTM_ILLEGAL_VALUE if paramter is not valid.
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_update_uuid_filter(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBTM_BLE_PF_COND_TYPE filter_type,
+ tBTM_BLE_PF_COND_PARAM *p_cond,
+ tBTM_BLE_FILT_CB_EVT cb_evt,
+ tBTM_BLE_REF_VALUE ref_value)
+{
+ UINT8 param[BTM_BLE_META_UUID_LEN + BTM_BLE_ADV_FILT_META_HDR_LENGTH],
+ * p = param,
+ len = BTM_BLE_ADV_FILT_META_HDR_LENGTH;
+ tBTM_STATUS st = BTM_ILLEGAL_VALUE;
+ tBTM_BLE_PF_UUID_COND *p_uuid_cond;
+ UINT8 evt_type;
+
+ memset(param, 0, BTM_BLE_META_UUID_LEN + BTM_BLE_ADV_FILT_META_HDR_LENGTH);
+
+ if (BTM_BLE_PF_SRVC_UUID == filter_type) {
+ evt_type = BTM_BLE_META_PF_UUID;
+ p_uuid_cond = p_cond ? &p_cond->srvc_uuid : NULL;
+ } else {
+ evt_type = BTM_BLE_META_PF_SOL_UUID;
+ p_uuid_cond = p_cond ? &p_cond->solicitate_uuid : NULL;
+ }
+
+ if (NULL == p_uuid_cond && action != BTM_BLE_SCAN_COND_CLEAR) {
+ BTM_TRACE_ERROR("Illegal param for add/delete UUID filter");
+ return st;
+ }
+
+ /* need to add address filter first, if adding per bda UUID filter without address filter */
+ if (BTM_BLE_SCAN_COND_ADD == action && NULL != p_uuid_cond &&
+ p_uuid_cond->p_target_addr &&
+ btm_ble_find_addr_filter_counter(p_uuid_cond->p_target_addr) == NULL) {
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_ADDR);
+ UINT8_TO_STREAM(p, action);
+
+ /* Filter index */
+ UINT8_TO_STREAM(p, filt_index);
+
+ BDADDR_TO_STREAM(p, p_uuid_cond->p_target_addr->bda);
+ UINT8_TO_STREAM(p, p_uuid_cond->p_target_addr->type);
+
+ /* send address filter */
+ if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF,
+ (UINT8)(BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_META_ADDR_LEN),
+ param,
+ btm_ble_scan_pf_cmpl_cback)) == BTM_NO_RESOURCES) {
+ BTM_TRACE_ERROR("Update Address filter into controller failed.");
+ return st;
+ }
+
+ btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_ADDR, cb_evt, ref_value, NULL, NULL);
+ BTM_TRACE_DEBUG("Updated Address filter");
+ }
+
+ p = param;
+ UINT8_TO_STREAM(p, evt_type);
+ UINT8_TO_STREAM(p, action);
+
+ /* Filter index */
+ UINT8_TO_STREAM(p, filt_index);
+
+ if ((BTM_BLE_SCAN_COND_ADD == action ||
+ BTM_BLE_SCAN_COND_DELETE == action) &&
+ NULL != p_uuid_cond) {
+ if (p_uuid_cond->uuid.len == LEN_UUID_16) {
+ UINT16_TO_STREAM(p, p_uuid_cond->uuid.uu.uuid16);
+ len += LEN_UUID_16;
+ } else if (p_uuid_cond->uuid.len == LEN_UUID_32) { /*4 bytes */
+ UINT32_TO_STREAM(p, p_uuid_cond->uuid.uu.uuid32);
+ len += LEN_UUID_32;
+ } else if (p_uuid_cond->uuid.len == LEN_UUID_128) {
+ ARRAY_TO_STREAM (p, p_uuid_cond->uuid.uu.uuid128, LEN_UUID_128);
+ len += LEN_UUID_128;
+ } else {
+ BTM_TRACE_ERROR("illegal UUID length: %d", p_uuid_cond->uuid.len);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ if (NULL != p_uuid_cond->p_uuid_mask) {
+ if (p_uuid_cond->uuid.len == LEN_UUID_16) {
+ UINT16_TO_STREAM(p, p_uuid_cond->p_uuid_mask->uuid16_mask);
+ len += LEN_UUID_16;
+ } else if (p_uuid_cond->uuid.len == LEN_UUID_32) { /*4 bytes */
+ UINT32_TO_STREAM(p, p_uuid_cond->p_uuid_mask->uuid32_mask);
+ len += LEN_UUID_32;
+ } else if (p_uuid_cond->uuid.len == LEN_UUID_128) {
+ ARRAY_TO_STREAM (p, p_uuid_cond->p_uuid_mask->uuid128_mask, LEN_UUID_128);
+ len += LEN_UUID_128;
+ }
+ } else {
+ memset(p, 0xff, p_uuid_cond->uuid.len);
+ len += p_uuid_cond->uuid.len;
+ }
+ BTM_TRACE_DEBUG("btm_ble_update_uuid_filter : %d, %d, %d, %d", filter_type, evt_type,
+ p_uuid_cond->uuid.len, len);
+ }
+
+ /* send UUID filter update */
+ if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF,
+ len,
+ param,
+ btm_ble_scan_pf_cmpl_cback)) != BTM_NO_RESOURCES) {
+ if (p_uuid_cond && p_uuid_cond->p_target_addr) {
+ memcpy(&btm_ble_adv_filt_cb.cur_filter_target, p_uuid_cond->p_target_addr,
+ sizeof(tBLE_BD_ADDR));
+ }
+ else {
+ memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
+ }
+ } else {
+ BTM_TRACE_ERROR("UUID filter udpating failed");
+ }
+
+ return st;
+}
+
+
+/*******************************************************************************
+**
+** Function btm_ble_clear_scan_pf_filter
+**
+** Description clear all adv payload filter by de-select all the adv pf feature bits
+**
+**
+** Returns BTM_SUCCESS if sucessful,
+** BTM_ILLEGAL_VALUE if paramter is not valid.
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_clear_scan_pf_filter(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBTM_BLE_PF_COND_PARAM *p_cond,
+ tBTM_BLE_PF_CFG_CBACK *p_cmpl_cback,
+ tBTM_BLE_FILT_CB_EVT cb_evt,
+ tBTM_BLE_REF_VALUE ref_value)
+{
+ tBLE_BD_ADDR *p_target = (p_cond == NULL) ? NULL : &p_cond->target_addr;
+ tBTM_BLE_PF_COUNT *p_bda_filter;
+ tBTM_STATUS st = BTM_WRONG_MODE;
+ UINT8 param[20], *p;
+
+ if (BTM_BLE_SCAN_COND_CLEAR != action) {
+ BTM_TRACE_ERROR("unable to perform action:%d for generic adv filter type", action);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ p = param;
+ memset(param, 0, 20);
+
+ p_bda_filter = btm_ble_find_addr_filter_counter(p_target);
+
+ if (NULL == p_bda_filter ||
+ /* not a generic filter */
+ (p_target != NULL && p_bda_filter)) {
+ BTM_TRACE_ERROR("Error: Can not clear filter, No PF filter has been configured!");
+ return st;
+ }
+
+ /* clear the general filter entry */
+ if (NULL == p_target) {
+ /* clear manufacturer data filter */
+ st = btm_ble_update_pf_manu_data(BTM_BLE_SCAN_COND_CLEAR, filt_index, NULL,
+ BTM_BLE_PF_MANU_DATA, cb_evt, ref_value);
+ if (BTM_CMD_STARTED == st) {
+ btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_MANU_DATA, cb_evt,
+ ref_value, NULL, NULL);
+ }
+
+ /* clear local name filter */
+ st = btm_ble_update_pf_local_name(BTM_BLE_SCAN_COND_CLEAR, filt_index, NULL);
+ if (BTM_CMD_STARTED == st) {
+ btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_LOCAL_NAME, cb_evt,
+ ref_value, NULL, NULL);
+ }
+
+ /* update the counter for service data */
+ st = btm_ble_update_srvc_data_change(BTM_BLE_SCAN_COND_CLEAR, filt_index, NULL);
+
+ /* clear UUID filter */
+ st = btm_ble_update_uuid_filter(BTM_BLE_SCAN_COND_CLEAR, filt_index,
+ BTM_BLE_PF_SRVC_UUID, NULL, cb_evt, ref_value);
+ if (BTM_CMD_STARTED == st) {
+ btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_UUID, cb_evt, ref_value, NULL, NULL);
+ }
+
+ st = btm_ble_update_uuid_filter(BTM_BLE_SCAN_COND_CLEAR, filt_index,
+ BTM_BLE_PF_SRVC_SOL_UUID, NULL, cb_evt, ref_value);
+ if (BTM_CMD_STARTED == st) {
+ btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_SOL_UUID, cb_evt,
+ ref_value, NULL, NULL);
+ }
+
+ /* clear service data filter */
+ st = btm_ble_update_pf_manu_data(BTM_BLE_SCAN_COND_CLEAR, filt_index, NULL,
+ BTM_BLE_PF_SRVC_DATA_PATTERN, cb_evt, ref_value);
+ if (BTM_CMD_STARTED == st) {
+ btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_SRVC_DATA, cb_evt,
+ ref_value, NULL, NULL);
+ }
+ }
+
+ /* select feature based on control block settings */
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL);
+ UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_CLEAR);
+
+ /* Filter index */
+ UINT8_TO_STREAM(p, filt_index);
+
+ /* set PCF selection */
+ UINT32_TO_STREAM(p, BTM_BLE_PF_SELECT_NONE);
+ /* set logic condition as OR as default */
+ UINT8_TO_STREAM(p, BTM_BLE_PF_LOGIC_OR);
+
+ if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF,
+ (UINT8)(BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_PF_FEAT_SEL_LEN),
+ param,
+ btm_ble_scan_pf_cmpl_cback))
+ != BTM_NO_RESOURCES) {
+ if (p_target) {
+ memcpy(&btm_ble_adv_filt_cb.cur_filter_target, p_target, sizeof(tBLE_BD_ADDR));
+ } else {
+ memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
+ }
+ }
+ return st;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleAdvFilterParamSetup
+**
+** Description This function is called to setup the adv data payload filter
+** condition.
+**
+** Parameters action - Type of action to be performed
+** filt_index - Filter index
+** p_filt_params - Filter parameters
+** p_target - Target device
+** p_cmpl_back - Callback pointer
+** ref_value - reference value
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleAdvFilterParamSetup(int action, tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBTM_BLE_PF_FILT_PARAMS *p_filt_params,
+ tBLE_BD_ADDR *p_target, tBTM_BLE_PF_PARAM_CBACK *p_cmpl_cback,
+ tBTM_BLE_REF_VALUE ref_value)
+{
+ tBTM_STATUS st = BTM_WRONG_MODE;
+ tBTM_BLE_PF_COUNT *p_bda_filter = NULL;
+ UINT8 len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN +
+ BTM_BLE_ADV_FILT_TRACK_NUM;
+ UINT8 param[len], *p;
+
+ if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) {
+ return st;
+ }
+
+ p = param;
+ memset(param, 0, len);
+ BTM_TRACE_EVENT (" BTM_BleAdvFilterParamSetup");
+
+ if (BTM_BLE_SCAN_COND_ADD == action) {
+ p_bda_filter = btm_ble_find_addr_filter_counter(p_target);
+ if (NULL == p_bda_filter) {
+ BTM_TRACE_ERROR("BD Address not found!");
+ return st;
+ }
+
+ BTM_TRACE_DEBUG("BTM_BleAdvFilterParamSetup : Feat mask:%d", p_filt_params->feat_seln);
+ /* select feature based on control block settings */
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL);
+ UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_ADD);
+
+ /* Filter index */
+ UINT8_TO_STREAM(p, filt_index);
+
+ /* set PCF selection */
+ UINT16_TO_STREAM(p, p_filt_params->feat_seln);
+ /* set logic type */
+ UINT16_TO_STREAM(p, p_filt_params->logic_type);
+ /* set logic condition */
+ UINT8_TO_STREAM(p, p_filt_params->filt_logic_type);
+ /* set RSSI high threshold */
+ UINT8_TO_STREAM(p, p_filt_params->rssi_high_thres);
+ /* set delivery mode */
+ UINT8_TO_STREAM(p, p_filt_params->dely_mode);
+
+ if (0x01 == p_filt_params->dely_mode) {
+ /* set onfound timeout */
+ UINT16_TO_STREAM(p, p_filt_params->found_timeout);
+ /* set onfound timeout count*/
+ UINT8_TO_STREAM(p, p_filt_params->found_timeout_cnt);
+ /* set RSSI low threshold */
+ UINT8_TO_STREAM(p, p_filt_params->rssi_low_thres);
+ /* set onlost timeout */
+ UINT16_TO_STREAM(p, p_filt_params->lost_timeout);
+ /* set num_of_track_entries for firmware greater than L-release version */
+ if (cmn_ble_adv_vsc_cb.version_supported > BTM_VSC_CHIP_CAPABILITY_L_VERSION) {
+ UINT16_TO_STREAM(p, p_filt_params->num_of_tracking_entries);
+ }
+ }
+
+ if (cmn_ble_adv_vsc_cb.version_supported == BTM_VSC_CHIP_CAPABILITY_L_VERSION) {
+ len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN;
+ } else {
+ len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN +
+ BTM_BLE_ADV_FILT_TRACK_NUM;
+ }
+
+ if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF,
+ (UINT8)len,
+ param,
+ btm_ble_scan_pf_cmpl_cback))
+ == BTM_NO_RESOURCES) {
+ return st;
+ }
+ btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_FEAT_SEL, BTM_BLE_FILT_ADV_PARAM,
+ ref_value, NULL, p_cmpl_cback);
+ } else if (BTM_BLE_SCAN_COND_DELETE == action) {
+ /* select feature based on control block settings */
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL);
+ UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_DELETE);
+ /* Filter index */
+ UINT8_TO_STREAM(p, filt_index);
+
+ if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF,
+ (UINT8)(BTM_BLE_ADV_FILT_META_HDR_LENGTH),
+ param,
+ btm_ble_scan_pf_cmpl_cback))
+ == BTM_NO_RESOURCES) {
+ return st;
+ }
+ btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_FEAT_SEL, BTM_BLE_FILT_ADV_PARAM,
+ ref_value, NULL, p_cmpl_cback);
+ } else if (BTM_BLE_SCAN_COND_CLEAR == action) {
+ /* Deallocate all filters here */
+ btm_ble_dealloc_addr_filter_counter(NULL, BTM_BLE_PF_TYPE_ALL);
+
+ /* select feature based on control block settings */
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL);
+ UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_CLEAR);
+
+ if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF,
+ (UINT8)(BTM_BLE_ADV_FILT_META_HDR_LENGTH - 1),
+ param,
+ btm_ble_scan_pf_cmpl_cback))
+ == BTM_NO_RESOURCES) {
+ return st;
+ }
+ btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_FEAT_SEL, BTM_BLE_FILT_ADV_PARAM,
+ ref_value, NULL, p_cmpl_cback);
+ }
+
+ return st;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleEnableDisableFilterFeature
+**
+** Description This function is called to enable / disable the APCF feature
+**
+** Parameters enable the generic scan condition.
+** enable: enable or disable the filter condition
+** p_stat_cback - Status callback pointer
+** ref_value - Ref value
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleEnableDisableFilterFeature(UINT8 enable,
+ tBTM_BLE_PF_STATUS_CBACK *p_stat_cback,
+ tBTM_BLE_REF_VALUE ref_value)
+{
+ UINT8 param[20], *p;
+ tBTM_STATUS st = BTM_WRONG_MODE;
+
+ if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) {
+ return st;
+ }
+
+ p = param;
+ memset(param, 0, 20);
+
+ /* enable the content filter in controller */
+ p = param;
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_ENABLE);
+ /* enable adv data payload filtering */
+ UINT8_TO_STREAM(p, enable);
+
+ if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF,
+ BTM_BLE_PCF_ENABLE_LEN, param,
+ btm_ble_scan_pf_cmpl_cback)) == BTM_CMD_STARTED) {
+ btm_ble_adv_filt_cb.p_filt_stat_cback = p_stat_cback;
+ btm_ble_advfilt_enq_op_q(enable, BTM_BLE_META_PF_ENABLE, BTM_BLE_FILT_ENABLE_DISABLE,
+ ref_value, NULL, NULL);
+ }
+ return st;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleCfgFilterCondition
+**
+** Description This function is called to configure the adv data payload filter
+** condition.
+**
+** Parameters action: to read/write/clear
+** cond_type: filter condition type.
+** filt_index - Filter index
+** p_cond: filter condition parameter
+** p_cmpl_cback - Config callback pointer
+** ref_value - Reference value
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleCfgFilterCondition(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_COND_TYPE cond_type,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBTM_BLE_PF_COND_PARAM *p_cond,
+ tBTM_BLE_PF_CFG_CBACK *p_cmpl_cback,
+ tBTM_BLE_REF_VALUE ref_value)
+{
+ tBTM_STATUS st = BTM_ILLEGAL_VALUE;
+ UINT8 ocf = 0;
+ BTM_TRACE_EVENT (" BTM_BleCfgFilterCondition action:%d, cond_type:%d, index:%d", action,
+ cond_type, filt_index);
+
+ if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) {
+ return st;
+ }
+
+ switch (cond_type) {
+ /* write service data filter */
+ case BTM_BLE_PF_SRVC_DATA_PATTERN:
+ /* write manufacturer data filter */
+ case BTM_BLE_PF_MANU_DATA:
+ st = btm_ble_update_pf_manu_data(action, filt_index, p_cond, cond_type, 0, ref_value);
+ break;
+
+ /* write local name filter */
+ case BTM_BLE_PF_LOCAL_NAME:
+ st = btm_ble_update_pf_local_name(action, filt_index, p_cond);
+ break;
+
+ /* filter on advertiser address */
+ case BTM_BLE_PF_ADDR_FILTER:
+ st = btm_ble_update_addr_filter(action, filt_index, p_cond);
+ break;
+
+ /* filter on service/solicited UUID */
+ case BTM_BLE_PF_SRVC_UUID:
+ case BTM_BLE_PF_SRVC_SOL_UUID:
+ st = btm_ble_update_uuid_filter(action, filt_index, cond_type, p_cond, 0, ref_value);
+ break;
+
+ case BTM_BLE_PF_SRVC_DATA:
+ st = btm_ble_update_srvc_data_change(action, filt_index, p_cond);
+ break;
+
+ case BTM_BLE_PF_TYPE_ALL: /* only used to clear filter */
+ st = btm_ble_clear_scan_pf_filter(action, filt_index, p_cond, p_cmpl_cback,
+ 0, ref_value);
+ break;
+
+ default:
+ BTM_TRACE_WARNING("condition type [%d] not supported currently.", cond_type);
+ break;
+ }
+
+ if (BTM_CMD_STARTED == st && cond_type != BTM_BLE_PF_TYPE_ALL) {
+ ocf = btm_ble_condtype_to_ocf(cond_type);
+ btm_ble_advfilt_enq_op_q(action, ocf, BTM_BLE_FILT_CFG, ref_value, p_cmpl_cback, NULL);
+ } else if (BTM_CMD_STARTED == st && BTM_BLE_PF_TYPE_ALL == cond_type) {
+ btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_FEAT_SEL, BTM_BLE_FILT_CFG,
+ ref_value, p_cmpl_cback, NULL);
+ }
+ return st;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_adv_filter_init
+**
+** Description This function initializes the adv filter control block
+**
+** Parameters
+**
+** Returns status
+**
+*******************************************************************************/
+void btm_ble_adv_filter_init(void)
+{
+#if BTM_DYNAMIC_MEMORY == TRUE
+ btm_ble_adv_filt_cb_ptr = (tBTM_BLE_ADV_FILTER_CB *)osi_malloc(sizeof(tBTM_BLE_ADV_FILTER_CB));
+ cmn_ble_adv_vsc_cb_ptr = (tBTM_BLE_VSC_CB *)osi_malloc(sizeof(tBTM_BLE_VSC_CB));
+ if (btm_ble_adv_filt_cb_ptr == NULL || cmn_ble_adv_vsc_cb_ptr == NULL) {
+ BTM_TRACE_ERROR("%s malloc failed", __func__);
+ return;
+ }
+ memset((void *)btm_ble_adv_filt_cb_ptr, 0, sizeof(tBTM_BLE_ADV_FILTER_CB));
+ memset((void *)cmn_ble_adv_vsc_cb_ptr, 0, sizeof(tBTM_BLE_VSC_CB));
+#endif
+ memset(&btm_ble_adv_filt_cb, 0, sizeof(tBTM_BLE_ADV_FILTER_CB));
+ if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) {
+ return;
+ }
+
+ if (cmn_ble_adv_vsc_cb.max_filter > 0) {
+ btm_ble_adv_filt_cb.p_addr_filter_count =
+ (tBTM_BLE_PF_COUNT *) osi_malloc( sizeof(tBTM_BLE_PF_COUNT) * cmn_ble_adv_vsc_cb.max_filter);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_adv_filter_cleanup
+**
+** Description This function de-initializes the adv filter control block
+**
+** Parameters
+**
+** Returns status
+**
+*******************************************************************************/
+void btm_ble_adv_filter_cleanup(void)
+{
+ if (btm_ble_adv_filt_cb.p_addr_filter_count) {
+ osi_free(btm_ble_adv_filt_cb.p_addr_filter_count);
+ btm_ble_adv_filt_cb.p_addr_filter_count = NULL;
+ }
+
+#if BTM_DYNAMIC_MEMORY == TRUE
+ osi_free(btm_ble_adv_filt_cb_ptr);
+ btm_ble_adv_filt_cb_ptr = NULL;
+ osi_free(cmn_ble_adv_vsc_cb_ptr);
+ cmn_ble_adv_vsc_cb_ptr = NULL;
+#endif
+}
+
+#endif
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_ble_batchscan.c b/lib/bt/host/bluedroid/stack/btm/btm_ble_batchscan.c
new file mode 100644
index 00000000..5b0fcd8f
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_ble_batchscan.c
@@ -0,0 +1,953 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 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 <stdio.h>
+#include <stddef.h>
+#include "common/bt_target.h"
+
+#include "stack/btm_ble_api.h"
+#include "stack/bt_types.h"
+//#include "bt_utils.h"
+#include "stack/btu.h"
+#include "btm_int.h"
+#include "device/controller.h"
+#include "stack/hcimsgs.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#if BTM_DYNAMIC_MEMORY == FALSE
+tBTM_BLE_BATCH_SCAN_CB ble_batchscan_cb;
+tBTM_BLE_ADV_TRACK_CB ble_advtrack_cb;
+#else
+tBTM_BLE_BATCH_SCAN_CB *ble_batchscan_cb_ptr;
+tBTM_BLE_ADV_TRACK_CB *ble_advtrack_cb_ptr;
+#define ble_batchscan_cb (*ble_batchscan_cb_ptr)
+#define ble_advtrack_cb (*ble_advtrack_cb_ptr)
+#endif
+
+/* length of each batch scan command */
+#define BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN 4
+#define BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN 12
+#define BTM_BLE_BATCH_SCAN_ENB_DISB_LEN 2
+#define BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN 2
+
+#define BTM_BLE_BATCH_SCAN_CB_EVT_MASK 0xF0
+#define BTM_BLE_BATCH_SCAN_SUBCODE_MASK 0x0F
+
+/*******************************************************************************
+** Local functions
+*******************************************************************************/
+void btm_ble_batchscan_vsc_cmpl_cback (tBTM_VSC_CMPL *p_params);
+void btm_ble_batchscan_cleanup(void);
+
+/*******************************************************************************
+**
+** Function btm_ble_batchscan_filter_track_adv_vse_cback
+**
+** Description VSE callback for batch scan, filter, and tracking events.
+**
+** Returns None
+**
+*******************************************************************************/
+void btm_ble_batchscan_filter_track_adv_vse_cback(UINT8 len, UINT8 *p)
+{
+ tBTM_BLE_TRACK_ADV_DATA adv_data;
+
+ UINT8 sub_event = 0;
+ tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+ STREAM_TO_UINT8(sub_event, p);
+
+ BTM_TRACE_EVENT("btm_ble_batchscan_filter_track_adv_vse_cback called with event:%x", sub_event);
+ if (HCI_VSE_SUBCODE_BLE_THRESHOLD_SUB_EVT == sub_event &&
+ NULL != ble_batchscan_cb.p_thres_cback) {
+ ble_batchscan_cb.p_thres_cback(ble_batchscan_cb.ref_value);
+ return;
+ }
+
+ if (HCI_VSE_SUBCODE_BLE_TRACKING_SUB_EVT == sub_event && NULL != ble_advtrack_cb.p_track_cback) {
+ if (len < 10) {
+ return;
+ }
+
+ memset(&adv_data, 0 , sizeof(tBTM_BLE_TRACK_ADV_DATA));
+ BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+ adv_data.client_if = (UINT8)ble_advtrack_cb.ref_value;
+ if (cmn_ble_vsc_cb.version_supported > BTM_VSC_CHIP_CAPABILITY_L_VERSION) {
+ STREAM_TO_UINT8(adv_data.filt_index, p);
+ STREAM_TO_UINT8(adv_data.advertiser_state, p);
+ STREAM_TO_UINT8(adv_data.advertiser_info_present, p);
+ STREAM_TO_BDADDR(adv_data.bd_addr.address, p);
+ STREAM_TO_UINT8(adv_data.addr_type, p);
+
+ /* Extract the adv info details */
+ if (ADV_INFO_PRESENT == adv_data.advertiser_info_present) {
+ STREAM_TO_UINT8(adv_data.tx_power, p);
+ STREAM_TO_UINT8(adv_data.rssi_value, p);
+ STREAM_TO_UINT16(adv_data.time_stamp, p);
+
+ STREAM_TO_UINT8(adv_data.adv_pkt_len, p);
+ if (adv_data.adv_pkt_len > 0) {
+ adv_data.p_adv_pkt_data = osi_malloc(adv_data.adv_pkt_len);
+ memcpy(adv_data.p_adv_pkt_data, p, adv_data.adv_pkt_len);
+ }
+
+ STREAM_TO_UINT8(adv_data.scan_rsp_len, p);
+ if (adv_data.scan_rsp_len > 0) {
+ adv_data.p_scan_rsp_data = osi_malloc(adv_data.scan_rsp_len);
+ memcpy(adv_data.p_scan_rsp_data, p, adv_data.scan_rsp_len);
+ }
+ }
+ } else {
+ /* Based on L-release version */
+ STREAM_TO_UINT8(adv_data.filt_index, p);
+ STREAM_TO_UINT8(adv_data.addr_type, p);
+ STREAM_TO_BDADDR(adv_data.bd_addr.address, p);
+ STREAM_TO_UINT8(adv_data.advertiser_state, p);
+ }
+
+ BTM_TRACE_EVENT("track_adv_vse_cback called: %d, %d, %d", adv_data.filt_index,
+ adv_data.addr_type, adv_data.advertiser_state);
+ ble_advtrack_cb.p_track_cback(&adv_data);
+ return;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_batchscan_enq_op_q
+**
+** Description enqueue a batchscan operation in q to check command complete
+** status
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_batchscan_enq_op_q(UINT8 opcode, tBTM_BLE_BATCH_SCAN_STATE cur_state,
+ UINT8 cb_evt, tBTM_BLE_REF_VALUE ref_value)
+{
+ ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.next_idx] = (opcode | (cb_evt << 4));
+ ble_batchscan_cb.op_q.cur_state[ble_batchscan_cb.op_q.next_idx] = cur_state;
+ ble_batchscan_cb.op_q.ref_value[ble_batchscan_cb.op_q.next_idx] = ref_value;
+ BTM_TRACE_DEBUG("btm_ble_batchscan_enq_op_q: subcode:%d, Cur_state:%d, ref_value:%d",
+ ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.next_idx],
+ ble_batchscan_cb.op_q.cur_state[ble_batchscan_cb.op_q.next_idx],
+ ble_batchscan_cb.op_q.ref_value[ble_batchscan_cb.op_q.next_idx]);
+ ble_batchscan_cb.op_q.next_idx = (ble_batchscan_cb.op_q.next_idx + 1)
+ % BTM_BLE_BATCH_SCAN_MAX;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_batchscan_enq_rep_q
+**
+** Description enqueue a batchscan report operation in q to check command complete
+** status
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_batchscan_enq_rep_q(UINT8 report_format, tBTM_BLE_REF_VALUE ref_value)
+{
+ int i = 0;
+ for (i = 0; i < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; i++) {
+ if (report_format == ble_batchscan_cb.main_rep_q.rep_mode[i]) {
+ return BTM_ILLEGAL_VALUE;
+ }
+ }
+
+ ble_batchscan_cb.main_rep_q.rep_mode[ble_batchscan_cb.main_rep_q.next_idx] = report_format;
+ ble_batchscan_cb.main_rep_q.ref_value[ble_batchscan_cb.main_rep_q.next_idx] = ref_value;
+ ble_batchscan_cb.main_rep_q.num_records[ble_batchscan_cb.main_rep_q.next_idx] = 0;
+ ble_batchscan_cb.main_rep_q.data_len[ble_batchscan_cb.main_rep_q.next_idx] = 0;
+ ble_batchscan_cb.main_rep_q.p_data[ble_batchscan_cb.main_rep_q.next_idx] = NULL;
+ BTM_TRACE_DEBUG("btm_ble_batchscan_enq_rep_q: index:%d, rep %d, ref %d",
+ ble_batchscan_cb.main_rep_q.next_idx, report_format, ref_value);
+
+ ble_batchscan_cb.main_rep_q.next_idx = (ble_batchscan_cb.main_rep_q.next_idx + 1)
+ % BTM_BLE_BATCH_REP_MAIN_Q_SIZE;
+ return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_batchscan_enq_rep_data
+**
+** Description setup the data in the main report queue
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_batchscan_enq_rep_data(UINT8 report_format, UINT8 num_records, UINT8 *p_data,
+ UINT8 data_len)
+{
+ int index = 0, len = 0;
+ UINT8 *p_orig_data = NULL, *p_app_data = NULL;
+
+ for (index = 0; index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; index++) {
+ if (report_format == ble_batchscan_cb.main_rep_q.rep_mode[index]) {
+ break;
+ }
+ }
+
+ BTM_TRACE_DEBUG("btm_ble_batchscan_enq_rep_data: index:%d, rep %d, num %d len : %d",
+ index, report_format, num_records, data_len);
+
+ if (index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE && data_len > 0 && num_records > 0) {
+ len = ble_batchscan_cb.main_rep_q.data_len[index];
+ p_orig_data = ble_batchscan_cb.main_rep_q.p_data[index];
+ if (NULL != p_orig_data) {
+ p_app_data = osi_malloc(len + data_len);
+ memcpy(p_app_data, p_orig_data, len);
+ memcpy(p_app_data + len, p_data, data_len);
+ osi_free(p_orig_data);
+ ble_batchscan_cb.main_rep_q.p_data[index] = p_app_data;
+ ble_batchscan_cb.main_rep_q.num_records[index] += num_records;
+ ble_batchscan_cb.main_rep_q.data_len[index] += data_len;
+ } else {
+ p_app_data = osi_malloc(data_len);
+ memcpy(p_app_data, p_data, data_len);
+ ble_batchscan_cb.main_rep_q.p_data[index] = p_app_data;
+ ble_batchscan_cb.main_rep_q.num_records[index] = num_records;
+ ble_batchscan_cb.main_rep_q.data_len[index] = data_len;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_batchscan_deq_rep_q
+**
+** Description dequeue a batchscan report in q when command complete
+** is received
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_batchscan_deq_rep_data(UINT8 report_format, tBTM_BLE_REF_VALUE *p_ref_value,
+ UINT8 *p_num_records, UINT8 **p_data, UINT16 *p_data_len)
+{
+ int index = 0;
+
+ for (index = 0; index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; index++) {
+ if (report_format == ble_batchscan_cb.main_rep_q.rep_mode[index]) {
+ break;
+ }
+ }
+
+ if (BTM_BLE_BATCH_REP_MAIN_Q_SIZE == index) {
+ BTM_TRACE_ERROR("btm_ble_batchscan_deq_rep_data: rep_format:%d not found", report_format);
+ return;
+ }
+
+ *p_num_records = ble_batchscan_cb.main_rep_q.num_records[index];
+ *p_ref_value = ble_batchscan_cb.main_rep_q.ref_value[index];
+ *p_data = ble_batchscan_cb.main_rep_q.p_data[index];
+ *p_data_len = ble_batchscan_cb.main_rep_q.data_len[index];
+
+ ble_batchscan_cb.main_rep_q.p_data[index] = NULL;
+ ble_batchscan_cb.main_rep_q.data_len[index] = 0;
+ ble_batchscan_cb.main_rep_q.rep_mode[index] = 0;
+ ble_batchscan_cb.main_rep_q.ref_value[index] = 0;
+ ble_batchscan_cb.main_rep_q.num_records[index] = 0;
+
+ BTM_TRACE_DEBUG("btm_ble_batchscan_deq_rep_data: index:%d, rep %d, num %d, data_len %d",
+ index, report_format, *p_num_records, *p_data_len);
+
+ ble_batchscan_cb.main_rep_q.pending_idx = (ble_batchscan_cb.main_rep_q.pending_idx + 1)
+ % BTM_BLE_BATCH_SCAN_MAX;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_batchscan_deq_op_q
+**
+** Description dequeue a batch scan operation from q when command complete
+** is received
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_batchscan_deq_op_q(UINT8 *p_opcode, tBTM_BLE_BATCH_SCAN_STATE *cur_state,
+ UINT8 *p_cb_evt, tBTM_BLE_REF_VALUE *p_ref)
+{
+ *p_cb_evt = (ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.pending_idx] >> 4);
+ *p_opcode = (ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.pending_idx]
+ & BTM_BLE_BATCH_SCAN_SUBCODE_MASK);
+ *p_ref = ble_batchscan_cb.op_q.ref_value[ble_batchscan_cb.op_q.pending_idx];
+ *cur_state = (ble_batchscan_cb.op_q.cur_state[ble_batchscan_cb.op_q.pending_idx]);
+ ble_batchscan_cb.op_q.pending_idx = (ble_batchscan_cb.op_q.pending_idx + 1)
+ % BTM_BLE_BATCH_SCAN_MAX;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_read_batchscan_reports
+**
+** Description This function reads the reports from controller
+**
+** Parameters scan_mode - The mode for which the reports are to be read out from the controller
+** ref_value - Reference value
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_read_batchscan_reports(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
+ tBTM_BLE_REF_VALUE ref_value)
+{
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+ UINT8 param[BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN], *pp;
+ pp = param;
+
+ memset(param, 0, BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN);
+
+ UINT8_TO_STREAM (pp, BTM_BLE_BATCH_SCAN_READ_RESULTS);
+ UINT8_TO_STREAM (pp, scan_mode);
+
+ if ((status = BTM_VendorSpecificCommand (HCI_BLE_BATCH_SCAN_OCF,
+ BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN, param, btm_ble_batchscan_vsc_cmpl_cback))
+ != BTM_CMD_STARTED) {
+ BTM_TRACE_ERROR("btm_ble_read_batchscan_reports %d", status);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ if (BTM_CMD_STARTED == status) {
+ /* The user needs to be provided scan read reports event */
+ btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_READ_RESULTS, ble_batchscan_cb.cur_state,
+ BTM_BLE_BATCH_SCAN_READ_REPTS_EVT, ref_value);
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_batchscan_vsc_cmpl_cback
+**
+** Description Batch scan VSC complete callback
+**
+** Parameters p_params - VSC completed callback parameters
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_batchscan_vsc_cmpl_cback (tBTM_VSC_CMPL *p_params)
+{
+ UINT8 *p = p_params->p_param_buf;
+ UINT16 len = p_params->param_len;
+ tBTM_BLE_REF_VALUE ref_value = 0;
+
+ UINT8 status = 0, subcode = 0, opcode = 0;
+ UINT8 report_format = 0, num_records = 0, cb_evt = 0;
+ UINT16 data_len = 0;
+ tBTM_BLE_BATCH_SCAN_STATE cur_state = 0;
+ tBTM_STATUS btm_status = 0;
+ UINT8 *p_data = NULL;
+
+ if (len < 2) {
+ BTM_TRACE_ERROR("wrong length for btm_ble_batch_scan_vsc_cmpl_cback");
+ btm_ble_batchscan_deq_op_q(&opcode, &cur_state, &cb_evt, &ref_value);
+ return;
+ }
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT8(subcode, p);
+
+ btm_ble_batchscan_deq_op_q(&opcode, &cur_state, &cb_evt, &ref_value);
+
+ BTM_TRACE_DEBUG("btm_ble_batchscan op_code = %02x state = %02x cb_evt = %02x,ref_value=%d",
+ opcode, cur_state, cb_evt, ref_value);
+
+ if (opcode != subcode) {
+ BTM_TRACE_ERROR("Got unexpected VSC cmpl, expected: %d got: %d", subcode, opcode);
+ return;
+ }
+
+ switch (subcode) {
+ case BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE: {
+ if (BTM_SUCCESS == status && BTM_BLE_SCAN_ENABLE_CALLED == cur_state) {
+ ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLED_STATE;
+ } else if (BTM_BLE_SCAN_ENABLE_CALLED == cur_state) {
+ BTM_TRACE_ERROR("SCAN_ENB_DISAB_CUST_FEATURE - Invalid state after enb");
+ ble_batchscan_cb.cur_state = BTM_BLE_SCAN_INVALID_STATE;
+ }
+
+ BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEAT status = %d, state: %d,evt=%d",
+ status, ble_batchscan_cb.cur_state, cb_evt);
+
+ if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback) {
+ ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status);
+ }
+ break;
+ }
+
+ case BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM: {
+ BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM status = %d, evt=%d",
+ status, cb_evt);
+ if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback) {
+ ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status);
+ }
+ break;
+ }
+
+ case BTM_BLE_BATCH_SCAN_SET_PARAMS: {
+ BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_SET_PARAMS status = %d,evt=%d", status, cb_evt);
+
+ if (BTM_BLE_SCAN_DISABLE_CALLED == cur_state) {
+ if (BTM_SUCCESS == status) {
+ ble_batchscan_cb.cur_state = BTM_BLE_SCAN_DISABLED_STATE;
+ } else {
+ BTM_TRACE_ERROR("BTM_BLE_BATCH_SCAN_SET_PARAMS - Invalid state after disabled");
+ ble_batchscan_cb.cur_state = BTM_BLE_SCAN_INVALID_STATE;
+ }
+ }
+
+ if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback) {
+ ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status);
+ }
+ break;
+ }
+
+ case BTM_BLE_BATCH_SCAN_READ_RESULTS: {
+ if (cb_evt != 0 && NULL != ble_batchscan_cb.p_scan_rep_cback) {
+ STREAM_TO_UINT8(report_format, p);
+ STREAM_TO_UINT8(num_records, p);
+ p = (uint8_t *)(p_params->p_param_buf + 4);
+ BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_READ_RESULTS status=%d,len=%d,rec=%d",
+ status, len - 4, num_records);
+
+ if (0 == num_records) {
+ btm_ble_batchscan_deq_rep_data(report_format, &ref_value, &num_records,
+ &p_data, &data_len);
+ if (NULL != ble_batchscan_cb.p_scan_rep_cback) {
+ ble_batchscan_cb.p_scan_rep_cback(ref_value, report_format, num_records,
+ data_len, p_data, status);
+ }
+ } else {
+ if ((len - 4) > 0) {
+ btm_ble_batchscan_enq_rep_data(report_format, num_records, p, len - 4);
+ /* More records could be in the buffer and needs to be pulled out */
+ btm_status = btm_ble_read_batchscan_reports(report_format, ref_value);
+ if (BTM_CMD_STARTED != btm_status) {
+ btm_ble_batchscan_deq_rep_data(report_format, &ref_value, &num_records,
+ &p_data, &data_len);
+ /* Send whatever is available, in case of a command failure */
+ if (NULL != ble_batchscan_cb.p_scan_rep_cback && NULL != p_data) {
+ ble_batchscan_cb.p_scan_rep_cback(ref_value, report_format,
+ num_records, data_len, p_data, status);
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_set_storage_config
+**
+** Description This function writes the storage configuration in controller
+**
+** Parameters batch_scan_full_max -Max storage space (in %) allocated to full scanning
+** batch_scan_trunc_max -Max storage space (in %) allocated to truncated scanning
+** batch_scan_notify_threshold - Setup notification level based on total space
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_set_storage_config(UINT8 batch_scan_full_max, UINT8 batch_scan_trunc_max,
+ UINT8 batch_scan_notify_threshold)
+{
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+ UINT8 param[BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN], *pp;
+
+ pp = param;
+ memset(param, 0, BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN);
+
+ UINT8_TO_STREAM (pp, BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM);
+ UINT8_TO_STREAM (pp, batch_scan_full_max);
+ UINT8_TO_STREAM (pp, batch_scan_trunc_max);
+ UINT8_TO_STREAM (pp, batch_scan_notify_threshold);
+
+ if ((status = BTM_VendorSpecificCommand (HCI_BLE_BATCH_SCAN_OCF,
+ BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN, param,
+ btm_ble_batchscan_vsc_cmpl_cback)) != BTM_CMD_STARTED) {
+ BTM_TRACE_ERROR("btm_ble_set_storage_config %d", status);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_set_batchscan_param
+**
+** Description This function writes the batch scan params in controller
+**
+** Parameters scan_mode -Batch scan mode
+** scan_interval - Scan interval
+** scan_window - Scan window
+** discard_rule -Discard rules
+** addr_type - Address type
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_set_batchscan_param(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
+ UINT32 scan_interval, UINT32 scan_window, tBLE_ADDR_TYPE addr_type,
+ tBTM_BLE_DISCARD_RULE discard_rule)
+{
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+ UINT8 scan_param[BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN], *pp_scan;
+
+ pp_scan = scan_param;
+ memset(scan_param, 0, BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN);
+
+ // Override param and decide addr_type based on own addr type
+ // TODO: Remove upper layer parameter?
+ addr_type = btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type;
+
+ UINT8_TO_STREAM (pp_scan, BTM_BLE_BATCH_SCAN_SET_PARAMS);
+ UINT8_TO_STREAM (pp_scan, scan_mode);
+ UINT32_TO_STREAM (pp_scan, scan_window);
+ UINT32_TO_STREAM (pp_scan, scan_interval);
+ UINT8_TO_STREAM (pp_scan, addr_type);
+ UINT8_TO_STREAM (pp_scan, discard_rule);
+
+ if ((status = BTM_VendorSpecificCommand (HCI_BLE_BATCH_SCAN_OCF,
+ BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN,
+ scan_param, btm_ble_batchscan_vsc_cmpl_cback)) != BTM_CMD_STARTED) {
+ BTM_TRACE_ERROR("btm_ble_set_batchscan_param %d", status);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_enable_disable_batchscan
+**
+** Description This function enables the customer specific feature in controller
+**
+** Parameters enable_disable: true - enable, false - disable
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_enable_disable_batchscan(BOOLEAN should_enable)
+{
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+ UINT8 shld_enable = 0x01;
+ UINT8 enable_param[BTM_BLE_BATCH_SCAN_ENB_DISB_LEN], *pp_enable;
+
+ if (!should_enable) {
+ shld_enable = 0x00;
+ }
+
+ if (should_enable) {
+ pp_enable = enable_param;
+ memset(enable_param, 0, BTM_BLE_BATCH_SCAN_ENB_DISB_LEN);
+
+ UINT8_TO_STREAM (pp_enable, BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE);
+ UINT8_TO_STREAM (pp_enable, shld_enable);
+
+ if ((status = BTM_VendorSpecificCommand(HCI_BLE_BATCH_SCAN_OCF,
+ BTM_BLE_BATCH_SCAN_ENB_DISB_LEN, enable_param,
+ btm_ble_batchscan_vsc_cmpl_cback)) != BTM_CMD_STARTED) {
+ status = BTM_MODE_UNSUPPORTED;
+ BTM_TRACE_ERROR("btm_ble_enable_disable_batchscan %d", status);
+ return BTM_ILLEGAL_VALUE;
+ }
+ } else if ((status = btm_ble_set_batchscan_param(BTM_BLE_BATCH_SCAN_MODE_DISABLE,
+ ble_batchscan_cb.scan_interval, ble_batchscan_cb.scan_window,
+ ble_batchscan_cb.addr_type, ble_batchscan_cb.discard_rule)) != BTM_CMD_STARTED) {
+ status = BTM_MODE_UNSUPPORTED;
+ BTM_TRACE_ERROR("btm_ble_enable_disable_batchscan %d", status);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ if (should_enable) {
+ ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLE_CALLED;
+ } else {
+ ble_batchscan_cb.cur_state = BTM_BLE_SCAN_DISABLE_CALLED;
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleSetStorageConfig
+**
+** Description This function is called to write storage config params.
+**
+** Parameters: batch_scan_full_max - Max storage space (in %) allocated to full style
+** batch_scan_trunc_max - Max storage space (in %) allocated to trunc style
+** batch_scan_notify_threshold - Setup notification level based on total space
+** p_setup_cback - Setup callback pointer
+** p_thres_cback - Threshold callback pointer
+** p_rep_cback - Reports callback pointer
+** ref_value - Reference value
+**
+** Returns tBTM_STATUS
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleSetStorageConfig(UINT8 batch_scan_full_max, UINT8 batch_scan_trunc_max,
+ UINT8 batch_scan_notify_threshold,
+ tBTM_BLE_SCAN_SETUP_CBACK *p_setup_cback,
+ tBTM_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback,
+ tBTM_BLE_SCAN_REP_CBACK *p_rep_cback,
+ tBTM_BLE_REF_VALUE ref_value)
+{
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+ tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+
+ BTM_TRACE_EVENT (" BTM_BleSetStorageConfig: %d, %d, %d, %d, %d",
+ ble_batchscan_cb.cur_state, ref_value, batch_scan_full_max, batch_scan_trunc_max,
+ batch_scan_notify_threshold);
+
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+ if (0 == cmn_ble_vsc_cb.tot_scan_results_strg) {
+ BTM_TRACE_ERROR("Controller does not support batch scan");
+ return BTM_ERR_PROCESSING;
+ }
+
+ ble_batchscan_cb.p_setup_cback = p_setup_cback;
+ ble_batchscan_cb.p_thres_cback = p_thres_cback;
+ ble_batchscan_cb.p_scan_rep_cback = p_rep_cback;
+ ble_batchscan_cb.ref_value = ref_value;
+
+ if (batch_scan_full_max > BTM_BLE_ADV_SCAN_FULL_MAX ||
+ batch_scan_trunc_max > BTM_BLE_ADV_SCAN_TRUNC_MAX ||
+ batch_scan_notify_threshold > BTM_BLE_ADV_SCAN_THR_MAX) {
+ BTM_TRACE_ERROR("Illegal set storage config params");
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ if (BTM_BLE_SCAN_INVALID_STATE == ble_batchscan_cb.cur_state ||
+ BTM_BLE_SCAN_DISABLED_STATE == ble_batchscan_cb.cur_state ||
+ BTM_BLE_SCAN_DISABLE_CALLED == ble_batchscan_cb.cur_state) {
+ status = btm_ble_enable_disable_batchscan(TRUE);
+ if (BTM_CMD_STARTED != status) {
+ return status;
+ }
+
+ ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLE_CALLED;
+ btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE,
+ BTM_BLE_SCAN_ENABLE_CALLED, 0, ref_value);
+ }
+
+ status = btm_ble_set_storage_config(batch_scan_full_max, batch_scan_trunc_max,
+ batch_scan_notify_threshold);
+ if (BTM_CMD_STARTED != status) {
+ return status;
+ }
+ /* The user needs to be provided scan config storage event */
+ btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM, ble_batchscan_cb.cur_state,
+ BTM_BLE_BATCH_SCAN_CFG_STRG_EVT, ref_value);
+
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_BleEnableBatchScan
+**
+** Description This function is called to configure and enable batch scanning
+**
+** Parameters: scan_mode -Batch scan mode
+** scan_interval - Scan interval value
+** scan_window - Scan window value
+** discard_rule - Data discard rule
+** ref_value - Reference value
+**
+** Returns tBTM_STATUS
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleEnableBatchScan(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
+ UINT32 scan_interval, UINT32 scan_window, tBLE_ADDR_TYPE addr_type,
+ tBTM_BLE_DISCARD_RULE discard_rule, tBTM_BLE_REF_VALUE ref_value)
+{
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+ tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+ BTM_TRACE_EVENT (" BTM_BleEnableBatchScan: %d, %d, %d, %d, %d, %d",
+ scan_mode, scan_interval, scan_window, addr_type, discard_rule, ref_value);
+
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+ if (0 == cmn_ble_vsc_cb.tot_scan_results_strg) {
+ BTM_TRACE_ERROR("Controller does not support batch scan");
+ return BTM_ERR_PROCESSING;
+ }
+
+ BTM_TRACE_DEBUG("BTM_BleEnableBatchScan: %d, %x, %x, %d, %d", scan_mode, scan_interval,
+ scan_window, discard_rule, ble_batchscan_cb.cur_state);
+
+ /* Only 16 bits will be used for scan interval and scan window as per agreement with Google */
+ /* So the standard LE range would suffice for scan interval and scan window */
+ if ((BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN, BTM_BLE_SCAN_INT_MAX) ||
+ BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN, BTM_BLE_SCAN_WIN_MAX))
+ && (BTM_BLE_BATCH_SCAN_MODE_PASS == scan_mode || BTM_BLE_BATCH_SCAN_MODE_ACTI == scan_mode
+ || BTM_BLE_BATCH_SCAN_MODE_PASS_ACTI == scan_mode)
+ && (BTM_BLE_DISCARD_OLD_ITEMS == discard_rule ||
+ BTM_BLE_DISCARD_LOWER_RSSI_ITEMS == discard_rule)) {
+ if (BTM_BLE_SCAN_INVALID_STATE == ble_batchscan_cb.cur_state ||
+ BTM_BLE_SCAN_DISABLED_STATE == ble_batchscan_cb.cur_state ||
+ BTM_BLE_SCAN_DISABLE_CALLED == ble_batchscan_cb.cur_state) {
+ status = btm_ble_enable_disable_batchscan(TRUE);
+ if (BTM_CMD_STARTED != status) {
+ return status;
+ }
+ btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE,
+ BTM_BLE_SCAN_ENABLE_CALLED, 0, ref_value);
+ }
+
+ ble_batchscan_cb.scan_mode = scan_mode;
+ ble_batchscan_cb.scan_interval = scan_interval;
+ ble_batchscan_cb.scan_window = scan_window;
+ ble_batchscan_cb.addr_type = addr_type;
+ ble_batchscan_cb.discard_rule = discard_rule;
+ /* This command starts batch scanning, if enabled */
+ status = btm_ble_set_batchscan_param(scan_mode, scan_interval, scan_window, addr_type,
+ discard_rule);
+ if (BTM_CMD_STARTED != status) {
+ return status;
+ }
+
+ /* The user needs to be provided scan enable event */
+ btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_SET_PARAMS, ble_batchscan_cb.cur_state,
+ BTM_BLE_BATCH_SCAN_ENABLE_EVT, ref_value);
+ } else {
+ BTM_TRACE_ERROR("Illegal enable scan params");
+ return BTM_ILLEGAL_VALUE;
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleDisableBatchScan
+**
+** Description This function is called to disable batch scanning
+**
+** Parameters: ref_value - Reference value
+**
+** Returns tBTM_STATUS
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleDisableBatchScan(tBTM_BLE_REF_VALUE ref_value)
+{
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+ tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+ BTM_TRACE_EVENT (" BTM_BleDisableBatchScan");
+
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+ if (0 == cmn_ble_vsc_cb.tot_scan_results_strg) {
+ BTM_TRACE_ERROR("Controller does not support batch scan");
+ return BTM_ERR_PROCESSING;
+ }
+
+ status = btm_ble_enable_disable_batchscan(FALSE);
+ if (BTM_CMD_STARTED == status) {
+ /* The user needs to be provided scan disable event */
+ btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_SET_PARAMS,
+ BTM_BLE_SCAN_DISABLE_CALLED, BTM_BLE_BATCH_SCAN_DISABLE_EVT,
+ ref_value);
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleReadScanReports
+**
+** Description This function is called to start reading batch scan reports
+**
+** Parameters: scan_mode - Batch scan mode
+** ref_value - Reference value
+**
+** Returns tBTM_STATUS
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleReadScanReports(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
+ tBTM_BLE_REF_VALUE ref_value)
+{
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+ tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+ UINT8 read_scan_mode = 0;
+ UINT8 *p_data = NULL, num_records = 0;
+ UINT16 data_len = 0;
+
+ BTM_TRACE_EVENT (" BTM_BleReadScanReports; %d, %d", scan_mode, ref_value);
+
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+ if (0 == cmn_ble_vsc_cb.tot_scan_results_strg) {
+ BTM_TRACE_ERROR("Controller does not support batch scan");
+ return BTM_ERR_PROCESSING;
+ }
+
+ /* Check if the requested scan mode has already been setup by the user */
+ read_scan_mode = ble_batchscan_cb.scan_mode & BTM_BLE_BATCH_SCAN_MODE_ACTI;
+ if (0 == read_scan_mode) {
+ read_scan_mode = ble_batchscan_cb.scan_mode & BTM_BLE_BATCH_SCAN_MODE_PASS;
+ }
+
+ /* Check only for modes, as scan reports can be called after disabling batch scan */
+ if (read_scan_mode > 0 && (BTM_BLE_BATCH_SCAN_MODE_PASS == scan_mode ||
+ BTM_BLE_BATCH_SCAN_MODE_ACTI == scan_mode)) {
+ status = btm_ble_batchscan_enq_rep_q(scan_mode, ref_value);
+ if (BTM_SUCCESS == status) {
+ status = btm_ble_read_batchscan_reports(scan_mode, ref_value);
+ if (BTM_CMD_STARTED != status) {
+ btm_ble_batchscan_deq_rep_data(scan_mode, &ref_value,
+ &num_records, &p_data, &data_len);
+ }
+ }
+ } else {
+ BTM_TRACE_ERROR("Illegal read scan params: %d, %d, %d", read_scan_mode, scan_mode,
+ ble_batchscan_cb.cur_state);
+ return BTM_ILLEGAL_VALUE;
+ }
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_BleTrackAdvertiser
+**
+** Description This function is called to setup the callback for tracking advertisers
+**
+** Parameters: p_track_cback - Tracking callback pointer
+** ref_value - Reference value
+**
+** Returns tBTM_STATUS
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK *p_track_cback,
+ tBTM_BLE_REF_VALUE ref_value)
+{
+ tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+ BTM_TRACE_EVENT (" BTM_BleTrackAdvertiser");
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+ if (0 == cmn_ble_vsc_cb.tot_scan_results_strg) {
+ BTM_TRACE_ERROR("Controller does not support scan storage");
+ return BTM_ERR_PROCESSING;
+ }
+
+ ble_advtrack_cb.p_track_cback = p_track_cback;
+ ble_advtrack_cb.ref_value = ref_value;
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_batchscan_init
+**
+** Description This function initialize the batch scan control block.
+**
+** Parameters None
+**
+** Returns status
+**
+*******************************************************************************/
+void btm_ble_batchscan_init(void)
+{
+#if BTM_DYNAMIC_MEMORY == TRUE
+ ble_batchscan_cb_ptr = (tBTM_BLE_BATCH_SCAN_CB *)osi_malloc(sizeof(tBTM_BLE_BATCH_SCAN_CB));
+ ble_advtrack_cb_ptr = (tBTM_BLE_ADV_TRACK_CB *)osi_malloc(sizeof(tBTM_BLE_ADV_TRACK_CB));
+ if (ble_batchscan_cb_ptr == NULL || ble_advtrack_cb_ptr == NULL) {
+ BTM_TRACE_ERROR("%s malloc failed", __func__);
+ return;
+ }
+#endif
+ BTM_TRACE_EVENT (" btm_ble_batchscan_init");
+ memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB));
+ memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB));
+ BTM_RegisterForVSEvents(btm_ble_batchscan_filter_track_adv_vse_cback, TRUE);
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_batchscan_cleanup
+**
+** Description This function cleans the batch scan control block.
+**
+** Parameters None
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_batchscan_cleanup(void)
+{
+ int index = 0;
+ BTM_TRACE_EVENT (" btm_ble_batchscan_cleanup");
+
+ for (index = 0; index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; index++) {
+ if (NULL != ble_batchscan_cb.main_rep_q.p_data[index]) {
+ osi_free(ble_batchscan_cb.main_rep_q.p_data[index]);
+ ble_batchscan_cb.main_rep_q.p_data[index] = NULL;
+ }
+ }
+
+ memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB));
+ memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB));
+
+#if BTM_DYNAMIC_MEMORY == TRUE
+ osi_free(ble_batchscan_cb_ptr);
+ osi_free(ble_advtrack_cb_ptr);
+ ble_batchscan_cb_ptr = NULL;
+ ble_advtrack_cb_ptr = NULL;
+#endif
+}
+
+#endif
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_ble_bgconn.c b/lib/bt/host/bluedroid/stack/btm/btm_ble_bgconn.c
new file mode 100644
index 00000000..4cb282b7
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_ble_bgconn.c
@@ -0,0 +1,836 @@
+/******************************************************************************
+ *
+ * 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 functions for BLE whitelist operation.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "common/bt_trace.h"
+#include "device/controller.h"
+#include "osi/allocator.h"
+#include "osi/hash_map.h"
+#include "stack/bt_types.h"
+#include "stack/btu.h"
+#include "btm_int.h"
+#include "l2c_int.h"
+#include "stack/hcimsgs.h"
+//#include "bt_utils.h"
+
+#ifndef BTM_BLE_SCAN_PARAM_TOUT
+#define BTM_BLE_SCAN_PARAM_TOUT 50 /* 50 seconds */
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+
+static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state);
+static void btm_wl_update_to_controller(void);
+
+// Unfortunately (for now?) we have to maintain a copy of the device whitelist
+// on the host to determine if a device is pending to be connected or not. This
+// controls whether the host should keep trying to scan for whitelisted
+// peripherals or not.
+// TODO: Move all of this to controller/le/background_list or similar?
+static const size_t background_connection_buckets = 42;
+static hash_map_t *background_connections = NULL;
+
+typedef struct background_connection_t {
+ bt_bdaddr_t address;
+} background_connection_t;
+
+static bool bdaddr_equality_fn(const void *x, const void *y)
+{
+ return bdaddr_equals((bt_bdaddr_t *)x, (bt_bdaddr_t *)y);
+}
+
+static void background_connections_lazy_init(void)
+{
+ if (!background_connections) {
+ background_connections = hash_map_new(background_connection_buckets,
+ hash_function_bdaddr, NULL, osi_free_func, bdaddr_equality_fn);
+ assert(background_connections);
+ }
+}
+
+static BOOLEAN background_connection_add(bt_bdaddr_t *address)
+{
+ assert(address);
+ background_connections_lazy_init();
+ background_connection_t *connection = hash_map_get(background_connections, address);
+ if (!connection) {
+ connection = osi_calloc(sizeof(background_connection_t));
+ connection->address = *address;
+ hash_map_set(background_connections, &(connection->address), connection);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static BOOLEAN background_connection_remove(bt_bdaddr_t *address)
+{
+ if (address && background_connections) {
+ return hash_map_erase(background_connections, address);
+ }
+ return FALSE;
+}
+
+static void background_connections_clear(void)
+{
+ if (background_connections) {
+ hash_map_clear(background_connections);
+ }
+}
+
+static bool background_connections_pending_cb(hash_map_entry_t *hash_entry, void *context)
+{
+ bool *pending_connections = context;
+ background_connection_t *connection = hash_entry->data;
+ const bool connected = BTM_IsAclConnectionUp(connection->address.address, BT_TRANSPORT_LE);
+ if (!connected) {
+ *pending_connections = true;
+ return false;
+ }
+ return true;
+}
+
+static bool background_connections_pending(void)
+{
+ bool pending_connections = false;
+ if (background_connections) {
+ hash_map_foreach(background_connections, background_connections_pending_cb, &pending_connections);
+ }
+ return pending_connections;
+}
+
+/*******************************************************************************
+**
+** Function btm_update_scanner_filter_policy
+**
+** Description This function updates the filter policy of scanner
+*******************************************************************************/
+void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy)
+{
+ tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
+
+ UINT32 scan_interval = !p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval;
+ UINT32 scan_window = !p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window;
+
+ BTM_TRACE_EVENT ("%s\n", __func__);
+
+ p_inq->sfp = scan_policy;
+ p_inq->scan_type = p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE ? BTM_BLE_SCAN_MODE_ACTI : p_inq->scan_type;
+
+ if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0) {
+ btsnd_hcic_ble_set_scan_params(p_inq->scan_type, (UINT16)scan_interval,
+ (UINT16)scan_window,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+ scan_policy);
+ } else {
+ btm_ble_send_extended_scan_params(p_inq->scan_type, scan_interval, scan_window,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+ scan_policy);
+ }
+}
+/*******************************************************************************
+**
+** Function btm_add_dev_to_controller
+**
+** Description This function load the device into controller white list
+*******************************************************************************/
+BOOLEAN btm_add_dev_to_controller (BOOLEAN to_add, BD_ADDR bd_addr, tBLE_ADDR_TYPE wl_addr_type)
+{
+ /*
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+ tBLE_ADDR_TYPE addr_type = BLE_ADDR_PUBLIC;
+ BOOLEAN started = FALSE;
+ BD_ADDR dummy_bda = {0};
+ tBT_DEVICE_TYPE dev_type;
+
+ if (p_dev_rec != NULL &&
+ p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) {
+ if (to_add) {
+ if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC || !BTM_BLE_IS_RESOLVE_BDA(bd_addr)) {
+ started = btsnd_hcic_ble_add_white_list (p_dev_rec->ble.ble_addr_type, bd_addr);
+ p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT;
+ } else if (memcmp(p_dev_rec->ble.static_addr, bd_addr, BD_ADDR_LEN) != 0 &&
+ memcmp(p_dev_rec->ble.static_addr, dummy_bda, BD_ADDR_LEN) != 0) {
+ started = btsnd_hcic_ble_add_white_list (p_dev_rec->ble.static_addr_type,
+ p_dev_rec->ble.static_addr);
+ p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT;
+ }
+ } else {
+ if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC || !BTM_BLE_IS_RESOLVE_BDA(bd_addr)) {
+ started = btsnd_hcic_ble_remove_from_white_list (p_dev_rec->ble.ble_addr_type, bd_addr);
+ }
+ if (memcmp(p_dev_rec->ble.static_addr, dummy_bda, BD_ADDR_LEN) != 0 &&
+ memcmp(p_dev_rec->ble.static_addr, bd_addr, BD_ADDR_LEN) != 0) {
+ started = btsnd_hcic_ble_remove_from_white_list (p_dev_rec->ble.static_addr_type, p_dev_rec->ble.static_addr);
+ }
+ p_dev_rec->ble.in_controller_list &= ~BTM_WHITE_LIST_BIT;
+ }
+ } // if not a known device, shall we add it?
+ else {
+ BTM_ReadDevInfo(bd_addr, &dev_type, &addr_type);
+
+ if (to_add) {
+ started = btsnd_hcic_ble_add_white_list (addr_type, bd_addr);
+ }else{
+ started = btsnd_hcic_ble_remove_from_white_list (addr_type, bd_addr);
+ }
+ }
+
+ return started;
+ */
+
+ /* Controller do not support resolvable address now, only support public address and static random address */
+ BOOLEAN started = FALSE;
+ if(wl_addr_type > BLE_ADDR_RANDOM) {
+ BTM_TRACE_ERROR("wl_addr_type is error\n");
+ return started;
+ }
+
+ if (to_add) {
+ started = btsnd_hcic_ble_add_white_list (wl_addr_type, bd_addr);
+ }else{
+ started = btsnd_hcic_ble_remove_from_white_list (wl_addr_type, bd_addr);
+ }
+
+ return started;
+
+
+}
+/*******************************************************************************
+**
+** Function btm_execute_wl_dev_operation
+**
+** Description execute the pending whitelist device operation(loading or removing)
+*******************************************************************************/
+BOOLEAN btm_execute_wl_dev_operation(void)
+{
+ tBTM_BLE_WL_OP *p_dev_op = btm_cb.ble_ctr_cb.wl_op_q;
+ UINT8 i = 0;
+ BOOLEAN rt = TRUE;
+
+ for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && rt; i ++, p_dev_op ++) {
+ if (p_dev_op->in_use) {
+ rt = btm_add_dev_to_controller(p_dev_op->to_add, p_dev_op->bd_addr, p_dev_op->addr_type);
+ memset(p_dev_op, 0, sizeof(tBTM_BLE_WL_OP));
+ } else {
+ break;
+ }
+ }
+ return rt;
+}
+/*******************************************************************************
+**
+** Function btm_enq_wl_dev_operation
+**
+** Description enqueue the pending whitelist device operation(loading or removing).
+*******************************************************************************/
+void btm_enq_wl_dev_operation(BOOLEAN to_add, BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type)
+{
+ tBTM_BLE_WL_OP *p_dev_op = btm_cb.ble_ctr_cb.wl_op_q;
+ UINT8 i = 0;
+
+ for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM; i ++, p_dev_op ++) {
+ if (p_dev_op->in_use && p_dev_op->addr_type == addr_type && !memcmp(p_dev_op->bd_addr, bd_addr, BD_ADDR_LEN)) {
+ p_dev_op->to_add = to_add;
+ return;
+ } else if (!p_dev_op->in_use) {
+ break;
+ }
+ }
+ if (i != BTM_BLE_MAX_BG_CONN_DEV_NUM) {
+ p_dev_op->in_use = TRUE;
+ p_dev_op->to_add = to_add;
+ p_dev_op->addr_type = addr_type;
+ memcpy(p_dev_op->bd_addr, bd_addr, BD_ADDR_LEN);
+ } else {
+ BTM_TRACE_ERROR("max pending WL operation reached, discard");
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function btm_update_dev_to_white_list
+**
+** Description This function adds or removes a device into/from
+** the white list.
+**
+*******************************************************************************/
+BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, tBTM_UPDATE_WHITELIST_CBACK *update_wl_cb)
+{
+ if(addr_type > BLE_ADDR_RANDOM) {
+ BTM_TRACE_ERROR("%s address type is error, unable to add device", __func__);
+ if (update_wl_cb){
+ update_wl_cb(HCI_ERR_ILLEGAL_PARAMETER_FMT,to_add);
+ }
+ return FALSE;
+ }
+
+ BD_ADDR invalid_rand_addr_a, invalid_rand_addr_b;
+ memset(invalid_rand_addr_a, 0xff, sizeof(BD_ADDR));
+ memset(invalid_rand_addr_b, 0x00, sizeof(BD_ADDR));
+
+ // look for public address information
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr);
+ // p_dev_rec is created at bluetooth initialization, p_dev_rec->ble.static_addr maybe be all 0 before pairing
+ if(p_dev_rec && memcmp(invalid_rand_addr_b, p_dev_rec->ble.static_addr, BD_ADDR_LEN) != 0) {
+ memcpy(bd_addr, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
+ addr_type = p_dev_rec->ble.static_addr_type;
+ }
+
+ // The device to be added to white list must be public address or random address
+ if(addr_type == BLE_ADDR_RANDOM) {
+ /*
+ A static address is a 48-bit randomly generated address and shall meet the following requirements:
+ • The two most significant bits of the address shall be equal to 1
+ • All bits of the random part of the address shall not be equal to 1
+ • All bits of the random part of the address shall not be equal to 0
+ */
+ invalid_rand_addr_b[0] = invalid_rand_addr_b[0] | BT_STATIC_RAND_ADDR_MASK;
+ if(memcmp(invalid_rand_addr_a, bd_addr, BD_ADDR_LEN) != 0
+ && memcmp(invalid_rand_addr_b, bd_addr, BD_ADDR_LEN) != 0){
+ // do nothing
+ } else {
+ BTC_TRACE_ERROR(" controller not support resolvable address");
+ if (update_wl_cb){
+ update_wl_cb(HCI_ERR_ILLEGAL_PARAMETER_FMT,to_add);
+ }
+ return FALSE;
+ }
+
+ }
+
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+
+ if (to_add && p_cb->white_list_avail_size == 0) {
+ BTM_TRACE_ERROR("%s Whitelist full, unable to add device", __func__);
+ if (update_wl_cb){
+ update_wl_cb(HCI_ERR_MEMORY_FULL,to_add);
+ }
+ return FALSE;
+ }
+
+ if (to_add) {
+ /* added the bd_addr to the connection hash map queue */
+ if(!background_connection_add((bt_bdaddr_t *)bd_addr)) {
+ /* if the bd_addr already exist in whitelist, just callback return TRUE */
+ if (update_wl_cb){
+ update_wl_cb(HCI_SUCCESS,to_add);
+ }
+ return TRUE;
+ }
+ } else {
+ /* remove the bd_addr to the connection hash map queue */
+ if(!background_connection_remove((bt_bdaddr_t *)bd_addr)){
+ /* if the bd_addr don't exist in whitelist, just callback return TRUE */
+ if (update_wl_cb){
+ update_wl_cb(HCI_SUCCESS,to_add);
+ }
+ return TRUE;
+ }
+ }
+
+ if (update_wl_cb){
+ //save add whitelist complete callback
+ p_cb->update_wl_cb = update_wl_cb;
+ }
+ /* stop the auto connect */
+ btm_suspend_wl_activity(p_cb->wl_state);
+ /* save the bd_addr to the btm_cb env */
+ btm_enq_wl_dev_operation(to_add, bd_addr, addr_type);
+ /* save the ba_addr to the controller white list */
+ btm_wl_update_to_controller();
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_clear_white_list
+**
+** Description This function clears the white list.
+**
+*******************************************************************************/
+void btm_ble_clear_white_list (tBTM_UPDATE_WHITELIST_CBACK *update_wl_cb)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+
+ BTM_TRACE_EVENT ("btm_ble_clear_white_list");
+ btsnd_hcic_ble_clear_white_list();
+ background_connections_clear();
+
+ if (update_wl_cb) {
+ p_cb->update_wl_cb = update_wl_cb;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_clear_white_list_complete
+**
+** Description Indicates white list cleared.
+**
+*******************************************************************************/
+void btm_ble_clear_white_list_complete(UINT8 *p_data, UINT16 evt_len)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ UINT8 status;
+ UNUSED(evt_len);
+
+ BTM_TRACE_EVENT ("btm_ble_clear_white_list_complete");
+ STREAM_TO_UINT8 (status, p_data);
+
+ if (status == HCI_SUCCESS) {
+ p_cb->white_list_avail_size = controller_get_interface()->get_ble_white_list_size();
+ } else {
+ BTM_TRACE_ERROR ("%s failed, status 0x%x\n", __func__, status);
+ }
+
+ if (p_cb->update_wl_cb) {
+ (*p_cb->update_wl_cb)(status, BTM_WHITELIST_CLEAR);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_white_list_init
+**
+** Description Initialize white list size
+**
+*******************************************************************************/
+void btm_ble_white_list_init(UINT8 white_list_size)
+{
+ BTM_TRACE_DEBUG("%s white_list_size = %d", __func__, white_list_size);
+ btm_cb.ble_ctr_cb.white_list_avail_size = white_list_size;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_add_2_white_list_complete
+**
+** Description White list element added
+**
+*******************************************************************************/
+void btm_ble_add_2_white_list_complete(UINT8 status)
+{
+ BTM_TRACE_EVENT("%s status=%d", __func__, status);
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ if (status == HCI_SUCCESS) {
+ --btm_cb.ble_ctr_cb.white_list_avail_size;
+ }
+ // add whitelist complete callback
+ if (p_cb->update_wl_cb)
+ {
+ (*p_cb->update_wl_cb)(status, BTM_WHITELIST_ADD);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_remove_from_white_list_complete
+**
+** Description White list element removal complete
+**
+*******************************************************************************/
+void btm_ble_remove_from_white_list_complete(UINT8 *p, UINT16 evt_len)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ UNUSED(evt_len);
+ BTM_TRACE_EVENT ("%s status=%d", __func__, *p);
+ if (*p == HCI_SUCCESS) {
+ ++btm_cb.ble_ctr_cb.white_list_avail_size;
+ }
+ if (p_cb->update_wl_cb)
+ {
+ (*p_cb->update_wl_cb)(*p, BTM_WHITELIST_REMOVE);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_start_auto_conn
+**
+** Description This function is to start/stop auto connection procedure.
+**
+** Parameters start: TRUE to start; FALSE to stop.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN btm_ble_start_auto_conn(BOOLEAN start)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ BD_ADDR dummy_bda = {0};
+ BOOLEAN exec = TRUE;
+ UINT16 scan_int;
+ UINT16 scan_win;
+ UINT8 own_addr_type = p_cb->addr_mgnt_cb.own_addr_type;
+ UINT8 peer_addr_type = BLE_ADDR_PUBLIC;
+
+ if (start) {
+ if (p_cb->conn_state == BLE_CONN_IDLE && background_connections_pending()
+ && btm_ble_topology_check(BTM_BLE_STATE_INIT)) {
+ p_cb->wl_state |= BTM_BLE_WL_INIT;
+
+ btm_execute_wl_dev_operation();
+
+#if BLE_PRIVACY_SPT == TRUE
+ btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_INIT);
+#endif
+ scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF) ?
+ BTM_BLE_SCAN_SLOW_INT_1 : p_cb->scan_int;
+ scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF) ?
+ BTM_BLE_SCAN_SLOW_WIN_1 : p_cb->scan_win;
+
+#if BLE_PRIVACY_SPT == TRUE
+ if (btm_cb.ble_ctr_cb.rl_state != BTM_BLE_RL_IDLE
+ && controller_get_interface()->supports_ble_privacy()) {
+ own_addr_type |= BLE_ADDR_TYPE_ID_BIT;
+ peer_addr_type |= BLE_ADDR_TYPE_ID_BIT;
+ }
+#endif
+
+ if (!btsnd_hcic_ble_create_ll_conn (scan_int, /* UINT16 scan_int */
+ scan_win, /* UINT16 scan_win */
+ 0x01, /* UINT8 white_list */
+ peer_addr_type, /* UINT8 addr_type_peer */
+ dummy_bda, /* BD_ADDR bda_peer */
+ own_addr_type, /* UINT8 addr_type_own */
+ BTM_BLE_CONN_INT_MIN_DEF, /* UINT16 conn_int_min */
+ BTM_BLE_CONN_INT_MAX_DEF, /* UINT16 conn_int_max */
+ BTM_BLE_CONN_SLAVE_LATENCY_DEF, /* UINT16 conn_latency */
+ BTM_BLE_CONN_TIMEOUT_DEF, /* UINT16 conn_timeout */
+ 0, /* UINT16 min_len */
+ 0)) { /* UINT16 max_len */
+ /* start auto connection failed */
+ exec = FALSE;
+ p_cb->wl_state &= ~BTM_BLE_WL_INIT;
+ } else {
+ btm_ble_set_conn_st (BLE_BG_CONN);
+ }
+ } else {
+ exec = FALSE;
+ }
+ } else {
+ if (p_cb->conn_state == BLE_BG_CONN) {
+ btsnd_hcic_ble_create_conn_cancel();
+ btm_ble_set_conn_st (BLE_CONN_CANCEL);
+ p_cb->wl_state &= ~BTM_BLE_WL_INIT;
+ } else {
+ BTM_TRACE_DEBUG("conn_st = %d, not in auto conn state, cannot stop", p_cb->conn_state);
+ exec = FALSE;
+ }
+ }
+ return exec;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_start_select_conn
+**
+** Description This function is to start/stop selective connection procedure.
+**
+** Parameters start: TRUE to start; FALSE to stop.
+** p_select_cback: callback function to return application
+** selection.
+**
+** Returns BOOLEAN: selective connection procedure is started.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_start_select_conn(BOOLEAN start, tBTM_BLE_SEL_CBACK *p_select_cback)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ UINT32 scan_int = p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF ? BTM_BLE_SCAN_FAST_INT : p_cb->scan_int;
+ UINT32 scan_win = p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF ? BTM_BLE_SCAN_FAST_WIN : p_cb->scan_win;
+
+ BTM_TRACE_EVENT ("%s", __func__);
+
+ if (start) {
+ if (!BTM_BLE_IS_SCAN_ACTIVE(p_cb->scan_activity)) {
+ if (p_select_cback != NULL) {
+ btm_cb.ble_ctr_cb.p_select_cback = p_select_cback;
+ }
+
+ btm_execute_wl_dev_operation();
+
+ btm_update_scanner_filter_policy(SP_ADV_WL);
+ btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_PASS;
+
+ /* Process advertising packets only from devices in the white list */
+ if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0) {
+ /* use passive scan by default */
+ if (!btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_PASS,
+ scan_int,
+ scan_win,
+ p_cb->addr_mgnt_cb.own_addr_type,
+ SP_ADV_WL)) {
+ return FALSE;
+ }
+ } else {
+ if (!btm_ble_send_extended_scan_params(BTM_BLE_SCAN_MODE_PASS,
+ scan_int,
+ scan_win,
+ p_cb->addr_mgnt_cb.own_addr_type,
+ SP_ADV_WL)) {
+ return FALSE;
+ }
+ }
+
+ if (!btm_ble_topology_check(BTM_BLE_STATE_PASSIVE_SCAN)) {
+ BTM_TRACE_ERROR("peripheral device cannot initiate passive scan for a selective connection");
+ return FALSE;
+ } else if (background_connections_pending()) {
+#if BLE_PRIVACY_SPT == TRUE
+ btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
+#endif
+ if (!btsnd_hcic_ble_set_scan_enable(TRUE, TRUE)) { /* duplicate filtering enabled */
+ return FALSE;
+ }
+ /* mark up inquiry status flag */
+ p_cb->scan_activity |= BTM_LE_SELECT_CONN_ACTIVE;
+ p_cb->wl_state |= BTM_BLE_WL_SCAN;
+ }
+ } else {
+ BTM_TRACE_ERROR("scan active, can not start selective connection procedure");
+ return FALSE;
+ }
+ } else { /* disable selective connection mode */
+ p_cb->scan_activity &= ~BTM_LE_SELECT_CONN_ACTIVE;
+ p_cb->p_select_cback = NULL;
+ p_cb->wl_state &= ~BTM_BLE_WL_SCAN;
+
+ /* stop scanning */
+ if (!BTM_BLE_IS_SCAN_ACTIVE(p_cb->scan_activity)) {
+ btm_ble_stop_scan(); /* duplicate filtering enabled */
+ }
+ }
+ return TRUE;
+}
+/*******************************************************************************
+**
+** Function btm_ble_initiate_select_conn
+**
+** Description This function is to start/stop selective connection procedure.
+**
+** Parameters start: TRUE to start; FALSE to stop.
+** p_select_cback: callback function to return application
+** selection.
+**
+** Returns BOOLEAN: selective connection procedure is started.
+**
+*******************************************************************************/
+void btm_ble_initiate_select_conn(BD_ADDR bda)
+{
+ BTM_TRACE_EVENT ("btm_ble_initiate_select_conn");
+
+ /* use direct connection procedure to initiate connection */
+ if (!L2CA_ConnectFixedChnl(L2CAP_ATT_CID, bda, BLE_ADDR_UNKNOWN_TYPE, FALSE)) {
+ BTM_TRACE_ERROR("btm_ble_initiate_select_conn failed");
+ }
+}
+/*******************************************************************************
+**
+** Function btm_ble_suspend_bg_conn
+**
+** Description This function is to suspend an active background connection
+** procedure.
+**
+** Parameters none.
+**
+** Returns none.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_suspend_bg_conn(void)
+{
+ BTM_TRACE_EVENT ("%s\n", __func__);
+
+ if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_AUTO) {
+ return btm_ble_start_auto_conn(FALSE);
+ } else if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE) {
+ return btm_ble_start_select_conn(FALSE, NULL);
+ }
+
+ return FALSE;
+}
+/*******************************************************************************
+**
+** Function btm_suspend_wl_activity
+**
+** Description This function is to suspend white list related activity
+**
+** Returns none.
+**
+*******************************************************************************/
+static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state)
+{
+ if (wl_state & BTM_BLE_WL_INIT) {
+ btm_ble_start_auto_conn(FALSE);
+ }
+ if (wl_state & BTM_BLE_WL_SCAN) {
+ btm_ble_start_select_conn(FALSE, NULL);
+ }
+ if (wl_state & BTM_BLE_WL_ADV) {
+ btm_ble_stop_adv();
+ }
+
+}
+/*******************************************************************************
+**
+** Function btm_resume_wl_activity
+**
+** Description This function is to resume white list related activity
+**
+** Returns none.
+**
+*******************************************************************************/
+void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state)
+{
+ btm_ble_resume_bg_conn();
+ if (wl_state & BTM_BLE_WL_ADV) {
+ btm_ble_start_adv();
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function btm_wl_update_to_controller
+**
+** Description This function is to update white list to controller
+**
+** Returns none.
+**
+*******************************************************************************/
+static void btm_wl_update_to_controller(void)
+{
+ /* whitelist will be added in the btm_ble_resume_bg_conn(), we do not
+ support background connection now, so we nedd to use btm_execute_wl_dev_operation
+ to add whitelist directly ,if we support background connection in the future,
+ please delete btm_execute_wl_dev_operation(). */
+ btm_execute_wl_dev_operation();
+
+}
+/*******************************************************************************
+**
+** Function btm_ble_resume_bg_conn
+**
+** Description This function is to resume a background auto connection
+** procedure.
+**
+** Parameters none.
+**
+** Returns none.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_resume_bg_conn(void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ BOOLEAN ret = FALSE;
+
+ if (p_cb->bg_conn_type != BTM_BLE_CONN_NONE) {
+ if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO) {
+ ret = btm_ble_start_auto_conn(TRUE);
+ }
+
+ if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE) {
+ ret = btm_ble_start_select_conn(TRUE, btm_cb.ble_ctr_cb.p_select_cback);
+ }
+ }
+
+ return ret;
+}
+/*******************************************************************************
+**
+** Function btm_ble_get_conn_st
+**
+** Description This function get BLE connection state
+**
+** Returns connection state
+**
+*******************************************************************************/
+tBTM_BLE_CONN_ST btm_ble_get_conn_st(void)
+{
+ return btm_cb.ble_ctr_cb.conn_state;
+}
+/*******************************************************************************
+**
+** Function btm_ble_set_conn_st
+**
+** Description This function set BLE connection state
+**
+** Returns None.
+**
+*******************************************************************************/
+void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st)
+{
+ btm_cb.ble_ctr_cb.conn_state = new_st;
+
+ if (new_st == BLE_BG_CONN || new_st == BLE_DIR_CONN) {
+ btm_ble_set_topology_mask(BTM_BLE_STATE_INIT_BIT);
+ } else {
+ btm_ble_clear_topology_mask(BTM_BLE_STATE_INIT_BIT);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_enqueue_direct_conn_req
+**
+** Description This function enqueue the direct connection request
+**
+** Returns None.
+**
+*******************************************************************************/
+void btm_ble_enqueue_direct_conn_req(void *p_param)
+{
+ tBTM_BLE_CONN_REQ *p = (tBTM_BLE_CONN_REQ *)osi_malloc(sizeof(tBTM_BLE_CONN_REQ));
+
+ p->p_param = p_param;
+
+ fixed_queue_enqueue(btm_cb.ble_ctr_cb.conn_pending_q, p, FIXED_QUEUE_MAX_TIMEOUT);
+}
+/*******************************************************************************
+**
+** Function btm_send_pending_direct_conn
+**
+** Description This function send the pending direct connection request in queue
+**
+** Returns TRUE if started, FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN btm_send_pending_direct_conn(void)
+{
+ tBTM_BLE_CONN_REQ *p_req;
+ BOOLEAN rt = FALSE;
+
+ p_req = (tBTM_BLE_CONN_REQ*)fixed_queue_dequeue(btm_cb.ble_ctr_cb.conn_pending_q, 0);
+ if (p_req != NULL) {
+ rt = l2cble_init_direct_conn((tL2C_LCB *)(p_req->p_param));
+
+ osi_free((void *)p_req);
+ }
+
+ return rt;
+}
+
+#endif
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_ble_cont_energy.c b/lib/bt/host/bluedroid/stack/btm/btm_ble_cont_energy.c
new file mode 100644
index 00000000..dd23d3e9
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_ble_cont_energy.c
@@ -0,0 +1,108 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 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"
+
+#if (BLE_INCLUDED == TRUE)
+#include "stack/bt_types.h"
+#include "stack/hcimsgs.h"
+#include "stack/btu.h"
+#include "btm_int.h"
+//#include "bt_utils.h"
+#include "stack/hcidefs.h"
+#include "stack/btm_ble_api.h"
+
+tBTM_BLE_ENERGY_INFO_CB ble_energy_info_cb;
+
+/*******************************************************************************
+**
+** Function btm_ble_cont_energy_cmpl_cback
+**
+** Description Controller VSC complete callback
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_cont_energy_cmpl_cback (tBTM_VSC_CMPL *p_params)
+{
+ UINT8 *p = p_params->p_param_buf;
+ UINT16 len = p_params->param_len;
+ UINT8 status = 0;
+ UINT32 total_tx_time = 0, total_rx_time = 0, total_idle_time = 0, total_energy_used = 0;
+
+ if (len < 17) {
+ BTM_TRACE_ERROR("wrong length for btm_ble_cont_energy_cmpl_cback");
+ return;
+ }
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT32(total_tx_time, p);
+ STREAM_TO_UINT32(total_rx_time, p);
+ STREAM_TO_UINT32(total_idle_time, p);
+ STREAM_TO_UINT32(total_energy_used, p);
+
+ BTM_TRACE_DEBUG("energy_info status=%d,tx_t=%u, rx_t=%u, ener_used=%u, idle_t=%u",
+ status, total_tx_time, total_rx_time, total_energy_used, total_idle_time);
+
+ if (NULL != ble_energy_info_cb.p_ener_cback) {
+ ble_energy_info_cb.p_ener_cback(total_tx_time, total_rx_time, total_idle_time,
+ total_energy_used, status);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleGetEnergyInfo
+**
+** Description This function obtains the energy info
+**
+** Parameters p_ener_cback - Callback pointer
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleGetEnergyInfo(tBTM_BLE_ENERGY_INFO_CBACK *p_ener_cback)
+{
+ tBTM_STATUS status = BTM_ILLEGAL_VALUE;
+ tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+
+ BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+ BTM_TRACE_EVENT("BTM_BleGetEnergyInfo\n");
+
+ if (0 == cmn_ble_vsc_cb.energy_support) {
+ BTM_TRACE_ERROR("Controller does not support get energy info\n");
+ return BTM_ERR_PROCESSING;
+ }
+
+ ble_energy_info_cb.p_ener_cback = p_ener_cback;
+ if ((status = BTM_VendorSpecificCommand (HCI_BLE_ENERGY_INFO_OCF, 0, NULL,
+ btm_ble_cont_energy_cmpl_cback)) != BTM_CMD_STARTED) {
+ BTM_TRACE_ERROR("BTM_BleGetEnergyInfo status: %d", status);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ return status;
+}
+
+#endif
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_ble_gap.c b/lib/bt/host/bluedroid/stack/btm/btm_ble_gap.c
new file mode 100644
index 00000000..fb27ba0f
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_ble_gap.c
@@ -0,0 +1,4724 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2008-2014 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 functions for BLE GAP.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+//#include <stdio.h>
+#include <stddef.h>
+
+#include "stack/bt_types.h"
+//#include "bt_utils.h"
+#include "btm_int.h"
+#include "stack/btm_ble_api.h"
+#include "stack/btu.h"
+#include "device/controller.h"
+#include "stack/hcimsgs.h"
+#include "stack/gap_api.h"
+#include "hci/hci_layer.h"
+#if BLE_INCLUDED == TRUE
+#include "l2c_int.h"
+
+#include "stack/gattdefs.h"
+#include "gatt_int.h"
+
+#include "btm_ble_int.h"
+//#define LOG_TAG "bt_btm_ble"
+//#include "osi/include/log.h"
+#include "osi/osi.h"
+#include "osi/mutex.h"
+
+#define BTM_BLE_NAME_SHORT 0x01
+#define BTM_BLE_NAME_CMPL 0x02
+
+#define BTM_BLE_FILTER_TARGET_UNKNOWN 0xff
+#define BTM_BLE_POLICY_UNKNOWN 0xff
+
+#define BTM_EXT_BLE_RMT_NAME_TIMEOUT 30
+#define MIN_ADV_LENGTH 2
+#define BTM_VSC_CHIP_CAPABILITY_RSP_LEN_L_RELEASE 9
+
+#define BTM_BLE_GAP_ADV_RPT_BATCH_SIZE (10)
+
+#if BTM_DYNAMIC_MEMORY == FALSE
+static tBTM_BLE_VSC_CB cmn_ble_gap_vsc_cb;
+#else
+static tBTM_BLE_VSC_CB *cmn_ble_gap_vsc_cb_ptr;
+#define cmn_ble_gap_vsc_cb (*cmn_ble_gap_vsc_cb_ptr)
+#endif
+
+#if BLE_VND_INCLUDED == TRUE
+static tBTM_BLE_CTRL_FEATURES_CBACK *p_ctrl_le_feature_rd_cmpl_cback = NULL;
+#endif
+
+tBTM_CallbackFunc conn_param_update_cb;
+/*******************************************************************************
+** Local functions
+*******************************************************************************/
+static void btm_ble_update_adv_flag(UINT8 flag);
+static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt_type, UINT8 *p);
+UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst,
+ tBTM_BLE_ADV_DATA *p_data);
+static UINT8 btm_set_conn_mode_adv_init_addr(tBTM_BLE_INQ_CB *p_cb,
+ BD_ADDR_PTR p_peer_addr_ptr,
+ tBLE_ADDR_TYPE *p_peer_addr_type,
+ tBLE_ADDR_TYPE *p_own_addr_type);
+static void btm_ble_stop_observe(void);
+static void btm_ble_stop_discover(void);
+static void btm_adv_pkt_handler(void *arg);
+uint32_t BTM_BleUpdateOwnType(uint8_t *own_bda_type, tBTM_START_ADV_CMPL_CBACK *cb);
+
+#define BTM_BLE_INQ_RESULT 0x01
+#define BTM_BLE_OBS_RESULT 0x02
+#define BTM_BLE_SEL_CONN_RESULT 0x04
+#define BTM_BLE_DISCO_RESULT 0x08
+
+static bool is_ble50_inter = false;
+
+void btm_ble_inter_set(bool extble_inter)
+{
+ is_ble50_inter = extble_inter;
+}
+
+bool btm_ble_inter_get(void)
+{
+ return is_ble50_inter;
+}
+
+/* LE states combo bit to check */
+const UINT8 btm_le_state_combo_tbl[BTM_BLE_STATE_MAX][BTM_BLE_STATE_MAX][2] = {
+ {/* single state support */
+ {HCI_SUPP_LE_STATES_CONN_ADV_MASK, HCI_SUPP_LE_STATES_CONN_ADV_OFF}, /* conn_adv */
+ {HCI_SUPP_LE_STATES_INIT_MASK, HCI_SUPP_LE_STATES_INIT_OFF}, /* init */
+ {HCI_SUPP_LE_STATES_INIT_MASK, HCI_SUPP_LE_STATES_INIT_OFF}, /* master */
+ {HCI_SUPP_LE_STATES_SLAVE_MASK, HCI_SUPP_LE_STATES_SLAVE_OFF}, /* slave */
+ {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_OFF}, /* lo du dir adv */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_OFF}, /* hi duty dir adv */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_OFF}, /* non connectable adv */
+ {HCI_SUPP_LE_STATES_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_OFF}, /* passive scan */
+ {HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_OFF}, /* active scan */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_MASK, HCI_SUPP_LE_STATESSCAN_ADV_OFF} /* scanable adv */
+ },
+ { /* conn_adv =0 */
+ {0, 0}, /* conn_adv */
+ {HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK, HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF}, /* init: 32 */
+ {HCI_SUPP_LE_STATES_CONN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_CONN_ADV_MASTER_OFF}, /* master: 35 */
+ {HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF}, /* slave: 38,*/
+ {0, 0}, /* lo du dir adv */
+ {0, 0}, /* hi duty dir adv */
+ {0, 0}, /* non connectable adv */
+ {HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_OFF}, /* passive scan */
+ {HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_OFF}, /* active scan */
+ {0, 0} /* scanable adv */
+ },
+ { /* init */
+ {HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK, HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF}, /* conn_adv: 32 */
+ {0, 0}, /* init */
+ {HCI_SUPP_LE_STATES_INIT_MASTER_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_OFF}, /* master 28 */
+ {HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF}, /* slave 41 */
+ {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_OFF} ,/* lo du dir adv 34 */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_OFF}, /* hi duty dir adv 33 */
+ {HCI_SUPP_LE_STATES_NON_CONN_INIT_MASK, HCI_SUPP_LE_STATES_NON_CONN_INIT_OFF}, /* non connectable adv */
+ {HCI_SUPP_LE_STATES_PASS_SCAN_INIT_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_INIT_OFF}, /* passive scan */
+ {HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_OFF}, /* active scan */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_INIT_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_INIT_OFF} /* scanable adv */
+
+ },
+ { /* master */
+ {HCI_SUPP_LE_STATES_CONN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_CONN_ADV_MASTER_OFF}, /* conn_adv: 35 */
+ {HCI_SUPP_LE_STATES_INIT_MASTER_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_OFF}, /* init 28 */
+ {HCI_SUPP_LE_STATES_INIT_MASTER_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_OFF}, /* master 28 */
+ {HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK, HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF}, /* slave: 32 */
+ {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_OFF}, /* lo duty cycle adv 37 */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_OFF}, /* hi duty cycle adv 36 */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_OFF}, /* non connectable adv */
+ {HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_OFF}, /* passive scan */
+ {HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_OFF}, /* active scan */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_OFF} /* scanable adv */
+
+ },
+ { /* slave */
+ {HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF}, /* conn_adv: 38,*/
+ {HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF}, /* init 41 */
+ {HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF}, /* master 41 */
+ {HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF}, /* slave: 38,*/
+ {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_OFF}, /* lo duty cycle adv 40 */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_OFF}, /* hi duty cycle adv 39 */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_OFF}, /* non connectable adv */
+ {HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_OFF}, /* passive scan */
+ {HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_OFF}, /* active scan */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_OFF} /* scanable adv */
+
+ },
+ { /* lo duty cycle adv */
+ {0, 0}, /* conn_adv: 38,*/
+ {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_OFF} ,/* init 34 */
+ {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_OFF}, /* master 37 */
+ {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_OFF}, /* slave: 40 */
+ {0, 0}, /* lo duty cycle adv 40 */
+ {0, 0}, /* hi duty cycle adv 39 */
+ {0, 0}, /* non connectable adv */
+ {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_OFF}, /* passive scan */
+ {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_OFF}, /* active scan */
+ {0, 0} /* scanable adv */
+ },
+ { /* hi duty cycle adv */
+ {0, 0}, /* conn_adv: 38,*/
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_OFF}, /* init 33 */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_OFF}, /* master 36 */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_OFF}, /* slave: 39*/
+ {0, 0}, /* lo duty cycle adv 40 */
+ {0, 0}, /* hi duty cycle adv 39 */
+ {0, 0}, /* non connectable adv */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_OFF}, /* passive scan */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_OFF}, /* active scan */
+ {0, 0} /* scanable adv */
+ },
+ { /* non connectable adv */
+ {0, 0}, /* conn_adv: */
+ {HCI_SUPP_LE_STATES_NON_CONN_INIT_MASK, HCI_SUPP_LE_STATES_NON_CONN_INIT_OFF}, /* init */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_OFF}, /* master */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_OFF}, /* slave: */
+ {0, 0}, /* lo duty cycle adv */
+ {0, 0}, /* hi duty cycle adv */
+ {0, 0}, /* non connectable adv */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_OFF}, /* passive scan */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_OFF}, /* active scan */
+ {0, 0} /* scanable adv */
+ },
+ { /* passive scan */
+ {HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_OFF}, /* conn_adv: */
+ {HCI_SUPP_LE_STATES_PASS_SCAN_INIT_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_INIT_OFF}, /* init */
+ {HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_OFF}, /* master */
+ {HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_OFF}, /* slave: */
+ {0, 0}, /* lo duty cycle adv */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_OFF}, /* hi duty cycle adv */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_OFF}, /* non connectable adv */
+ {0, 0}, /* passive scan */
+ {0, 0}, /* active scan */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_OFF} /* scanable adv */
+ },
+ { /* active scan */
+ {HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_OFF}, /* conn_adv: */
+ {HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_OFF}, /* init */
+ {HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_OFF}, /* master */
+ {HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_OFF}, /* slave: */
+ {0, 0}, /* lo duty cycle adv */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_OFF}, /* hi duty cycle adv */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_OFF}, /* non connectable adv */
+ {0, 0}, /* TODO: passive scan */
+ {0, 0}, /* TODO: active scan */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_OFF} /* scanable adv */
+ },
+ { /* scanable adv */
+ {0, 0}, /* conn_adv: */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_INIT_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_INIT_OFF}, /* init */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_OFF}, /* master */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_OFF}, /* slave: */
+ {0, 0}, /* lo duty cycle adv */
+ {0, 0}, /* hi duty cycle adv */
+ {0, 0}, /* non connectable adv */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_OFF}, /* passive scan */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_OFF}, /* active scan */
+ {0, 0} /* scanable adv */
+ }
+
+};
+/* check LE combo state supported */
+#define BTM_LE_STATES_SUPPORTED(x, y, z) ((x)[(z)] & (y))
+
+static osi_mutex_t adv_enable_lock;
+static osi_mutex_t adv_data_lock;
+static osi_mutex_t adv_param_lock;
+static osi_mutex_t scan_enable_lock;
+static osi_mutex_t scan_param_lock;
+osi_sem_t adv_enable_sem;
+osi_sem_t adv_data_sem;
+osi_sem_t adv_param_sem;
+osi_sem_t scan_enable_sem;
+osi_sem_t scan_param_sem;
+uint8_t adv_enable_status = 0;
+uint8_t adv_data_status = 0;
+uint8_t adv_param_status = 0;
+uint8_t scan_enable_status = 0;
+uint8_t scan_param_status = 0;
+
+void btm_ble_lock_init(void)
+{
+ osi_mutex_new(&adv_enable_lock);
+ osi_mutex_new(&adv_data_lock);
+ osi_mutex_new(&adv_param_lock);
+ osi_mutex_new(&scan_enable_lock);
+ osi_mutex_new(&scan_param_lock);
+}
+
+void btm_ble_lock_free(void)
+{
+ osi_mutex_free(&adv_enable_lock);
+ osi_mutex_free(&adv_data_lock);
+ osi_mutex_free(&adv_param_lock);
+ osi_mutex_free(&scan_enable_lock);
+ osi_mutex_free(&scan_param_lock);
+}
+
+void btm_ble_sem_init(void)
+{
+ osi_sem_new(&adv_enable_sem, 1, 0);
+ osi_sem_new(&adv_data_sem, 1, 0);
+ osi_sem_new(&adv_param_sem, 1, 0);
+ osi_sem_new(&scan_enable_sem, 1, 0);
+ osi_sem_new(&scan_param_sem, 1, 0);
+}
+
+void btm_ble_sem_free(void)
+{
+ osi_sem_free(&adv_enable_sem);
+ osi_sem_free(&adv_data_sem);
+ osi_sem_free(&adv_param_sem);
+ osi_sem_free(&scan_enable_sem);
+ osi_sem_free(&scan_param_sem);
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleRegiseterConnParamCallback
+**
+** Description register connection parameters update callback func
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleRegiseterConnParamCallback(tBTM_UPDATE_CONN_PARAM_CBACK *update_conn_param_cb)
+{
+ conn_param_update_cb.update_conn_param_cb = update_conn_param_cb;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleUpdateAdvWhitelist
+**
+** Description Add or remove device from advertising white list
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN BTM_BleUpdateAdvWhitelist(BOOLEAN add_remove, BD_ADDR remote_bda, tBLE_ADDR_TYPE addr_type, tBTM_UPDATE_WHITELIST_CBACK *update_wl_cb)
+{
+ return btm_update_dev_to_white_list(add_remove, remote_bda, addr_type, update_wl_cb);
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleUpdateAdvWhitelist
+**
+** Description Add or remove device from advertising white list
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleClearWhitelist(tBTM_UPDATE_WHITELIST_CBACK *update_wl_cb)
+{
+ btm_ble_clear_white_list(update_wl_cb);
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleUpdateAdvFilterPolicy
+**
+** Description This function update the filter policy of advertiser.
+**
+** Parameter adv_policy: advertising filter policy
+**
+** Return void
+*******************************************************************************/
+void BTM_BleUpdateAdvFilterPolicy(tBTM_BLE_AFP adv_policy)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC;
+ BD_ADDR p_addr_ptr = {0};
+ UINT8 adv_mode = p_cb->adv_mode;
+
+ BTM_TRACE_EVENT ("BTM_BleUpdateAdvFilterPolicy\n");
+
+ if (!controller_get_interface()->supports_ble()) {
+ return;
+ }
+
+ if (p_cb->afp != adv_policy) {
+ p_cb->afp = adv_policy;
+
+ /* if adv active, stop and restart */
+ btm_ble_stop_adv ();
+
+ if (p_cb->connectable_mode & BTM_BLE_CONNECTABLE) {
+ p_cb->evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &init_addr_type,
+ &p_cb->adv_addr_type);
+ }
+
+ btsnd_hcic_ble_write_adv_params ((UINT16)(p_cb->adv_interval_min ? p_cb->adv_interval_min :
+ BTM_BLE_GAP_ADV_SLOW_INT),
+ (UINT16)(p_cb->adv_interval_max ? p_cb->adv_interval_max :
+ BTM_BLE_GAP_ADV_SLOW_INT),
+ p_cb->evt_type,
+ p_cb->adv_addr_type,
+ init_addr_type,
+ p_addr_ptr,
+ p_cb->adv_chnl_map,
+ p_cb->afp);
+
+ if (adv_mode == BTM_BLE_ADV_ENABLE) {
+ btm_ble_start_adv ();
+ }
+
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_send_extended_scan_params
+**
+** Description This function sends out the extended scan parameters command to the controller
+**
+** Parameters scan_type - Scan type
+** scan_int - Scan interval
+** scan_win - Scan window
+** addr_type_own - Own address type
+** scan_filter_policy - Scan filter policy
+**
+** Returns TRUE or FALSE
+**
+*******************************************************************************/
+BOOLEAN btm_ble_send_extended_scan_params(UINT8 scan_type, UINT32 scan_int,
+ UINT32 scan_win, UINT8 addr_type_own,
+ UINT8 scan_filter_policy)
+{
+ UINT8 scan_param[HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_PARAM];
+ UINT8 *pp_scan = scan_param;
+
+ memset(scan_param, 0, HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_PARAM);
+
+ UINT8_TO_STREAM(pp_scan, scan_type);
+ UINT32_TO_STREAM(pp_scan, scan_int);
+ UINT32_TO_STREAM(pp_scan, scan_win);
+ UINT8_TO_STREAM(pp_scan, addr_type_own);
+ UINT8_TO_STREAM(pp_scan, scan_filter_policy);
+
+ BTM_TRACE_DEBUG("%s, %d, %d", __func__, scan_int, scan_win);
+ if ((BTM_VendorSpecificCommand(HCI_BLE_EXTENDED_SCAN_PARAMS_OCF,
+ HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_PARAM, scan_param, NULL)) != BTM_SUCCESS) {
+ BTM_TRACE_ERROR("%s error sending extended scan parameters", __func__);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleObserve
+**
+** Description This procedure keep the device listening for advertising
+** events from a broadcast device.
+**
+** Parameters start: start or stop observe.
+** white_list: use white list in observer mode or not.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT32 duration,
+ tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb)
+{
+ tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
+ tBTM_STATUS status = BTM_WRONG_MODE;
+
+ UINT32 scan_interval = !p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval;
+ UINT32 scan_window = !p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window;
+
+ BTM_TRACE_EVENT ("%s : scan_type:%d, %d, %d\n", __func__, btm_cb.btm_inq_vars.scan_type,
+ p_inq->scan_interval, p_inq->scan_window);
+
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ if (start) {
+ /* shared inquiry database, do not allow observe if any inquiry is active */
+ if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
+ BTM_TRACE_ERROR("%s Observe Already Active", __func__);
+ return status;
+ }
+
+ btm_cb.ble_ctr_cb.p_obs_results_cb = p_results_cb;
+ btm_cb.ble_ctr_cb.p_obs_cmpl_cb = p_cmpl_cb;
+ status = BTM_CMD_STARTED;
+
+ /* scan is not started */
+ if (!BTM_BLE_IS_SCAN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
+ /* allow config of scan type */
+ p_inq->scan_type = (p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE) ?
+ BTM_BLE_SCAN_MODE_ACTI : p_inq->scan_type;
+ /* assume observe always not using white list */
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+ /* enable resolving list */
+ //btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
+#endif
+
+ if (cmn_ble_gap_vsc_cb.extended_scan_support == 0) {
+ btsnd_hcic_ble_set_scan_params(p_inq->scan_type, (UINT16)scan_interval,
+ (UINT16)scan_window,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+ BTM_BLE_DEFAULT_SFP);
+ } else {
+ btm_ble_send_extended_scan_params(p_inq->scan_type, scan_interval, scan_window,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+ BTM_BLE_DEFAULT_SFP);
+ }
+
+ status = btm_ble_start_scan();
+ }
+
+ if (status == BTM_CMD_STARTED) {
+ btm_cb.ble_ctr_cb.scan_activity |= BTM_LE_OBSERVE_ACTIVE;
+ if (duration != 0)
+ /* start observer timer */
+ {
+ btu_start_timer (&btm_cb.ble_ctr_cb.obs_timer_ent, BTU_TTYPE_BLE_OBSERVE, duration);
+ }
+ }
+ } else if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
+ status = BTM_CMD_STARTED;
+ btm_ble_stop_observe();
+ } else {
+ BTM_TRACE_ERROR("%s Observe not active\n", __func__);
+ }
+
+ return status;
+
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleScan
+**
+** Description This procedure keep the device listening for advertising
+** events from a broadcast device.
+**
+** Parameters start: start or stop scan.
+** white_list: use white list in observer mode or not.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleScan(BOOLEAN start, UINT32 duration,
+ tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb, tBTM_INQ_DIS_CB *p_discard_cb)
+{
+ tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
+ tBTM_STATUS status = BTM_WRONG_MODE;
+
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ if (start) {
+ /* shared inquiry database, do not allow scan if any inquiry is active */
+ if (BTM_BLE_IS_DISCO_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
+ BTM_TRACE_ERROR("%s scan already active", __func__);
+ return status;
+ }
+
+ btm_cb.ble_ctr_cb.p_scan_results_cb = p_results_cb;
+ btm_cb.ble_ctr_cb.p_scan_cmpl_cb = p_cmpl_cb;
+ btm_cb.ble_ctr_cb.p_obs_discard_cb = p_discard_cb;
+ status = BTM_CMD_STARTED;
+
+ /* scan is not started */
+ if (!BTM_BLE_IS_SCAN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
+ /* assume observe always not using white list */
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+ /* enable resolving list */
+ //btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
+#endif
+ // if not set scan params, set default scan params
+ if (!p_inq->scan_params_set) {
+ /* allow config of scan type */
+ p_inq->scan_type = BTM_BLE_SCAN_MODE_ACTI;
+ p_inq->scan_interval = BTM_BLE_GAP_DISC_SCAN_INT;
+ p_inq->scan_window = BTM_BLE_GAP_DISC_SCAN_WIN;
+ p_inq->sfp = BTM_BLE_DEFAULT_SFP;
+ p_inq->scan_params_set = TRUE;
+ p_inq->scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;
+ btsnd_hcic_ble_set_scan_params(p_inq->scan_type, p_inq->scan_interval,
+ p_inq->scan_window,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+ p_inq->sfp);
+ }
+ status = btm_ble_start_scan();
+ }
+
+ if (status == BTM_CMD_STARTED) {
+ btm_cb.ble_ctr_cb.scan_activity |= BTM_LE_DISCOVER_ACTIVE;
+ if (duration != 0)
+ /* start observer timer */
+ {
+ btu_start_timer (&btm_cb.ble_ctr_cb.scan_timer_ent, BTU_TTYPE_BLE_SCAN, duration);
+ }
+ }
+ } else if (BTM_BLE_IS_DISCO_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
+ status = BTM_CMD_STARTED;
+ btm_ble_stop_discover();
+ } else {
+ BTM_TRACE_ERROR("%s scan not active\n", __func__);
+ }
+
+ return status;
+
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleBroadcast
+**
+** Description This function is to start or stop broadcasting.
+**
+** Parameters start: start or stop broadcasting.
+**
+** Returns status.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleBroadcast(BOOLEAN start, tBTM_START_STOP_ADV_CMPL_CBACK *p_stop_adv_cback)
+{
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+ tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ UINT8 evt_type = p_cb->scan_rsp ? BTM_BLE_DISCOVER_EVT : BTM_BLE_NON_CONNECT_EVT;
+
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+#ifdef BTM_BLE_PC_ADV_TEST_MODE
+ if (BTM_BLE_PC_ADV_TEST_MODE) {
+ evt_type = p_cb->scan_rsp ? BTM_BLE_CONNECT_EVT : BTM_BLE_NON_CONNECT_EVT;
+ }
+#endif
+
+ if (start) {
+ /* update adv params */
+ if (!btsnd_hcic_ble_write_adv_params ((UINT16)(p_cb->adv_interval_min ? p_cb->adv_interval_min :
+ BTM_BLE_GAP_ADV_INT),
+ (UINT16)(p_cb->adv_interval_max ? p_cb->adv_interval_max :
+ BTM_BLE_GAP_ADV_INT),
+ evt_type,
+ p_addr_cb->own_addr_type,
+ p_cb->direct_bda.type,
+ p_cb->direct_bda.bda,
+ p_cb->adv_chnl_map,
+ p_cb->afp))
+
+ {
+ status = BTM_NO_RESOURCES;
+ } else {
+ p_cb->evt_type = evt_type;
+ }
+
+ status = btm_ble_start_adv ();
+ } else {
+ //save the stop adv callback to the BTM env.
+ p_cb->p_stop_adv_cb = p_stop_adv_cback;
+ status = btm_ble_stop_adv();
+#if BLE_PRIVACY_SPT == TRUE
+ btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, TRUE);
+#endif
+ }
+ return status;
+}
+
+#if BLE_VND_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function btm_vsc_brcm_features_complete
+**
+** Description Command Complete callback for HCI_BLE_VENDOR_CAP_OCF
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_vendor_capability_vsc_cmpl_cback (tBTM_VSC_CMPL *p_vcs_cplt_params)
+{
+ UINT8 status = 0xFF;
+ UINT8 *p;
+
+ BTM_TRACE_DEBUG("%s", __func__);
+
+ /* Check status of command complete event */
+ if ((p_vcs_cplt_params->opcode == HCI_BLE_VENDOR_CAP_OCF) &&
+ (p_vcs_cplt_params->param_len > 0)) {
+ p = p_vcs_cplt_params->p_param_buf;
+ STREAM_TO_UINT8(status, p);
+ }
+
+ if (status == HCI_SUCCESS) {
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.adv_inst_max, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.rpa_offloading, p);
+ STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.tot_scan_results_strg, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.max_irk_list_sz, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.filter_support, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.max_filter, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.energy_support, p);
+
+ if (p_vcs_cplt_params->param_len > BTM_VSC_CHIP_CAPABILITY_RSP_LEN_L_RELEASE) {
+ STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.version_supported, p);
+ } else {
+ btm_cb.cmn_ble_vsc_cb.version_supported = BTM_VSC_CHIP_CAPABILITY_L_VERSION;
+ }
+
+ if (btm_cb.cmn_ble_vsc_cb.version_supported >= BTM_VSC_CHIP_CAPABILITY_M_VERSION) {
+ STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.total_trackable_advertisers, p);
+ STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.extended_scan_support, p);
+ STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.debug_logging_supported, p);
+ }
+ btm_cb.cmn_ble_vsc_cb.values_read = TRUE;
+ }
+
+ BTM_TRACE_DEBUG("%s: stat=%d, irk=%d, ADV ins:%d, rpa=%d, ener=%d, ext_scan=%d",
+ __func__, status, btm_cb.cmn_ble_vsc_cb.max_irk_list_sz,
+ btm_cb.cmn_ble_vsc_cb.adv_inst_max, btm_cb.cmn_ble_vsc_cb.rpa_offloading,
+ btm_cb.cmn_ble_vsc_cb.energy_support, btm_cb.cmn_ble_vsc_cb.extended_scan_support);
+
+ if (BTM_BleMaxMultiAdvInstanceCount() > 0) {
+ btm_ble_multi_adv_init();
+ }
+
+ if (btm_cb.cmn_ble_vsc_cb.max_filter > 0) {
+ btm_ble_adv_filter_init();
+ }
+
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+ /* VS capability included and non-4.2 device */
+ if (btm_cb.cmn_ble_vsc_cb.max_irk_list_sz > 0 &&
+ controller_get_interface()->get_ble_resolving_list_max_size() == 0) {
+ btm_ble_resolving_list_init(btm_cb.cmn_ble_vsc_cb.max_irk_list_sz);
+ }
+#endif
+
+ if (btm_cb.cmn_ble_vsc_cb.tot_scan_results_strg > 0) {
+ btm_ble_batchscan_init();
+ }
+
+ if (p_ctrl_le_feature_rd_cmpl_cback != NULL) {
+ p_ctrl_le_feature_rd_cmpl_cback(status);
+ }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function BTM_BleGetVendorCapabilities
+**
+** Description This function reads local LE features
+**
+** Parameters p_cmn_vsc_cb : Locala LE capability structure
+**
+** Returns void
+**
+*******************************************************************************/
+extern void BTM_BleGetVendorCapabilities(tBTM_BLE_VSC_CB *p_cmn_vsc_cb)
+{
+ BTM_TRACE_DEBUG("BTM_BleGetVendorCapabilities");
+
+ if (NULL != p_cmn_vsc_cb) {
+ *p_cmn_vsc_cb = btm_cb.cmn_ble_vsc_cb;
+ }
+}
+
+/******************************************************************************
+**
+** Function BTM_BleReadControllerFeatures
+**
+** Description Reads BLE specific controller features
+**
+** Parameters: tBTM_BLE_CTRL_FEATURES_CBACK : Callback to notify when features are read
+**
+** Returns void
+**
+*******************************************************************************/
+extern void BTM_BleReadControllerFeatures(tBTM_BLE_CTRL_FEATURES_CBACK *p_vsc_cback)
+{
+ if (TRUE == btm_cb.cmn_ble_vsc_cb.values_read) {
+ return;
+ }
+
+#if BLE_VND_INCLUDED == TRUE
+ BTM_TRACE_DEBUG("BTM_BleReadControllerFeatures");
+
+ p_ctrl_le_feature_rd_cmpl_cback = p_vsc_cback;
+ if ( BTM_VendorSpecificCommand (HCI_BLE_VENDOR_CAP_OCF,
+ 0,
+ NULL,
+ btm_ble_vendor_capability_vsc_cmpl_cback)
+ != BTM_CMD_STARTED) {
+ BTM_TRACE_ERROR("LE Get_Vendor Capabilities Command Failed.");
+ }
+#else
+ UNUSED(p_vsc_cback);
+#endif
+ return ;
+}
+
+void BTM_VendorHciEchoCmdCallback(tBTM_VSC_CMPL *p1)
+{
+#if (!CONFIG_BT_STACK_NO_LOG)
+ if (!p1) {
+ return;
+ }
+ uint8_t *p = p1->p_param_buf;
+ uint8_t status, echo;
+ STREAM_TO_UINT8 (status, p);
+ STREAM_TO_UINT8 (echo, p);
+#endif
+ BTM_TRACE_DEBUG("%s status 0x%x echo 0x%x", __func__, status, echo);
+}
+
+/******************************************************************************
+**
+** Function BTM_VendorHciEchoCmdTest
+**
+** Description vendor common echo hci cmd test, controller will return status and echo
+**
+** Parameters: echo : echo value
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_VendorHciEchoCmdTest(uint8_t echo)
+{
+ BTM_VendorSpecificCommand (HCI_VENDOR_COMMON_ECHO_CMD_OPCODE,
+ 1,
+ &echo,
+ BTM_VendorHciEchoCmdCallback);
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleEnableMixedPrivacyMode
+**
+** Description This function is called to enabled Mixed mode if privacy 1.2
+** is applicable in controller.
+**
+** Parameters mixed_on: mixed mode to be used or not.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleEnableMixedPrivacyMode(BOOLEAN mixed_on)
+{
+
+#if BLE_PRIVACY_SPT == TRUE
+ btm_cb.ble_ctr_cb.mixed_mode = mixed_on;
+
+ /* TODO: send VSC to enabled mixed mode */
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleConfigPrivacy
+**
+** Description This function is called to enable or disable the privacy in
+** LE channel of the local device.
+**
+** Parameters privacy_mode: privacy mode on or off.
+**
+** Returns BOOLEAN privacy mode set success; otherwise failed.
+**
+*******************************************************************************/
+BOOLEAN BTM_BleConfigPrivacy(BOOLEAN privacy_mode, tBTM_SET_LOCAL_PRIVACY_CBACK *set_local_privacy_cback)
+{
+#if BLE_PRIVACY_SPT == TRUE
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ tBTM_LE_RANDOM_CB *random_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ if (random_cb){
+ random_cb->set_local_privacy_cback = set_local_privacy_cback;
+ }else{
+ BTM_TRACE_ERROR("%s,random_cb = NULL", __func__);
+ }
+
+ BTM_TRACE_EVENT ("%s\n", __func__);
+
+ /* if LE is not supported, return error */
+ if (!controller_get_interface()->supports_ble()) {
+ return FALSE;
+ }
+
+#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE && GATTS_INCLUDED == TRUE)
+ uint8_t addr_resolution = 0;
+#endif /* defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE && GATTS_INCLUDED == TRUE */
+ if (!privacy_mode) { /* if privacy disabled, always use public address */
+ p_cb->addr_mgnt_cb.exist_addr_bit &= (~BTM_BLE_GAP_ADDR_BIT_RESOLVABLE);
+ memset(p_cb->addr_mgnt_cb.resolvale_addr, 0, BD_ADDR_LEN);
+ p_cb->addr_mgnt_cb.own_addr_type = BLE_ADDR_PUBLIC;
+ p_cb->privacy_mode = BTM_PRIVACY_NONE;
+ // Disable RPA function
+ btsnd_hcic_ble_set_addr_resolution_enable(FALSE);
+ } else { /* privacy is turned on*/
+#if (CONTROLLER_RPA_LIST_ENABLE == FALSE)
+ /* always set host random address, used when privacy 1.1 or priavcy 1.2 is disabled */
+ btm_gen_resolvable_private_addr((void *)btm_gen_resolve_paddr_low);
+#endif
+
+ if (BTM_BleMaxMultiAdvInstanceCount() > 0) {
+ btm_ble_multi_adv_enb_privacy(privacy_mode);
+ }
+
+ /* 4.2 controller only allow privacy 1.2 or mixed mode, resolvable private address in controller */
+ if (controller_get_interface()->supports_ble_privacy()) {
+#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE && GATTS_INCLUDED == TRUE)
+ addr_resolution = 1;
+#endif /* defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE && GATTS_INCLUDED == TRUE */
+ /* check vendor specific capability */
+ p_cb->privacy_mode = btm_cb.ble_ctr_cb.mixed_mode ? BTM_PRIVACY_MIXED : BTM_PRIVACY_1_2;
+ } else { /* 4.1/4.0 controller */
+ p_cb->privacy_mode = BTM_PRIVACY_1_1;
+ }
+ // Enable RPA function
+ btsnd_hcic_ble_set_addr_resolution_enable(TRUE);
+ }
+
+#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE && GATTS_INCLUDED == TRUE)
+ GAP_BleAttrDBUpdate (GATT_UUID_GAP_CENTRAL_ADDR_RESOL, (tGAP_BLE_ATTR_VALUE *)&addr_resolution);
+#endif
+
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTMGetLocalResolvablePrivateAddr
+**
+** Description This function is called to get local RPA address
+**
+** Parameters bda: address pointer.
+**
+**
+*******************************************************************************/
+
+BOOLEAN BTM_GetLocalResolvablePrivateAddr(BD_ADDR bda)
+{
+ tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ BTM_TRACE_DEBUG ("get owm resolvable random address");
+
+ if (bda) {
+ /* if privacy disabled, return false */
+ if ((p_cb->exist_addr_bit & BTM_BLE_GAP_ADDR_BIT_RESOLVABLE) == BTM_BLE_GAP_ADDR_BIT_RESOLVABLE) {
+ memcpy(bda, p_cb->resolvale_addr, BD_ADDR_LEN);
+ BTM_TRACE_DEBUG("own resolvable random address: 0x%02x:%02x:%02x:%02x:%02x:%02x",
+ p_cb->resolvale_addr[0], p_cb->resolvale_addr[1],
+ p_cb->resolvale_addr[2], p_cb->resolvale_addr[3],
+ p_cb->resolvale_addr[4], p_cb->resolvale_addr[5]);
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function BTM_UpdateAddrInfor
+**
+** Description This function is called to update address information
+**
+** Parameters addr_type: address type
+** bda: address pointer.
+**
+**
+*******************************************************************************/
+void BTM_UpdateAddrInfor(uint8_t addr_type, BD_ADDR bda)
+{
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type = addr_type;
+ memcpy(btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr, bda, BD_ADDR_LEN);
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleSetStaticAddr
+**
+** Description This function is called to save random address
+**
+** Parameters rand_addr: address pointer.
+**
+**
+*******************************************************************************/
+void BTM_BleSetStaticAddr(BD_ADDR rand_addr)
+{
+ memcpy(btm_cb.ble_ctr_cb.addr_mgnt_cb.static_rand_addr, rand_addr, BD_ADDR_LEN);
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.exist_addr_bit |= BTM_BLE_GAP_ADDR_BIT_RANDOM;
+}
+
+#if (CONTROLLER_RPA_LIST_ENABLE == FALSE)
+uint32_t BTM_BleUpdateOwnType(uint8_t *own_bda_type, tBTM_START_ADV_CMPL_CBACK *cb)
+{
+ if(*own_bda_type == BLE_ADDR_RANDOM) {
+ if((btm_cb.ble_ctr_cb.addr_mgnt_cb.exist_addr_bit & BTM_BLE_GAP_ADDR_BIT_RANDOM) == BTM_BLE_GAP_ADDR_BIT_RANDOM) {
+ //close privacy
+ #if BLE_PRIVACY_SPT == TRUE
+ if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) {
+ BTM_BleConfigPrivacy(FALSE, NULL);
+ }
+ #endif
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type = BLE_ADDR_RANDOM;
+ memcpy(btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.static_rand_addr, BD_ADDR_LEN);
+ // set address to controller
+ btsnd_hcic_ble_set_random_addr(btm_cb.ble_ctr_cb.addr_mgnt_cb.static_rand_addr);
+
+ } else if((btm_cb.ble_ctr_cb.addr_mgnt_cb.exist_addr_bit & BTM_BLE_GAP_ADDR_BIT_RESOLVABLE) == BTM_BLE_GAP_ADDR_BIT_RESOLVABLE) {
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type = BLE_ADDR_RANDOM;
+ memcpy(btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.resolvale_addr, BD_ADDR_LEN);
+ btsnd_hcic_ble_set_random_addr(btm_cb.ble_ctr_cb.addr_mgnt_cb.resolvale_addr);
+ }else {
+ BTM_TRACE_ERROR ("No random address yet, please set random address using API \"esp_ble_gap_set_rand_addr\" and retry\n");
+ if(cb) {
+ (* cb)(HCI_ERR_ESP_VENDOR_FAIL);
+ }
+ return BTM_ILLEGAL_VALUE;
+ }
+ } else if(*own_bda_type == BLE_ADDR_PUBLIC_ID || *own_bda_type == BLE_ADDR_RANDOM_ID) {
+ if((btm_cb.ble_ctr_cb.addr_mgnt_cb.exist_addr_bit & BTM_BLE_GAP_ADDR_BIT_RESOLVABLE) == BTM_BLE_GAP_ADDR_BIT_RESOLVABLE) {
+ *own_bda_type = BLE_ADDR_RANDOM;
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type = BLE_ADDR_RANDOM;
+ memcpy(btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.resolvale_addr, BD_ADDR_LEN);
+ btsnd_hcic_ble_set_random_addr(btm_cb.ble_ctr_cb.addr_mgnt_cb.resolvale_addr);
+ } else {
+ #if BLE_PRIVACY_SPT == TRUE
+ if(btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) {
+ BTM_TRACE_ERROR ("Error state\n");
+ if(cb) {
+ (* cb)(HCI_ERR_ESP_VENDOR_FAIL);
+ }
+ return BTM_ILLEGAL_VALUE;
+ }
+ #endif
+ if(*own_bda_type == BLE_ADDR_PUBLIC_ID) {
+ *own_bda_type = BLE_ADDR_PUBLIC;
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type = BLE_ADDR_PUBLIC;
+ } else { //own_bda_type == BLE_ADDR_RANDOM_ID
+ if((btm_cb.ble_ctr_cb.addr_mgnt_cb.exist_addr_bit & BTM_BLE_GAP_ADDR_BIT_RANDOM) == BTM_BLE_GAP_ADDR_BIT_RANDOM) {
+ *own_bda_type = BLE_ADDR_RANDOM;
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type = BLE_ADDR_RANDOM;
+ memcpy(btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.static_rand_addr, BD_ADDR_LEN);
+ btsnd_hcic_ble_set_random_addr(btm_cb.ble_ctr_cb.addr_mgnt_cb.static_rand_addr);
+ } else {
+ BTM_TRACE_ERROR ("No RPA and no random address yet, please set RPA or random address and try\n");
+ if(cb) {
+ (* cb)(HCI_ERR_ESP_VENDOR_FAIL);
+ }
+ return BTM_ILLEGAL_VALUE;
+ }
+ }
+ }
+ } else {
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type = BLE_ADDR_PUBLIC;
+ }
+
+ return BTM_SUCCESS;
+}
+#else
+uint32_t BTM_BleUpdateOwnType(uint8_t *own_bda_type, tBTM_START_ADV_CMPL_CBACK *cb)
+{
+ tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+
+ if((*own_bda_type == BLE_ADDR_RANDOM) || (*own_bda_type == BLE_ADDR_RANDOM_ID)) {
+ if((p_cb->exist_addr_bit & BTM_BLE_GAP_ADDR_BIT_RANDOM) != BTM_BLE_GAP_ADDR_BIT_RANDOM) {
+ BTM_TRACE_ERROR("No random address yet, please set random address and try\n");
+ if(cb) {
+ (* cb)(HCI_ERR_ESP_VENDOR_FAIL);
+ }
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ // If a device is using RPA, it shall also have an Identity Address
+ if ((*own_bda_type == BLE_ADDR_RANDOM_ID) && BTM_BLE_IS_NON_RESLVE_BDA(p_cb->static_rand_addr)) {
+ BTM_TRACE_ERROR("No identity address yet, please set static random address and try\n");
+ if (cb) {
+ (* cb)(HCI_ERR_ESP_VENDOR_FAIL);
+ }
+ return BTM_ILLEGAL_VALUE;
+ }
+ }
+
+ p_cb->own_addr_type = *own_bda_type;
+
+ return BTM_SUCCESS;
+}
+#endif
+
+
+/*******************************************************************************
+**
+** Function BTM_BleConfigLocalIcon
+**
+** Description This function is called to set local icon
+**
+** Parameters icon: appearance value.
+**
+**
+*******************************************************************************/
+void BTM_BleConfigLocalIcon(uint16_t icon)
+{
+#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE && GATTS_INCLUDED == TRUE)
+ tGAP_BLE_ATTR_VALUE p_value;
+ p_value.icon = icon;
+ GAP_BleAttrDBUpdate(GATT_UUID_GAP_ICON, &p_value);
+#else
+ BTM_TRACE_ERROR("%s\n", __func__);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleConfigConnParams
+**
+** Description This function is called to set the connection parameters
+**
+** Parameters int_min: minimum connection interval
+** int_max: maximum connection interval
+** latency: slave latency
+** timeout: supervision timeout
+**
+*******************************************************************************/
+void BTM_BleConfigConnParams(uint16_t int_min, uint16_t int_max, uint16_t latency, uint16_t timeout)
+{
+#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE && GATTS_INCLUDED == TRUE)
+ tGAP_BLE_ATTR_VALUE p_value;
+
+ p_value.conn_param.int_min = int_min;
+ p_value.conn_param.int_max = int_max;
+ p_value.conn_param.latency = latency;
+ p_value.conn_param.sp_tout = timeout;
+ GAP_BleAttrDBUpdate(GATT_UUID_GAP_PREF_CONN_PARAM, &p_value);
+#else
+ BTM_TRACE_ERROR("%s\n", __func__);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleMaxMultiAdvInstanceCount
+**
+** Description Returns max number of multi adv instances supported by controller
+**
+** Returns Max multi adv instance count
+**
+*******************************************************************************/
+extern UINT8 BTM_BleMaxMultiAdvInstanceCount(void)
+{
+ return btm_cb.cmn_ble_vsc_cb.adv_inst_max < BTM_BLE_MULTI_ADV_MAX ?
+ btm_cb.cmn_ble_vsc_cb.adv_inst_max : BTM_BLE_MULTI_ADV_MAX;
+}
+
+#if BLE_PRIVACY_SPT == TRUE
+/*******************************************************************************
+**
+** Function btm_ble_resolve_random_addr_on_adv
+**
+** Description resolve random address complete callback.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_resolve_random_addr_on_adv(void *p_rec, void *p)
+{
+ tBTM_SEC_DEV_REC *match_rec = (tBTM_SEC_DEV_REC *) p_rec;
+ UINT8 addr_type = BLE_ADDR_RANDOM;
+ BD_ADDR bda;
+ UINT8 *pp = (UINT8 *)p + 1;
+ UINT8 evt_type;
+
+ BTM_TRACE_EVENT ("btm_ble_resolve_random_addr_on_adv ");
+
+ STREAM_TO_UINT8 (evt_type, pp);
+ STREAM_TO_UINT8 (addr_type, pp);
+ STREAM_TO_BDADDR (bda, pp);
+
+ if (match_rec) {
+ BTM_TRACE_DEBUG("Random match");
+ match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA;
+ memcpy(match_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN);
+
+ if (btm_ble_init_pseudo_addr(match_rec, bda)) {
+ memcpy(bda, match_rec->bd_addr, BD_ADDR_LEN);
+ } else {
+ // Assign the original address to be the current report address
+ memcpy(bda, match_rec->ble.pseudo_addr, BD_ADDR_LEN);
+ }
+ }
+
+ btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, pp);
+
+ return;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function BTM_BleLocalPrivacyEnabled
+**
+** Description Checks if local device supports private address
+**
+** Returns Return TRUE if local privacy is enabled else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_BleLocalPrivacyEnabled(void)
+{
+#if BLE_PRIVACY_SPT == TRUE
+ return (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE);
+#else
+ return false;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleSetBgConnType
+**
+** Description This function is called to set BLE connectable mode for a
+** peripheral device.
+**
+** Parameters bg_conn_type: it can be auto connection, or selective connection.
+** p_select_cback: callback function when selective connection procedure
+** is being used.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN BTM_BleSetBgConnType(tBTM_BLE_CONN_TYPE bg_conn_type,
+ tBTM_BLE_SEL_CBACK *p_select_cback)
+{
+ BOOLEAN started = TRUE;
+
+ BTM_TRACE_EVENT ("BTM_BleSetBgConnType ");
+ if (!controller_get_interface()->supports_ble()) {
+ return FALSE;
+ }
+
+ if (btm_cb.ble_ctr_cb.bg_conn_type != bg_conn_type) {
+ switch (bg_conn_type) {
+ case BTM_BLE_CONN_AUTO:
+ btm_ble_start_auto_conn(TRUE);
+ break;
+
+ case BTM_BLE_CONN_SELECTIVE:
+ if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_AUTO) {
+ btm_ble_start_auto_conn(FALSE);
+ }
+ btm_ble_start_select_conn(TRUE, p_select_cback);
+ break;
+
+ case BTM_BLE_CONN_NONE:
+ if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_AUTO) {
+ btm_ble_start_auto_conn(FALSE);
+ } else if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE) {
+ btm_ble_start_select_conn(FALSE, NULL);
+ }
+ started = TRUE;
+ break;
+
+ default:
+ BTM_TRACE_ERROR("invalid bg connection type : %d ", bg_conn_type);
+ started = FALSE;
+ break;
+ }
+
+ if (started) {
+ btm_cb.ble_ctr_cb.bg_conn_type = bg_conn_type;
+ }
+ }
+ return started;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleClearBgConnDev
+**
+** Description This function is called to clear the whitelist,
+** end any pending whitelist connections,
+* and reset the local bg device list.
+**
+** Parameters void
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleClearBgConnDev(void)
+{
+ btm_ble_start_auto_conn(FALSE);
+ btm_ble_clear_white_list(NULL);
+ gatt_reset_bgdev_list();
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleUpdateBgConnDev
+**
+** Description This function is called to add or remove a device into/from
+** background connection procedure. The background connection
+* procedure is decided by the background connection type, it can be
+* auto connection, or selective connection.
+**
+** Parameters add_remove: TRUE to add; FALSE to remove.
+** remote_bda: device address to add/remove.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN BTM_BleUpdateBgConnDev(BOOLEAN add_remove, BD_ADDR remote_bda)
+{
+ BTM_TRACE_EVENT("%s() add=%d", __func__, add_remove);
+ return btm_update_dev_to_white_list(add_remove, remote_bda, 0, NULL);
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleSetConnectableMode
+**
+** Description This function is called to set BLE connectable mode for a
+** peripheral device.
+**
+** Parameters conn_mode: directed connectable mode, or non-directed.It can
+** be BTM_BLE_CONNECT_EVT, BTM_BLE_CONNECT_DIR_EVT or
+** BTM_BLE_CONNECT_LO_DUTY_DIR_EVT
+**
+** Returns BTM_ILLEGAL_VALUE if controller does not support BLE.
+** BTM_SUCCESS is status set successfully; otherwise failure.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleSetConnectableMode(tBTM_BLE_CONN_MODE connectable_mode)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ BTM_TRACE_EVENT ("%s connectable_mode = %d ", __func__, connectable_mode);
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ p_cb->directed_conn = connectable_mode;
+ return btm_ble_set_connectability( p_cb->connectable_mode);
+}
+
+/*******************************************************************************
+**
+** Function btm_set_conn_mode_adv_init_addr
+**
+** Description set initator address type and local address type based on adv
+** mode.
+**
+**
+*******************************************************************************/
+static UINT8 btm_set_conn_mode_adv_init_addr(tBTM_BLE_INQ_CB *p_cb,
+ BD_ADDR_PTR p_peer_addr_ptr,
+ tBLE_ADDR_TYPE *p_peer_addr_type,
+ tBLE_ADDR_TYPE *p_own_addr_type)
+{
+ UINT8 evt_type;
+#if BLE_PRIVACY_SPT == TRUE
+ UINT8 i = BTM_SEC_MAX_DEVICE_RECORDS;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ list_node_t *p_node = NULL;
+#endif ///BLE_PRIVACY_SPT == TRUE
+ evt_type = (p_cb->connectable_mode == BTM_BLE_NON_CONNECTABLE) ? \
+ ((p_cb->scan_rsp) ? BTM_BLE_DISCOVER_EVT : BTM_BLE_NON_CONNECT_EVT )\
+ : BTM_BLE_CONNECT_EVT;
+
+ if (evt_type == BTM_BLE_CONNECT_EVT) {
+ evt_type = p_cb->directed_conn;
+
+ if ( p_cb->directed_conn == BTM_BLE_CONNECT_DIR_EVT ||
+ p_cb->directed_conn == BTM_BLE_CONNECT_LO_DUTY_DIR_EVT) {
+
+#if BLE_PRIVACY_SPT == TRUE
+ /* for privacy 1.2, convert peer address as static, own address set as ID addr */
+ if (btm_cb.ble_ctr_cb.privacy_mode == BTM_PRIVACY_1_2 ||
+ btm_cb.ble_ctr_cb.privacy_mode == BTM_PRIVACY_MIXED) {
+ /* only do so for bonded device */
+ if ((p_dev_rec = btm_find_or_alloc_dev (p_cb->direct_bda.bda)) != NULL &&
+ p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) {
+ //btm_ble_enable_resolving_list(BTM_BLE_RL_ADV);
+ memcpy(p_peer_addr_ptr, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
+ *p_peer_addr_type = p_dev_rec->ble.static_addr_type;
+ *p_own_addr_type = BLE_ADDR_RANDOM_ID;
+ return evt_type;
+ }
+ /* otherwise fall though as normal directed adv */
+ else {
+ btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, TRUE);
+ }
+ }
+#endif
+ /* direct adv mode does not have privacy, if privacy is not enabled */
+ *p_peer_addr_type = p_cb->direct_bda.type;
+ memcpy(p_peer_addr_ptr, p_cb->direct_bda.bda, BD_ADDR_LEN);
+ return evt_type;
+ }
+ }
+
+ /* undirect adv mode or non-connectable mode*/
+#if BLE_PRIVACY_SPT == TRUE
+ /* when privacy 1.2 privacy only mode is used, or mixed mode */
+ if ((btm_cb.ble_ctr_cb.privacy_mode == BTM_PRIVACY_1_2 && p_cb->afp != AP_SCAN_CONN_ALL) ||
+ btm_cb.ble_ctr_cb.privacy_mode == BTM_PRIVACY_MIXED) {
+ /* if enhanced privacy is required, set Identity address and matching IRK peer */
+ for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
+ p_dev_rec = list_node(p_node);
+ if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE) != 0 &&
+ (p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) != 0) {
+ memcpy(p_peer_addr_ptr, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
+ *p_peer_addr_type = p_dev_rec->ble.static_addr_type;
+ break;
+ }
+ }
+
+ if (i != BTM_SEC_MAX_DEVICE_RECORDS) {
+ *p_own_addr_type = BLE_ADDR_RANDOM_ID;
+ } else
+ /* resolving list is empty, not enabled */
+ {
+ *p_own_addr_type = BLE_ADDR_RANDOM;
+ }
+ }
+ /* privacy 1.1, or privacy 1.2, general discoverable/connectable mode, disable privacy in */
+ /* controller fall back to host based privacy */
+ else if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) {
+ *p_own_addr_type = BLE_ADDR_RANDOM;
+ }
+#endif
+
+ /* if no privacy,do not set any peer address,*/
+ /* local address type go by global privacy setting */
+ return evt_type;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleSetAdvParams
+**
+** Description This function is called to set advertising parameters.
+**
+** Parameters adv_int_min: minimum advertising interval
+** adv_int_max: maximum advertising interval
+** p_dir_bda: connectable direct initiator's LE device address
+** chnl_map: advertising channel map.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleSetAdvParams(UINT16 adv_int_min, UINT16 adv_int_max,
+ tBLE_BD_ADDR *p_dir_bda,
+ tBTM_BLE_ADV_CHNL_MAP chnl_map)
+{
+ tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ tBTM_STATUS status = BTM_SUCCESS;
+ BD_ADDR p_addr_ptr = {0};
+ tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC;
+ tBLE_ADDR_TYPE own_addr_type = p_addr_cb->own_addr_type;
+ UINT8 adv_mode = p_cb->adv_mode;
+
+ BTM_TRACE_EVENT ("BTM_BleSetAdvParams");
+
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ if (!BTM_BLE_ISVALID_PARAM(adv_int_min, BTM_BLE_ADV_INT_MIN, BTM_BLE_ADV_INT_MAX) ||
+ !BTM_BLE_ISVALID_PARAM(adv_int_max, BTM_BLE_ADV_INT_MIN, BTM_BLE_ADV_INT_MAX)) {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ p_cb->adv_interval_min = adv_int_min;
+ p_cb->adv_interval_max = adv_int_max;
+ p_cb->adv_chnl_map = chnl_map;
+
+ if (p_dir_bda) {
+ memcpy(&p_cb->direct_bda, p_dir_bda, sizeof(tBLE_BD_ADDR));
+ }
+
+ BTM_TRACE_EVENT ("update params for an active adv\n");
+
+ btm_ble_stop_adv();
+
+ p_cb->evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &init_addr_type,
+ &own_addr_type);
+
+ /* update adv params */
+ btsnd_hcic_ble_write_adv_params (p_cb->adv_interval_min,
+ p_cb->adv_interval_max,
+ p_cb->evt_type,
+ own_addr_type,
+ init_addr_type,
+ p_addr_ptr,
+ p_cb->adv_chnl_map,
+ p_cb->afp);
+
+ if (adv_mode == BTM_BLE_ADV_ENABLE) {
+ btm_ble_start_adv();
+ }
+
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_BleSetAdvParamsAll
+**
+** Description This function is called to set all of the advertising parameters.
+**
+** Parameters: None.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleSetAdvParamsAll(UINT16 adv_int_min, UINT16 adv_int_max, UINT8 adv_type,
+ tBLE_ADDR_TYPE own_bda_type, tBLE_BD_ADDR *p_dir_bda,
+ tBTM_BLE_ADV_CHNL_MAP chnl_map, tBTM_BLE_AFP afp, tBTM_START_ADV_CMPL_CBACK *adv_cb)
+{
+ tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ BTM_TRACE_EVENT ("BTM_BleSetAdvParamsAll\n");
+
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ILLEGAL_VALUE;
+ }
+ if (BTM_BleUpdateOwnType(&own_bda_type, adv_cb) != 0) {
+ return BTM_ILLEGAL_VALUE;
+ }
+ if (!BTM_BLE_ISVALID_PARAM(adv_int_min, BTM_BLE_ADV_INT_MIN, BTM_BLE_ADV_INT_MAX) ||
+ !BTM_BLE_ISVALID_PARAM(adv_int_max, BTM_BLE_ADV_INT_MIN, BTM_BLE_ADV_INT_MAX)) {
+ BTM_TRACE_ERROR ("adv_int_min or adv_int_max is invalid\n");
+ if(adv_cb) {
+ (* adv_cb)(HCI_ERR_ESP_VENDOR_FAIL);
+ }
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ btm_ble_stop_adv();
+
+ osi_mutex_lock(&adv_param_lock, OSI_MUTEX_MAX_TIMEOUT);
+ if(adv_type == BTM_BLE_CONNECT_DIR_EVT){
+ btm_ble_set_topology_mask(BTM_BLE_STATE_HI_DUTY_DIR_ADV_BIT);
+ }else if(adv_type == BTM_BLE_CONNECT_LO_DUTY_DIR_EVT){
+ btm_ble_set_topology_mask(BTM_BLE_STATE_LO_DUTY_DIR_ADV_BIT);
+ }else if(adv_type == BTM_BLE_NON_CONNECT_EVT){
+ btm_ble_set_topology_mask(BTM_BLE_STATE_NON_CONN_ADV_BIT);
+ }
+
+ p_cb->adv_interval_min = adv_int_min;
+ p_cb->adv_interval_max = adv_int_max;
+ p_cb->adv_chnl_map = chnl_map;
+ p_addr_cb->own_addr_type = own_bda_type;
+ p_cb->evt_type = adv_type;
+ p_cb->afp = afp;
+ p_cb->p_adv_cb = adv_cb;
+
+ if (p_dir_bda) {
+ memcpy(&p_cb->direct_bda, p_dir_bda, sizeof(tBLE_BD_ADDR));
+ } else {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ BTM_TRACE_EVENT ("update params for an active adv\n");
+
+ tBTM_STATUS status = BTM_SUCCESS;
+ /* update adv params */
+ if (btsnd_hcic_ble_write_adv_params (adv_int_min,
+ adv_int_max,
+ adv_type,
+ own_bda_type,
+ p_dir_bda->type,
+ p_dir_bda->bda,
+ chnl_map,
+ p_cb->afp)) {
+ osi_sem_take(&adv_param_sem, OSI_SEM_MAX_TIMEOUT);
+ status = adv_param_status;
+ } else {
+ status = BTM_NO_RESOURCES;
+ }
+ osi_mutex_unlock(&adv_param_lock);
+ return status;
+}
+
+tBTM_STATUS BTM_BleStartAdv(void)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ btm_ble_stop_adv();
+
+ status = btm_ble_start_adv();
+
+ return status;
+}
+/*******************************************************************************
+**
+** Function BTM_BleReadAdvParams
+**
+** Description This function is called to set advertising parameters.
+**
+** Parameters adv_int_min: minimum advertising interval
+** adv_int_max: maximum advertising interval
+** p_dir_bda: connectable direct initiator's LE device address
+** chnl_map: advertising channel map.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleReadAdvParams (UINT16 *adv_int_min, UINT16 *adv_int_max,
+ tBLE_BD_ADDR *p_dir_bda, tBTM_BLE_ADV_CHNL_MAP *p_chnl_map)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ BTM_TRACE_EVENT ("BTM_BleReadAdvParams ");
+ if (!controller_get_interface()->supports_ble()) {
+ return ;
+ }
+
+ *adv_int_min = p_cb->adv_interval_min;
+ *adv_int_max = p_cb->adv_interval_max;
+ *p_chnl_map = p_cb->adv_chnl_map;
+
+ if (p_dir_bda != NULL) {
+ memcpy(p_dir_bda, &p_cb->direct_bda, sizeof(tBLE_BD_ADDR));
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleSetScanParams
+**
+** Description This function is called to set scan parameters.
+**
+** Parameters client_if - Client IF
+** scan_interval - Scan interval
+** scan_window - Scan window
+** scan_mode - Scan mode
+** scan_setup_status_cback - Scan param setup status callback
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleSetScanParams(tGATT_IF client_if, UINT32 scan_interval, UINT32 scan_window,
+ tBLE_SCAN_MODE scan_mode,
+ tBLE_SCAN_PARAM_SETUP_CBACK scan_setup_status_cback)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ UINT32 max_scan_interval;
+ UINT32 max_scan_window;
+
+ BTM_TRACE_EVENT ("%s\n", __func__);
+ if (!controller_get_interface()->supports_ble()) {
+ return;
+ }
+
+ /* If not supporting extended scan support, use the older range for checking */
+ if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0) {
+ max_scan_interval = BTM_BLE_SCAN_INT_MAX;
+ max_scan_window = BTM_BLE_SCAN_WIN_MAX;
+ } else {
+ /* If supporting extended scan support, use the new extended range for checking */
+ max_scan_interval = BTM_BLE_EXT_SCAN_INT_MAX;
+ max_scan_window = BTM_BLE_EXT_SCAN_WIN_MAX;
+ }
+
+ if (BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN, max_scan_interval) &&
+ BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN, max_scan_window) &&
+ (scan_mode == BTM_BLE_SCAN_MODE_ACTI || scan_mode == BTM_BLE_SCAN_MODE_PASS)) {
+ p_cb->scan_type = scan_mode;
+ p_cb->scan_interval = scan_interval;
+ p_cb->scan_window = scan_window;
+
+ if (scan_setup_status_cback != NULL) {
+ scan_setup_status_cback(client_if, BTM_SUCCESS);
+ }
+ } else {
+ if (scan_setup_status_cback != NULL) {
+ scan_setup_status_cback(client_if, BTM_ILLEGAL_VALUE);
+ }
+
+ BTM_TRACE_ERROR("Illegal params: scan_interval = %d scan_window = %d\n",
+ scan_interval, scan_window);
+ }
+
+}
+
+tBTM_STATUS BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32 scan_window,
+ tBLE_SCAN_MODE scan_mode, UINT8 addr_type_own, UINT8 scan_duplicate_filter, tBTM_BLE_SFP scan_filter_policy,
+ tBLE_SCAN_PARAM_SETUP_CBACK scan_setup_status_cback)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ UINT32 max_scan_interval;
+ UINT32 max_scan_window;
+ tBTM_STATUS ret = BTM_SUCCESS;
+
+ BTM_TRACE_EVENT ("%s\n", __func__);
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ILLEGAL_VALUE;
+ }
+ if (BTM_BleUpdateOwnType(&addr_type_own, NULL) != 0) {
+ return BTM_ILLEGAL_VALUE;
+ }
+ /* If not supporting extended scan support, use the older range for checking */
+ if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0) {
+ max_scan_interval = BTM_BLE_SCAN_INT_MAX;
+ max_scan_window = BTM_BLE_SCAN_WIN_MAX;
+ } else {
+ /* If supporting extended scan support, use the new extended range for checking */
+ max_scan_interval = BTM_BLE_EXT_SCAN_INT_MAX;
+ max_scan_window = BTM_BLE_EXT_SCAN_WIN_MAX;
+ }
+
+ osi_mutex_lock(&scan_param_lock, OSI_MUTEX_MAX_TIMEOUT);
+
+ if (BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN, max_scan_interval) &&
+ BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN, max_scan_window) &&
+ (scan_mode == BTM_BLE_SCAN_MODE_ACTI || scan_mode == BTM_BLE_SCAN_MODE_PASS) &&
+ (scan_duplicate_filter < BTM_BLE_SCAN_DUPLICATE_MAX) && (scan_window <= scan_interval)) {
+ p_cb->scan_type = scan_mode;
+ p_cb->scan_interval = scan_interval;
+ p_cb->scan_window = scan_window;
+ p_cb->sfp = scan_filter_policy;
+ p_cb->scan_params_set = TRUE;
+ p_cb->scan_duplicate_filter = scan_duplicate_filter;
+
+
+ if (btsnd_hcic_ble_set_scan_params(p_cb->scan_type, (UINT16)scan_interval,
+ (UINT16)scan_window,
+ addr_type_own,
+ scan_filter_policy)) {
+ osi_sem_take(&scan_param_sem, OSI_SEM_MAX_TIMEOUT);
+ ret = scan_param_status;
+ }
+ } else {
+ ret = BTM_ILLEGAL_VALUE;
+ BTM_TRACE_ERROR("Illegal params: scan_interval = %d scan_window = %d\n",
+ scan_interval, scan_window);
+ }
+ osi_mutex_unlock(&scan_param_lock);
+ return ret;
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_BleWriteScanRsp
+**
+** Description This function is called to write LE scan response.
+**
+** Parameters: p_scan_rsp: scan response information.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleWriteScanRsp(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p_data)
+{
+ tBTM_STATUS ret;
+ UINT8 rsp_data[BTM_BLE_AD_DATA_LEN],
+ *p = rsp_data;
+
+ BTM_TRACE_EVENT (" BTM_BleWriteScanRsp");
+
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ osi_mutex_lock(&adv_data_lock, OSI_MUTEX_MAX_TIMEOUT);
+ memset(rsp_data, 0, BTM_BLE_AD_DATA_LEN);
+ btm_ble_build_adv_data(&data_mask, &p, p_data);
+ if (data_mask != 0) {
+ //data length should not exceed 31 bytes
+ BTM_TRACE_WARNING("%s, Partial data write into ADV", __func__);
+ }
+
+ if (btsnd_hcic_ble_set_scan_rsp_data((UINT8)(p - rsp_data), rsp_data)) {
+ osi_sem_take(&adv_data_sem, OSI_SEM_MAX_TIMEOUT);
+ ret = adv_data_status;
+
+ if (adv_data_status == BTM_SUCCESS && data_mask != 0) {
+ btm_cb.ble_ctr_cb.inq_var.scan_rsp = TRUE;
+ } else {
+ btm_cb.ble_ctr_cb.inq_var.scan_rsp = FALSE;
+ }
+ } else {
+ ret = BTM_ILLEGAL_VALUE;
+ }
+
+ osi_mutex_unlock(&adv_data_lock);
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleWriteScanRspRaw
+**
+** Description This function is called to write raw scan response data
+**
+** Parameters: None.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleWriteScanRspRaw(UINT8 *p_raw_scan_rsp, UINT32 raw_scan_rsp_len)
+{
+ tBTM_STATUS ret;
+
+ osi_mutex_lock(&adv_data_lock, OSI_MUTEX_MAX_TIMEOUT);
+ if (btsnd_hcic_ble_set_scan_rsp_data((UINT8)raw_scan_rsp_len, p_raw_scan_rsp)) {
+ osi_sem_take(&adv_data_sem, OSI_SEM_MAX_TIMEOUT);
+ ret = adv_data_status;
+ } else {
+ ret = BTM_NO_RESOURCES;
+ }
+ osi_mutex_unlock(&adv_data_lock);
+
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function BTM_UpdateBleDuplicateExceptionalList
+**
+** Description This function is called to update duplicate scan exceptional list.
+**
+** Parameters: subcode: add, remove or clean duplicate scan exceptional list.
+** type: device info type
+** device_info: device information
+** update_exceptional_list_cmp_cb: complete callback
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS BTM_UpdateBleDuplicateExceptionalList(uint8_t subcode, uint32_t type, BD_ADDR device_info,
+ tBTM_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK update_exceptional_list_cmp_cb)
+{
+ tBTM_BLE_CB *ble_cb = &btm_cb.ble_ctr_cb;
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+
+ ble_cb->update_exceptional_list_cmp_cb = update_exceptional_list_cmp_cb;
+
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ILLEGAL_VALUE;
+ }
+ if(!device_info) {
+ return BTM_ILLEGAL_VALUE;
+ }
+ // subcoe + type + device info
+ uint8_t device_info_array[1 + 4 + BD_ADDR_LEN] = {0};
+ device_info_array[0] = subcode;
+ device_info_array[1] = type & 0xff;
+ device_info_array[2] = (type >> 8) & 0xff;
+ device_info_array[3] = (type >> 16) & 0xff;
+ device_info_array[4] = (type >> 24) & 0xff;
+ switch (type)
+ {
+ case BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_ADV_ADDR:
+ bt_rcopy(&device_info_array[5], device_info, BD_ADDR_LEN);
+ break;
+ case BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_LINK_ID:
+ memcpy(&device_info_array[5], device_info, 4);
+ break;
+ case BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_BEACON_TYPE:
+ //do nothing
+ break;
+ case BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_PROV_SRV_ADV:
+ //do nothing
+ break;
+ case BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_PROXY_SRV_ADV:
+ //do nothing
+ break;
+ default:
+ //do nothing
+ break;
+ }
+
+ status = BTM_VendorSpecificCommand(HCI_VENDOR_BLE_UPDATE_DUPLICATE_EXCEPTIONAL_LIST, 1 + 4 + BD_ADDR_LEN, device_info_array, NULL);
+ if(status == BTM_CMD_STARTED) {
+ status = BTM_SUCCESS;
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleWriteAdvData
+**
+** Description This function is called to write advertising data.
+**
+** Parameters: None.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleWriteAdvData(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p_data)
+{
+ tBTM_BLE_LOCAL_ADV_DATA *p_cb_data = &btm_cb.ble_ctr_cb.inq_var.adv_data;
+ UINT8 *p;
+ tBTM_BLE_AD_MASK mask = data_mask;
+ tBTM_STATUS ret;
+
+ BTM_TRACE_EVENT ("BTM_BleWriteAdvData ");
+
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ILLEGAL_VALUE;
+ }
+ osi_mutex_lock(&adv_data_lock, OSI_MUTEX_MAX_TIMEOUT);
+ memset(p_cb_data, 0, sizeof(tBTM_BLE_LOCAL_ADV_DATA));
+ p = p_cb_data->ad_data;
+ p_cb_data->data_mask = data_mask;
+
+ p_cb_data->p_flags = btm_ble_build_adv_data(&mask, &p, p_data);
+
+ p_cb_data->p_pad = p;
+
+ if (mask != 0) {
+ //data length should not exceed 31 bytes
+ BTM_TRACE_WARNING("%s, Partial data write into ADV", __func__);
+ }
+
+ p_cb_data->data_mask &= ~mask;
+
+ if (btsnd_hcic_ble_set_adv_data((UINT8)(p_cb_data->p_pad - p_cb_data->ad_data),
+ p_cb_data->ad_data)) {
+ osi_sem_take(&adv_data_sem, OSI_SEM_MAX_TIMEOUT);
+ ret = adv_data_status;
+ } else {
+ ret = BTM_NO_RESOURCES;
+ }
+ osi_mutex_unlock(&adv_data_lock);
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleWriteLongAdvData
+**
+** Description This function is called to write long advertising data.
+**
+** Parameters: adv_data: long advertising data
+** adv_data_len: the length of long advertising data
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleWriteLongAdvData(uint8_t *adv_data, uint8_t adv_data_len)
+{
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ILLEGAL_VALUE;
+ }
+ if(!adv_data || adv_data_len <= 0 || adv_data_len > BTM_BLE_LONG_ADV_MAX_LEN) {
+ return BTM_ILLEGAL_VALUE;
+ }
+ uint8_t long_adv[BTM_BLE_LONG_ADV_MAX_LEN + 1] = {0};
+ long_adv[0] = adv_data_len;
+ memcpy(&long_adv[1], adv_data, adv_data_len);
+ status = BTM_VendorSpecificCommand(HCI_VENDOR_BLE_LONG_ADV_DATA, BTM_BLE_LONG_ADV_MAX_LEN + 1, long_adv, NULL);
+ if(status == BTM_CMD_STARTED) {
+ status = BTM_SUCCESS;
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleWriteAdvDataRaw
+**
+** Description This function is called to write raw advertising data.
+**
+** Parameters: None.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleWriteAdvDataRaw(UINT8 *p_raw_adv, UINT32 raw_adv_len)
+{
+ tBTM_STATUS ret;
+ osi_mutex_lock(&adv_data_lock, OSI_MUTEX_MAX_TIMEOUT);
+ if (btsnd_hcic_ble_set_adv_data((UINT8)raw_adv_len, p_raw_adv)) {
+ osi_sem_take(&adv_data_sem, OSI_SEM_MAX_TIMEOUT);
+ ret = adv_data_status;
+ } else {
+ ret = BTM_NO_RESOURCES;
+ }
+ osi_mutex_unlock(&adv_data_lock);
+
+ return ret;
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_BleSetRandAddress
+**
+** Description This function is called to set the LE random address.
+**
+** Parameters: None.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleSetRandAddress(BD_ADDR rand_addr)
+{
+ if (rand_addr == NULL) {
+ return BTM_SET_STATIC_RAND_ADDR_FAIL;
+ }
+
+ if (btm_cb.ble_ctr_cb.inq_var.state != BTM_BLE_IDLE) {
+ BTM_TRACE_ERROR("Advertising or scaning now, can't set randaddress %d", btm_cb.ble_ctr_cb.inq_var.state);
+ return BTM_SET_STATIC_RAND_ADDR_FAIL;
+ }
+ memcpy(btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr, rand_addr, BD_ADDR_LEN);
+ memcpy(btm_cb.ble_ctr_cb.addr_mgnt_cb.static_rand_addr, rand_addr, BD_ADDR_LEN);
+ //send the set random address to the controller
+ if(btsnd_hcic_ble_set_random_addr(rand_addr)) {
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.exist_addr_bit |= BTM_BLE_GAP_ADDR_BIT_RANDOM;
+ return BTM_SUCCESS;
+ } else {
+ return BTM_SET_STATIC_RAND_ADDR_FAIL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleClearRandAddress
+**
+** Description This function is called to clear the LE random address.
+**
+** Parameters: None.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleClearRandAddress(void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ if (btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type == BLE_ADDR_RANDOM && (p_cb->inq_var.state != BTM_BLE_IDLE)) {
+ BTM_TRACE_ERROR("Advertising or scaning now, can't restore public address ");
+ return;
+ }
+ memset(btm_cb.ble_ctr_cb.addr_mgnt_cb.static_rand_addr, 0, BD_ADDR_LEN);
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.exist_addr_bit &= (~BTM_BLE_GAP_ADDR_BIT_RANDOM);
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type = BLE_ADDR_PUBLIC;
+}
+/*******************************************************************************
+**
+** Function BTM_BleGetCurrentAddress
+**
+** Description This function is called to get local used BLE address.
+**
+** Parameters: None.
+**
+** Returns success or fail
+**
+*******************************************************************************/
+BOOLEAN BTM_BleGetCurrentAddress(BD_ADDR addr, uint8_t *addr_type)
+{
+ if(addr == NULL || addr_type == NULL) {
+ BTM_TRACE_ERROR("%s addr or addr_type is NULL\n", __func__);
+ return FALSE;
+ }
+ if(btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type == BLE_ADDR_RANDOM) {
+ *addr_type = BLE_ADDR_RANDOM;
+ memcpy(addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr, BD_ADDR_LEN);
+ } else if(btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type == BLE_ADDR_PUBLIC) {
+ *addr_type = BLE_ADDR_PUBLIC;
+ memcpy(addr, &controller_get_interface()->get_address()->address, BD_ADDR_LEN);
+ } else {
+ BTM_TRACE_ERROR("%s\n", __func__);
+ memset(addr, 0, BD_ADDR_LEN);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function BTM_CheckAdvData
+**
+** Description This function is called to get ADV data for a specific type.
+**
+** Parameters p_adv - pointer of ADV data
+** type - finding ADV data type
+** p_length - return the length of ADV data not including type
+**
+** Returns pointer of ADV data
+**
+*******************************************************************************/
+UINT8 *BTM_CheckAdvData( UINT8 *p_adv, UINT8 type, UINT8 *p_length)
+{
+ UINT8 *p = p_adv;
+ UINT8 length;
+ UINT8 adv_type;
+ BTM_TRACE_API("BTM_CheckAdvData type=0x%02X", type);
+
+ STREAM_TO_UINT8(length, p);
+
+ while ( length && (p - p_adv < BTM_BLE_CACHE_ADV_DATA_MAX)) {
+ STREAM_TO_UINT8(adv_type, p);
+
+ if ( adv_type == type ) {
+ /* length doesn't include itself */
+ *p_length = length - 1; /* minus the length of type */
+ return p;
+ }
+
+ p += length - 1; /* skip the length of data */
+
+ /* Break loop if advertising data is in an incorrect format,
+ as it may lead to memory overflow */
+ if (p >= p_adv + BTM_BLE_CACHE_ADV_DATA_MAX) {
+ break;
+ }
+
+ STREAM_TO_UINT8(length, p);
+ }
+
+ *p_length = 0;
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function BTM__BLEReadDiscoverability
+**
+** Description This function is called to read the current LE discoverability
+** mode of the device.
+**
+** Returns BTM_BLE_NON_DISCOVERABLE ,BTM_BLE_LIMITED_DISCOVERABLE or
+** BTM_BLE_GENRAL_DISCOVERABLE
+**
+*******************************************************************************/
+UINT16 BTM_BleReadDiscoverability(void)
+{
+ BTM_TRACE_API("%s\n", __FUNCTION__);
+
+ return (btm_cb.ble_ctr_cb.inq_var.discoverable_mode);
+}
+
+/*******************************************************************************
+**
+** Function BTM__BLEReadConnectability
+**
+** Description This function is called to read the current LE connectibility
+** mode of the device.
+**
+** Returns BTM_BLE_NON_CONNECTABLE or BTM_BLE_CONNECTABLE
+**
+*******************************************************************************/
+UINT16 BTM_BleReadConnectability(void)
+{
+ BTM_TRACE_API ("%s\n", __FUNCTION__);
+
+ return (btm_cb.ble_ctr_cb.inq_var.connectable_mode);
+}
+
+void BTM_Recovery_Pre_State(void)
+{
+ tBTM_BLE_INQ_CB *ble_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ if (ble_inq_cb->state & BTM_BLE_ADVERTISING) {
+ btm_ble_stop_adv();
+ btm_ble_start_adv();
+ }
+ if (ble_inq_cb->state & BTM_BLE_SCANNING) {
+ btm_ble_start_scan();
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetCurrentConnParams
+**
+** Description This function is called to read the current connection parameters
+** of the device
+**
+** Returns TRUE or FALSE
+**
+*******************************************************************************/
+
+BOOLEAN BTM_GetCurrentConnParams(BD_ADDR bda, uint16_t *interval, uint16_t *latency, uint16_t *timeout)
+{
+ if( (interval == NULL) || (latency == NULL) || (timeout == NULL) ) {
+ BTM_TRACE_ERROR("%s error ", __func__);
+ return FALSE;
+ }
+
+ if(btm_get_current_conn_params(bda, interval, latency, timeout)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_build_adv_data
+**
+** Description This function is called build the adv data and rsp data.
+*******************************************************************************/
+UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst,
+ tBTM_BLE_ADV_DATA *p_data)
+{
+ UINT32 data_mask = *p_data_mask;
+ UINT8 *p = *p_dst,
+ *p_flag = NULL;
+ UINT16 len = BTM_BLE_AD_DATA_LEN, cp_len = 0;
+ UINT8 i = 0;
+ tBTM_BLE_PROP_ELEM *p_elem;
+
+ BTM_TRACE_EVENT (" btm_ble_build_adv_data");
+
+ /* build the adv data structure and build the data string */
+ if (data_mask) {
+ /* flags */
+ if (data_mask & BTM_BLE_AD_BIT_FLAGS) {
+ *p++ = MIN_ADV_LENGTH;
+ *p++ = BTM_BLE_AD_TYPE_FLAG;
+ p_flag = p;
+ if (p_data) {
+ *p++ = p_data->flag;
+ } else {
+ *p++ = 0;
+ }
+
+ len -= 3;
+
+ data_mask &= ~BTM_BLE_AD_BIT_FLAGS;
+ }
+ /* appearance data */
+ if (len > 3 && data_mask & BTM_BLE_AD_BIT_APPEARANCE) {
+ *p++ = 3; /* length */
+ *p++ = BTM_BLE_AD_TYPE_APPEARANCE;
+ UINT16_TO_STREAM(p, p_data->appearance);
+ len -= 4;
+
+ data_mask &= ~BTM_BLE_AD_BIT_APPEARANCE;
+ }
+ /* device name */
+#if BTM_MAX_LOC_BD_NAME_LEN > 0
+ if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_DEV_NAME) {
+ if (strlen(btm_cb.cfg.bd_name) > (UINT16)(len - MIN_ADV_LENGTH)) {
+ cp_len = (UINT16)(len - MIN_ADV_LENGTH);
+ *p++ = cp_len + 1;
+ *p++ = BTM_BLE_AD_TYPE_NAME_SHORT;
+ ARRAY_TO_STREAM(p, btm_cb.cfg.bd_name, cp_len);
+ } else {
+ cp_len = (UINT16)strlen(btm_cb.cfg.bd_name);
+ *p++ = cp_len + 1;
+ *p++ = BTM_BLE_AD_TYPE_NAME_CMPL;
+ ARRAY_TO_STREAM(p, btm_cb.cfg.bd_name, cp_len);
+ }
+ len -= (cp_len + MIN_ADV_LENGTH);
+ data_mask &= ~BTM_BLE_AD_BIT_DEV_NAME;
+ }
+#endif
+ /* manufacturer data */
+ if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_MANU &&
+ p_data && p_data->p_manu &&
+ p_data->p_manu->len != 0 && p_data->p_manu->p_val) {
+ if (p_data->p_manu->len > (len - MIN_ADV_LENGTH)) {
+ cp_len = len - MIN_ADV_LENGTH;
+ } else {
+ cp_len = p_data->p_manu->len;
+ }
+ BTM_TRACE_DEBUG("cp_len = %d\n,p_data->p_manu->len=%d\n", cp_len, p_data->p_manu->len);
+ for (int i = 0; i < p_data->p_manu->len; i++) {
+ BTM_TRACE_DEBUG("p_data->p_manu->p_val[%d] = %x\n", i, p_data->p_manu->p_val[i]);
+ }
+ *p++ = cp_len + 1;
+ *p++ = BTM_BLE_AD_TYPE_MANU;
+ ARRAY_TO_STREAM(p, p_data->p_manu->p_val, cp_len);
+ BTM_TRACE_DEBUG("p_addr = %p\n,p_data->p_manu->p_val = %p\n", p, p_data->p_manu->p_val);
+ len -= (cp_len + MIN_ADV_LENGTH);
+ data_mask &= ~BTM_BLE_AD_BIT_MANU;
+ }
+ /* TX power */
+ if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_TX_PWR) {
+ *p++ = MIN_ADV_LENGTH;
+ *p++ = BTM_BLE_AD_TYPE_TX_PWR;
+ if (p_data->tx_power > BTM_BLE_ADV_TX_POWER_MAX) {
+ p_data->tx_power = BTM_BLE_ADV_TX_POWER_MAX;
+ }
+ *p++ = btm_ble_map_adv_tx_power(p_data->tx_power);
+ len -= 3;
+ data_mask &= ~BTM_BLE_AD_BIT_TX_PWR;
+ }
+ /* 16 bits services */
+ if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_SERVICE &&
+ p_data && p_data->p_services &&
+ p_data->p_services->num_service != 0 &&
+ p_data->p_services->p_uuid) {
+ if (p_data->p_services->num_service * LEN_UUID_16 > (len - MIN_ADV_LENGTH)) {
+ cp_len = (len - MIN_ADV_LENGTH) / LEN_UUID_16;
+ *p ++ = 1 + cp_len * LEN_UUID_16;
+ *p++ = BTM_BLE_AD_TYPE_16SRV_PART;
+ } else {
+ cp_len = p_data->p_services->num_service;
+ *p++ = 1 + cp_len * LEN_UUID_16;
+ *p++ = BTM_BLE_AD_TYPE_16SRV_CMPL;
+ }
+ for (i = 0; i < cp_len; i ++) {
+ UINT16_TO_STREAM(p, *(p_data->p_services->p_uuid + i));
+ }
+
+ len -= (cp_len * MIN_ADV_LENGTH + MIN_ADV_LENGTH);
+ data_mask &= ~BTM_BLE_AD_BIT_SERVICE;
+ }
+ /* 32 bits service uuid */
+ if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_SERVICE_32 &&
+ p_data && p_data->p_service_32b &&
+ p_data->p_service_32b->num_service != 0 &&
+ p_data->p_service_32b->p_uuid) {
+ if ((p_data->p_service_32b->num_service * LEN_UUID_32) > (len - MIN_ADV_LENGTH)) {
+ cp_len = (len - MIN_ADV_LENGTH) / LEN_UUID_32;
+ *p ++ = 1 + cp_len * LEN_UUID_32;
+ *p++ = BTM_BLE_AD_TYPE_32SRV_PART;
+ } else {
+ cp_len = p_data->p_service_32b->num_service;
+ *p++ = 1 + cp_len * LEN_UUID_32;
+ *p++ = BTM_BLE_AD_TYPE_32SRV_CMPL;
+ }
+ for (i = 0; i < cp_len; i ++) {
+ UINT32_TO_STREAM(p, *(p_data->p_service_32b->p_uuid + i));
+ }
+
+ len -= (cp_len * LEN_UUID_32 + MIN_ADV_LENGTH);
+ data_mask &= ~BTM_BLE_AD_BIT_SERVICE_32;
+ }
+ /* 128 bits services */
+ if (len >= (MAX_UUID_SIZE + 2) && data_mask & BTM_BLE_AD_BIT_SERVICE_128 &&
+ p_data && p_data->p_services_128b) {
+ *p ++ = 1 + MAX_UUID_SIZE;
+ if (!p_data->p_services_128b->list_cmpl) {
+ *p++ = BTM_BLE_AD_TYPE_128SRV_PART;
+ } else {
+ *p++ = BTM_BLE_AD_TYPE_128SRV_CMPL;
+ }
+
+ ARRAY_TO_STREAM(p, p_data->p_services_128b->uuid128, MAX_UUID_SIZE);
+
+ len -= (MAX_UUID_SIZE + MIN_ADV_LENGTH);
+ data_mask &= ~BTM_BLE_AD_BIT_SERVICE_128;
+ }
+ /* 32 bits Service Solicitation UUIDs */
+ if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_SERVICE_32SOL &&
+ p_data && p_data->p_sol_service_32b &&
+ p_data->p_sol_service_32b->num_service != 0 &&
+ p_data->p_sol_service_32b->p_uuid) {
+ if ((p_data->p_sol_service_32b->num_service * LEN_UUID_32) > (len - MIN_ADV_LENGTH)) {
+ cp_len = (len - MIN_ADV_LENGTH) / LEN_UUID_32;
+ *p ++ = 1 + cp_len * LEN_UUID_32;
+ } else {
+ cp_len = p_data->p_sol_service_32b->num_service;
+ *p++ = 1 + cp_len * LEN_UUID_32;
+ }
+
+ *p++ = BTM_BLE_AD_TYPE_32SOL_SRV_UUID;
+ for (i = 0; i < cp_len; i ++) {
+ UINT32_TO_STREAM(p, *(p_data->p_sol_service_32b->p_uuid + i));
+ }
+
+ len -= (cp_len * LEN_UUID_32 + MIN_ADV_LENGTH);
+ data_mask &= ~BTM_BLE_AD_BIT_SERVICE_32SOL;
+ }
+ /* 128 bits Solicitation services UUID */
+ if (len >= (MAX_UUID_SIZE + MIN_ADV_LENGTH) && data_mask & BTM_BLE_AD_BIT_SERVICE_128SOL &&
+ p_data && p_data->p_sol_service_128b) {
+ *p ++ = 1 + MAX_UUID_SIZE;
+ *p++ = BTM_BLE_AD_TYPE_128SOL_SRV_UUID;
+ ARRAY_TO_STREAM(p, p_data->p_sol_service_128b->uuid128, MAX_UUID_SIZE);
+ len -= (MAX_UUID_SIZE + MIN_ADV_LENGTH);
+ data_mask &= ~BTM_BLE_AD_BIT_SERVICE_128SOL;
+ }
+ /* 16bits/32bits/128bits Service Data */
+ if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_SERVICE_DATA &&
+ p_data && p_data->p_service_data->len != 0 && p_data->p_service_data->p_val) {
+ if (len > (p_data->p_service_data->service_uuid.len + MIN_ADV_LENGTH)) {
+ if (p_data->p_service_data->len > (len - MIN_ADV_LENGTH)) {
+ cp_len = len - MIN_ADV_LENGTH - p_data->p_service_data->service_uuid.len;
+ } else {
+ cp_len = p_data->p_service_data->len;
+ }
+
+ *p++ = cp_len + 1 + p_data->p_service_data->service_uuid.len;
+ if (p_data->p_service_data->service_uuid.len == LEN_UUID_16) {
+ *p++ = BTM_BLE_AD_TYPE_SERVICE_DATA;
+ UINT16_TO_STREAM(p, p_data->p_service_data->service_uuid.uu.uuid16);
+ } else if (p_data->p_service_data->service_uuid.len == LEN_UUID_32) {
+ *p++ = BTM_BLE_AD_TYPE_32SERVICE_DATA;
+ UINT32_TO_STREAM(p, p_data->p_service_data->service_uuid.uu.uuid32);
+ } else {
+ *p++ = BTM_BLE_AD_TYPE_128SERVICE_DATA;
+ ARRAY_TO_STREAM(p, p_data->p_service_data->service_uuid.uu.uuid128,
+ LEN_UUID_128);
+ }
+
+ ARRAY_TO_STREAM(p, p_data->p_service_data->p_val, cp_len);
+
+ len -= (cp_len + MIN_ADV_LENGTH + p_data->p_service_data->service_uuid.len);
+ data_mask &= ~BTM_BLE_AD_BIT_SERVICE_DATA;
+ } else {
+ BTM_TRACE_WARNING("service data does not fit");
+ }
+ }
+
+ if (len >= 6 && data_mask & BTM_BLE_AD_BIT_INT_RANGE &&
+ p_data) {
+ *p++ = 5;
+ *p++ = BTM_BLE_AD_TYPE_INT_RANGE;
+ UINT16_TO_STREAM(p, p_data->int_range.low);
+ UINT16_TO_STREAM(p, p_data->int_range.hi);
+ len -= 6;
+ data_mask &= ~BTM_BLE_AD_BIT_INT_RANGE;
+ }
+ if (data_mask & BTM_BLE_AD_BIT_PROPRIETARY && p_data && p_data->p_proprietary) {
+ for (i = 0; i < p_data->p_proprietary->num_elem ; i ++) {
+ p_elem = p_data->p_proprietary->p_elem + i;
+
+ if (len >= (MIN_ADV_LENGTH + p_elem->len))/* len byte(1) + ATTR type(1) + Uuid len(2)
+ + value length */
+ {
+ *p ++ = p_elem->len + 1; /* Uuid len + value length */
+ *p ++ = p_elem->adv_type;
+ ARRAY_TO_STREAM(p, p_elem->p_val, p_elem->len);
+
+ len -= (MIN_ADV_LENGTH + p_elem->len);
+ } else {
+ BTM_TRACE_WARNING("data exceed max adv packet length");
+ break;
+ }
+ }
+ data_mask &= ~BTM_BLE_AD_BIT_PROPRIETARY;
+ }
+ }
+
+ *p_data_mask = data_mask;
+ *p_dst = p;
+
+ return p_flag;
+}
+/*******************************************************************************
+**
+** Function btm_ble_select_adv_interval
+**
+** Description select adv interval based on device mode
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_select_adv_interval(tBTM_BLE_INQ_CB *p_cb, UINT8 evt_type, UINT16 *p_adv_int_min, UINT16 *p_adv_int_max)
+{
+ if (p_cb->adv_interval_min && p_cb->adv_interval_max) {
+ *p_adv_int_min = p_cb->adv_interval_min;
+ *p_adv_int_max = p_cb->adv_interval_max;
+ } else {
+ switch (evt_type) {
+ case BTM_BLE_CONNECT_EVT:
+ case BTM_BLE_CONNECT_LO_DUTY_DIR_EVT:
+ *p_adv_int_min = *p_adv_int_max = BTM_BLE_GAP_ADV_FAST_INT_1;
+ break;
+
+ case BTM_BLE_NON_CONNECT_EVT:
+ case BTM_BLE_DISCOVER_EVT:
+ *p_adv_int_min = *p_adv_int_max = BTM_BLE_GAP_ADV_FAST_INT_2;
+ break;
+
+ /* connectable directed event */
+ case BTM_BLE_CONNECT_DIR_EVT:
+ *p_adv_int_min = BTM_BLE_GAP_ADV_DIR_MIN_INT;
+ *p_adv_int_max = BTM_BLE_GAP_ADV_DIR_MAX_INT;
+ break;
+
+ default:
+ *p_adv_int_min = *p_adv_int_max = BTM_BLE_GAP_ADV_SLOW_INT;
+ break;
+ }
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_update_dmt_flag_bits
+**
+** Description Obtain updated adv flag value based on connect and discoverability mode.
+** Also, setup DMT support value in the flag based on whether the controller
+** supports both LE and BR/EDR.
+**
+** Parameters: flag_value (Input / Output) - flag value
+** connect_mode (Input) - Connect mode value
+** disc_mode (Input) - discoverability mode
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_update_dmt_flag_bits(UINT8 *adv_flag_value, const UINT16 connect_mode,
+ const UINT16 disc_mode)
+{
+ /* BR/EDR non-discoverable , non-connectable */
+ if ((disc_mode & BTM_DISCOVERABLE_MASK) == 0 &&
+ (connect_mode & BTM_CONNECTABLE_MASK) == 0) {
+ *adv_flag_value |= BTM_BLE_BREDR_NOT_SPT;
+ } else {
+ *adv_flag_value &= ~BTM_BLE_BREDR_NOT_SPT;
+ }
+
+ /* if local controller support, mark both controller and host support in flag */
+ if (controller_get_interface()->supports_simultaneous_le_bredr()) {
+ *adv_flag_value |= (BTM_BLE_DMT_CONTROLLER_SPT | BTM_BLE_DMT_HOST_SPT);
+ } else {
+ *adv_flag_value &= ~(BTM_BLE_DMT_CONTROLLER_SPT | BTM_BLE_DMT_HOST_SPT);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_set_adv_flag
+**
+** Description Set adv flag in adv data.
+**
+** Parameters: connect_mode (Input)- Connect mode value
+** disc_mode (Input) - discoverability mode
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_set_adv_flag(UINT16 connect_mode, UINT16 disc_mode)
+{
+ UINT8 flag = 0, old_flag = 0;
+ tBTM_BLE_LOCAL_ADV_DATA *p_adv_data = &btm_cb.ble_ctr_cb.inq_var.adv_data;
+
+ if (p_adv_data->p_flags != NULL) {
+ flag = old_flag = *(p_adv_data->p_flags);
+ }
+
+ btm_ble_update_dmt_flag_bits (&flag, connect_mode, disc_mode);
+
+ BTM_TRACE_DEBUG("disc_mode %04x", disc_mode);
+ /* update discoverable flag */
+ if (disc_mode & BTM_BLE_LIMITED_DISCOVERABLE) {
+ flag &= ~BTM_BLE_GEN_DISC_FLAG;
+ flag |= BTM_BLE_LIMIT_DISC_FLAG;
+ } else if (disc_mode & BTM_BLE_GENERAL_DISCOVERABLE) {
+ flag |= BTM_BLE_GEN_DISC_FLAG;
+ flag &= ~BTM_BLE_LIMIT_DISC_FLAG;
+ } else { /* remove all discoverable flags */
+ flag &= ~(BTM_BLE_LIMIT_DISC_FLAG | BTM_BLE_GEN_DISC_FLAG);
+ }
+
+ if (flag != old_flag) {
+ BTM_TRACE_ERROR("flag = 0x%x,old_flag = 0x%x", flag, old_flag);
+ btm_ble_update_adv_flag(flag);
+ }
+}
+/*******************************************************************************
+**
+** Function btm_ble_set_discoverability
+**
+** Description This function is called to set BLE discoverable mode.
+**
+** Parameters: combined_mode: discoverability mode.
+**
+** Returns BTM_SUCCESS is status set successfully; otherwise failure.
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_set_discoverability(UINT16 combined_mode)
+{
+ tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ UINT16 mode = (combined_mode & BTM_BLE_DISCOVERABLE_MASK);
+ UINT8 new_mode = BTM_BLE_ADV_ENABLE;
+ UINT8 evt_type;
+ tBTM_STATUS status = BTM_SUCCESS;
+ BD_ADDR p_addr_ptr = {0};
+ tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC,
+ own_addr_type = p_addr_cb->own_addr_type;
+ UINT16 adv_int_min, adv_int_max;
+
+ BTM_TRACE_EVENT ("%s mode=0x%0x combined_mode=0x%x\n", __FUNCTION__, mode, combined_mode);
+
+ /*** Check mode parameter ***/
+ if (mode > BTM_BLE_MAX_DISCOVERABLE) {
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ p_cb->discoverable_mode = mode;
+
+ evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &init_addr_type, &own_addr_type);
+
+ if (p_cb->connectable_mode == BTM_BLE_NON_CONNECTABLE && mode == BTM_BLE_NON_DISCOVERABLE) {
+ new_mode = BTM_BLE_ADV_DISABLE;
+ }
+
+ btm_ble_select_adv_interval(p_cb, evt_type, &adv_int_min, &adv_int_max);
+
+ btu_stop_timer(&p_cb->fast_adv_timer);
+
+ /* update adv params if start advertising */
+ BTM_TRACE_EVENT ("evt_type=0x%x p-cb->evt_type=0x%x\n ", evt_type, p_cb->evt_type);
+
+ if (new_mode == BTM_BLE_ADV_ENABLE) {
+ btm_ble_set_adv_flag (btm_cb.btm_inq_vars.connectable_mode, combined_mode);
+
+ if (evt_type != p_cb->evt_type || p_cb->adv_addr_type != own_addr_type
+ || !p_cb->fast_adv_on) {
+ btm_ble_stop_adv();
+
+ /* update adv params */
+ if (!btsnd_hcic_ble_write_adv_params (adv_int_min,
+ adv_int_max,
+ evt_type,
+ own_addr_type,
+ init_addr_type,
+ p_addr_ptr,
+ p_cb->adv_chnl_map,
+ p_cb->afp)) {
+ status = BTM_NO_RESOURCES;
+ } else {
+ p_cb->evt_type = evt_type;
+ p_cb->adv_addr_type = own_addr_type;
+ }
+ }
+ }
+
+ if (status == BTM_SUCCESS && p_cb->adv_mode != new_mode) {
+ if (new_mode == BTM_BLE_ADV_ENABLE) {
+ status = btm_ble_start_adv();
+ } else {
+ status = btm_ble_stop_adv();
+ }
+ }
+
+ if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) {
+ p_cb->fast_adv_on = TRUE;
+ /* start initial GAP mode adv timer */
+ btu_start_timer (&p_cb->fast_adv_timer, BTU_TTYPE_BLE_GAP_FAST_ADV,
+ BTM_BLE_GAP_FAST_ADV_TOUT);
+ } else {
+#if BLE_PRIVACY_SPT == TRUE
+ btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, TRUE);
+#endif
+ }
+
+ /* set up stop advertising timer */
+ if (status == BTM_SUCCESS && mode == BTM_BLE_LIMITED_DISCOVERABLE) {
+ BTM_TRACE_EVENT ("start timer for limited disc mode duration=%d (180 secs)", BTM_BLE_GAP_LIM_TOUT);
+ /* start Tgap(lim_timeout) */
+ btu_start_timer (&p_cb->inq_timer_ent, BTU_TTYPE_BLE_GAP_LIM_DISC,
+ BTM_BLE_GAP_LIM_TOUT);
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_set_connectability
+**
+** Description This function is called to set BLE connectability mode.
+**
+** Parameters: combined_mode: connectability mode.
+**
+** Returns BTM_SUCCESS is status set successfully; otherwise failure.
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_set_connectability(UINT16 combined_mode)
+{
+ tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ UINT16 mode = (combined_mode & BTM_BLE_CONNECTABLE_MASK);
+ UINT8 new_mode = BTM_BLE_ADV_ENABLE;
+ UINT8 evt_type;
+ tBTM_STATUS status = BTM_SUCCESS;
+ BD_ADDR p_addr_ptr = {0};
+ tBLE_ADDR_TYPE peer_addr_type = BLE_ADDR_PUBLIC,
+ own_addr_type = p_addr_cb->own_addr_type;
+ UINT16 adv_int_min, adv_int_max;
+
+ BTM_TRACE_EVENT ("%s mode=0x%0x combined_mode=0x%x\n", __FUNCTION__, mode, combined_mode);
+
+ /*** Check mode parameter ***/
+ if (mode > BTM_BLE_MAX_CONNECTABLE) {
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ p_cb->connectable_mode = mode;
+
+ evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &peer_addr_type, &own_addr_type);
+
+ if (mode == BTM_BLE_NON_CONNECTABLE && p_cb->discoverable_mode == BTM_BLE_NON_DISCOVERABLE) {
+ new_mode = BTM_BLE_ADV_DISABLE;
+ }
+
+ btm_ble_select_adv_interval(p_cb, evt_type, &adv_int_min, &adv_int_max);
+
+ btu_stop_timer(&p_cb->fast_adv_timer);
+ /* update adv params if needed */
+ if (new_mode == BTM_BLE_ADV_ENABLE) {
+ btm_ble_set_adv_flag (combined_mode, btm_cb.btm_inq_vars.discoverable_mode);
+ if (p_cb->evt_type != evt_type || p_cb->adv_addr_type != p_addr_cb->own_addr_type
+ || !p_cb->fast_adv_on) {
+ btm_ble_stop_adv();
+
+ if (!btsnd_hcic_ble_write_adv_params (adv_int_min,
+ adv_int_max,
+ evt_type,
+ own_addr_type,
+ peer_addr_type,
+ p_addr_ptr,
+ p_cb->adv_chnl_map,
+ p_cb->afp)) {
+ status = BTM_NO_RESOURCES;
+ } else {
+ p_cb->evt_type = evt_type;
+ p_cb->adv_addr_type = own_addr_type;
+ }
+ }
+ }
+
+ /* update advertising mode */
+ if (status == BTM_SUCCESS && new_mode != p_cb->adv_mode) {
+ if (new_mode == BTM_BLE_ADV_ENABLE) {
+ status = btm_ble_start_adv();
+ } else {
+ status = btm_ble_stop_adv();
+ }
+ }
+
+ if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) {
+ p_cb->fast_adv_on = TRUE;
+ /* start initial GAP mode adv timer */
+ btu_start_timer (&p_cb->fast_adv_timer, BTU_TTYPE_BLE_GAP_FAST_ADV,
+ BTM_BLE_GAP_FAST_ADV_TOUT);
+ } else {
+#if BLE_PRIVACY_SPT == TRUE
+ btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, TRUE);
+#endif
+ }
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function btm_ble_start_inquiry
+**
+** Description This function is called to start BLE inquiry procedure.
+** If the duration is zero, the periodic inquiry mode is cancelled.
+**
+** Parameters: mode - GENERAL or LIMITED inquiry
+** p_inq_params - pointer to the BLE inquiry parameter.
+** p_results_cb - callback returning pointer to results (tBTM_INQ_RESULTS)
+** p_cmpl_cb - callback indicating the end of an inquiry
+**
+**
+**
+** Returns BTM_CMD_STARTED if successfully started
+** BTM_NO_RESOURCES if could not allocate a message buffer
+** BTM_BUSY - if an inquiry is already active
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8 duration)
+{
+ tBTM_STATUS status = BTM_CMD_STARTED;
+ tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ BTM_TRACE_DEBUG("btm_ble_start_inquiry: mode = %02x inq_active = 0x%02x", mode, btm_cb.btm_inq_vars.inq_active);
+
+ /* if selective connection is active, or inquiry is already active, reject it */
+ if (BTM_BLE_IS_INQ_ACTIVE(p_ble_cb->scan_activity) ||
+ BTM_BLE_IS_SEL_CONN_ACTIVE (p_ble_cb->scan_activity)) {
+ BTM_TRACE_ERROR("LE Inquiry is active, can not start inquiry");
+ return (BTM_BUSY);
+ }
+
+ if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) {
+ btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_ACTI,
+ BTM_BLE_LOW_LATENCY_SCAN_INT,
+ BTM_BLE_LOW_LATENCY_SCAN_WIN,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+ SP_ADV_ALL);
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+ /* enable IRK list */
+ //btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
+#endif
+ status = btm_ble_start_scan();
+ } else if ((p_ble_cb->inq_var.scan_interval != BTM_BLE_LOW_LATENCY_SCAN_INT) ||
+ (p_ble_cb->inq_var.scan_window != BTM_BLE_LOW_LATENCY_SCAN_WIN)) {
+ BTM_TRACE_DEBUG("%s, restart LE scan with low latency scan params", __FUNCTION__);
+ btsnd_hcic_ble_set_scan_enable(BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+ btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_ACTI,
+ BTM_BLE_LOW_LATENCY_SCAN_INT,
+ BTM_BLE_LOW_LATENCY_SCAN_WIN,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+ SP_ADV_ALL);
+ btsnd_hcic_ble_set_scan_enable(BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE);
+ }
+
+ if (status == BTM_CMD_STARTED) {
+ p_inq->inq_active |= mode;
+ p_ble_cb->scan_activity |= mode;
+
+ BTM_TRACE_DEBUG("btm_ble_start_inquiry inq_active = 0x%02x", p_inq->inq_active);
+
+ if (duration != 0) {
+ /* start inquiry timer */
+ btu_start_timer (&p_ble_cb->inq_var.inq_timer_ent, BTU_TTYPE_BLE_INQUIRY, duration);
+ }
+ }
+
+ return status;
+
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_read_remote_name_cmpl
+**
+** Description This function is called when BLE remote name is received.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_read_remote_name_cmpl(BOOLEAN status, BD_ADDR bda, UINT16 length, char *p_name)
+{
+ UINT8 hci_status = HCI_SUCCESS;
+ BD_NAME bd_name;
+
+ memset(bd_name, 0, (BD_NAME_LEN + 1));
+ if (length > BD_NAME_LEN) {
+ length = BD_NAME_LEN;
+ }
+ memcpy((UINT8 *)bd_name, p_name, length);
+
+ if ((!status) || (length == 0)) {
+ hci_status = HCI_ERR_HOST_TIMEOUT;
+ }
+
+ btm_process_remote_name(bda, bd_name, length + 1, hci_status);
+#if (SMP_INCLUDED == TRUE)
+ btm_sec_rmt_name_request_complete (bda, (UINT8 *)p_name, hci_status);
+#endif ///SMP_INCLUDED == TRUE
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_read_remote_name
+**
+** Description This function read remote LE device name using GATT read
+** procedure.
+**
+** Parameters: None.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_read_remote_name(BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur, tBTM_CMPL_CB *p_cb)
+{
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ if (!controller_get_interface()->supports_ble()) {
+ return BTM_ERR_PROCESSING;
+ }
+
+ if (p_cur &&
+ p_cur->results.ble_evt_type != BTM_BLE_EVT_CONN_ADV &&
+ p_cur->results.ble_evt_type != BTM_BLE_EVT_CONN_DIR_ADV) {
+ BTM_TRACE_DEBUG("name request to non-connectable device failed.");
+ return BTM_ERR_PROCESSING;
+ }
+
+ /* read remote device name using GATT procedure */
+ if (p_inq->remname_active) {
+ return BTM_BUSY;
+ }
+
+#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE && GATTS_INCLUDED == TRUE)
+ if (!GAP_BleReadPeerDevName(remote_bda, btm_ble_read_remote_name_cmpl)) {
+ return BTM_BUSY;
+ }
+#endif
+
+ p_inq->p_remname_cmpl_cb = p_cb;
+ p_inq->remname_active = TRUE;
+
+ memcpy(p_inq->remname_bda, remote_bda, BD_ADDR_LEN);
+
+ btu_start_timer (&p_inq->rmt_name_timer_ent,
+ BTU_TTYPE_BTM_RMT_NAME,
+ BTM_EXT_BLE_RMT_NAME_TIMEOUT);
+
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_cancel_remote_name
+**
+** Description This function cancel read remote LE device name.
+**
+** Parameters: None.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN btm_ble_cancel_remote_name(BD_ADDR remote_bda)
+{
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ BOOLEAN status = TRUE;
+
+#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE && GATTS_INCLUDED == TRUE)
+ status = GAP_BleCancelReadPeerDevName(remote_bda);
+#endif
+
+ p_inq->remname_active = FALSE;
+ memset(p_inq->remname_bda, 0, BD_ADDR_LEN);
+ btu_stop_timer(&p_inq->rmt_name_timer_ent);
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_update_adv_flag
+**
+** Description This function update the limited discoverable flag in the adv
+** data.
+**
+** Parameters: None.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_update_adv_flag(UINT8 flag)
+{
+ tBTM_BLE_LOCAL_ADV_DATA *p_adv_data = &btm_cb.ble_ctr_cb.inq_var.adv_data;
+ UINT8 *p;
+
+ BTM_TRACE_DEBUG ("btm_ble_update_adv_flag new=0x%x", flag);
+
+ if (p_adv_data->p_flags != NULL) {
+ BTM_TRACE_DEBUG ("btm_ble_update_adv_flag old=0x%x", *p_adv_data->p_flags);
+ *p_adv_data->p_flags = flag;
+ } else { /* no FLAGS in ADV data*/
+ p = (p_adv_data->p_pad == NULL) ? p_adv_data->ad_data : p_adv_data->p_pad;
+ /* need 3 bytes space to stuff in the flags, if not */
+ /* erase all written data, just for flags */
+ if ((BTM_BLE_AD_DATA_LEN - (p - p_adv_data->ad_data)) < 3) {
+ p = p_adv_data->p_pad = p_adv_data->ad_data;
+ memset(p_adv_data->ad_data, 0, BTM_BLE_AD_DATA_LEN);
+ }
+
+ *p++ = 2;
+ *p++ = BTM_BLE_AD_TYPE_FLAG;
+ p_adv_data->p_flags = p;
+ *p++ = flag;
+ p_adv_data->p_pad = p;
+ }
+
+ if (btsnd_hcic_ble_set_adv_data((UINT8)(p_adv_data->p_pad - p_adv_data->ad_data),
+ p_adv_data->ad_data)) {
+ p_adv_data->data_mask |= BTM_BLE_AD_BIT_FLAGS;
+ }
+
+}
+
+#if 0
+/*******************************************************************************
+**
+** Function btm_ble_parse_adv_data
+**
+** Description This function parse the adv data into a structure.
+**
+** Returns pointer to entry, or NULL if not found
+**
+*******************************************************************************/
+static void btm_ble_parse_adv_data(tBTM_INQ_INFO *p_info, UINT8 *p_data,
+ UINT8 len, tBTM_BLE_INQ_DATA *p_adv_data, UINT8 *p_buf)
+{
+ UINT8 *p_cur = p_data;
+ UINT8 ad_len, ad_type, ad_flag;
+
+ BTM_TRACE_EVENT (" btm_ble_parse_adv_data");
+
+ while (len > 0) {
+ BTM_TRACE_DEBUG("btm_ble_parse_adv_data: len = %d", len);
+ if ((ad_len = *p_cur ++) == 0) {
+ break;
+ }
+
+ ad_type = *p_cur ++;
+
+ BTM_TRACE_DEBUG(" ad_type = %02x ad_len = %d", ad_type, ad_len);
+
+ switch (ad_type) {
+ case BTM_BLE_AD_TYPE_NAME_SHORT:
+
+ case BTM_BLE_AD_TYPE_NAME_CMPL:
+ p_adv_data->ad_mask |= BTM_BLE_AD_BIT_DEV_NAME;
+ if (p_info) {
+ p_info->remote_name_type = (ad_type == BTM_BLE_AD_TYPE_NAME_SHORT) ?
+ BTM_BLE_NAME_SHORT : BTM_BLE_NAME_CMPL;
+ memcpy(p_info->remote_name, p_cur, ad_len - 1);
+ p_info->remote_name[ad_len] = 0;
+ p_adv_data->p_remote_name = p_info->remote_name;
+ p_info->remote_name_len = p_adv_data->remote_name_len = ad_len - 1;
+ BTM_TRACE_DEBUG("BTM_BLE_AD_TYPE_NAME name = %s", p_adv_data->p_remote_name);
+ }
+ p_cur += (ad_len - 1);
+
+ break;
+
+ case BTM_BLE_AD_TYPE_FLAG:
+ p_adv_data->ad_mask |= BTM_BLE_AD_BIT_FLAGS;
+ ad_flag = *p_cur ++;
+ p_adv_data->flag = (UINT8)(ad_flag & BTM_BLE_ADV_FLAG_MASK) ;
+ BTM_TRACE_DEBUG("BTM_BLE_AD_TYPE_FLAG flag = %s | %s | %s",
+ (p_adv_data->flag & BTM_BLE_LIMIT_DISC_FLAG) ? "LE_LIMIT_DISC" : "",
+ (p_adv_data->flag & BTM_BLE_GEN_DISC_FLAG) ? "LE_GENERAL_DISC" : "",
+ (p_adv_data->flag & BTM_BLE_BREDR_NOT_SPT) ? "LE Only device" : "");
+ break;
+
+ case BTM_BLE_AD_TYPE_TX_PWR:
+ p_adv_data->ad_mask |= BTM_BLE_AD_BIT_TX_PWR;
+ p_adv_data->tx_power_level = (INT8) * p_cur ++;
+ BTM_TRACE_DEBUG("BTM_BLE_AD_TYPE_TX_PWR tx_level = %d", p_adv_data->tx_power_level);
+ break;
+
+ case BTM_BLE_AD_TYPE_MANU:
+
+ case BTM_BLE_AD_TYPE_16SRV_PART:
+ case BTM_BLE_AD_TYPE_16SRV_CMPL:
+ p_adv_data->ad_mask |= BTM_BLE_AD_BIT_SERVICE;
+ /* need allocate memory to store UUID list */
+ p_adv_data->service.num_service = (ad_len - 1) / 2;
+ BTM_TRACE_DEBUG("service UUID list, num = %d", p_adv_data->service.num_service);
+ p_cur += (ad_len - 1);
+ break;
+
+ case BTM_BLE_AD_TYPE_SOL_SRV_UUID:
+ p_adv_data->ad_mask |= BTM_BLE_AD_BIT_SERVICE_SOL;
+ /* need allocate memory to store UUID list */
+ p_adv_data->service.num_service = (ad_len - 1) / 2;
+ BTM_TRACE_DEBUG("service UUID list, num = %d", p_adv_data->service.num_service);
+ p_cur += (ad_len - 1);
+ break;
+
+ case BTM_BLE_AD_TYPE_128SOL_SRV_UUID:
+ p_adv_data->ad_mask |= BTM_BLE_AD_BIT_SERVICE_128SOL;
+ /* need allocate memory to store UUID list */
+ p_adv_data->service.num_service = (ad_len - 1) / 16;
+ BTM_TRACE_DEBUG("service UUID list, num = %d", p_adv_data->service.num_service);
+ p_cur += (ad_len - 1);
+ break;
+
+ case BTM_BLE_AD_TYPE_APPEARANCE:
+ case BTM_BLE_AD_TYPE_PUBLIC_TARGET:
+ case BTM_BLE_AD_TYPE_RANDOM_TARGET:
+ default:
+ break;
+ }
+ len -= (ad_len + 1);
+ }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function btm_ble_cache_adv_data
+**
+** Description Update advertising cache data.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_cache_adv_data(BD_ADDR bda, tBTM_INQ_RESULTS *p_cur, UINT8 data_len, UINT8 *p, UINT8 evt_type)
+{
+ tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+ UINT8 *p_cache;
+ //UINT8 length;
+
+ /* cache adv report/scan response data */
+ if (evt_type != BTM_BLE_SCAN_RSP_EVT) {
+ p_le_inq_cb->adv_len = 0;
+ memset(p_le_inq_cb->adv_data_cache, 0, BTM_BLE_CACHE_ADV_DATA_MAX);
+ p_cur->adv_data_len = 0;
+ p_cur->scan_rsp_len = 0;
+ }
+
+ //Clear the adv cache if the addresses are not equal
+ if(memcmp(bda, p_le_inq_cb->adv_addr, BD_ADDR_LEN) != 0) {
+ p_le_inq_cb->adv_len = 0;
+ memcpy(p_le_inq_cb->adv_addr, bda, BD_ADDR_LEN);
+ memset(p_le_inq_cb->adv_data_cache, 0, BTM_BLE_CACHE_ADV_DATA_MAX);
+ p_cur->adv_data_len = 0;
+ p_cur->scan_rsp_len = 0;
+ }
+
+ if (data_len > 0) {
+ p_cache = &p_le_inq_cb->adv_data_cache[p_le_inq_cb->adv_len];
+ if((data_len + p_le_inq_cb->adv_len) <= BTM_BLE_CACHE_ADV_DATA_MAX) {
+ memcpy(p_cache, p, data_len);
+ p_le_inq_cb->adv_len += data_len;
+ }
+ }
+
+ if (evt_type != BTM_BLE_SCAN_RSP_EVT) {
+ p_cur->adv_data_len = p_le_inq_cb->adv_len;
+ }
+ else {
+ p_cur->scan_rsp_len = p_le_inq_cb->adv_len - p_cur->adv_data_len;
+ }
+
+ /* parse service UUID from adv packet and save it in inq db eir_uuid */
+ /* TODO */
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_is_discoverable
+**
+** Description check ADV flag to make sure device is discoverable and match
+** the search condition
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+UINT8 btm_ble_is_discoverable(BD_ADDR bda, UINT8 evt_type, UINT8 *p)
+{
+ UINT8 *p_flag, flag = 0, rt = 0;
+ UINT8 data_len;
+ tBTM_INQ_PARMS *p_cond = &btm_cb.btm_inq_vars.inqparms;
+ tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ UNUSED(p);
+
+ /* for observer, always "discoverable */
+ if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
+ rt |= BTM_BLE_OBS_RESULT;
+ }
+ /* for discover, always "discoverable */
+ if (BTM_BLE_IS_DISCO_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
+ rt |= BTM_BLE_DISCO_RESULT;
+ }
+
+ if (BTM_BLE_IS_SEL_CONN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity) &&
+ (evt_type == BTM_BLE_CONNECT_EVT || evt_type == BTM_BLE_CONNECT_DIR_EVT)) {
+ rt |= BTM_BLE_SEL_CONN_RESULT;
+ }
+
+ /* does not match filter condition */
+ if (p_cond->filter_cond_type == BTM_FILTER_COND_BD_ADDR &&
+ memcmp(bda, p_cond->filter_cond.bdaddr_cond, BD_ADDR_LEN) != 0) {
+ BTM_TRACE_DEBUG("BD ADDR does not meet filter condition");
+ return rt;
+ }
+
+ if (p_le_inq_cb->adv_len != 0) {
+ if ((p_flag = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache,
+ BTM_BLE_AD_TYPE_FLAG, &data_len)) != NULL) {
+ flag = * p_flag;
+
+ if ((btm_cb.btm_inq_vars.inq_active & BTM_BLE_GENERAL_INQUIRY) &&
+ (flag & (BTM_BLE_LIMIT_DISC_FLAG | BTM_BLE_GEN_DISC_FLAG)) != 0) {
+ BTM_TRACE_DEBUG("Find Generable Discoverable device");
+ rt |= BTM_BLE_INQ_RESULT;
+ }
+
+ else if (btm_cb.btm_inq_vars.inq_active & BTM_BLE_LIMITED_INQUIRY &&
+ (flag & BTM_BLE_LIMIT_DISC_FLAG) != 0) {
+ BTM_TRACE_DEBUG("Find limited discoverable device");
+ rt |= BTM_BLE_INQ_RESULT;
+ }
+ }
+ }
+ return rt;
+}
+
+static void btm_ble_appearance_to_cod(UINT16 appearance, UINT8 *dev_class)
+{
+ dev_class[0] = 0;
+
+ switch (appearance) {
+ case BTM_BLE_APPEARANCE_GENERIC_PHONE:
+ dev_class[1] = BTM_COD_MAJOR_PHONE;
+ dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_COMPUTER:
+ dev_class[1] = BTM_COD_MAJOR_COMPUTER;
+ dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_REMOTE:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_REMOTE_CONTROL;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_THERMOMETER:
+ case BTM_BLE_APPEARANCE_THERMOMETER_EAR:
+ dev_class[1] = BTM_COD_MAJOR_HEALTH;
+ dev_class[2] = BTM_COD_MINOR_THERMOMETER;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_HEART_RATE:
+ case BTM_BLE_APPEARANCE_HEART_RATE_BELT:
+ dev_class[1] = BTM_COD_MAJOR_HEALTH;
+ dev_class[2] = BTM_COD_MINOR_HEART_PULSE_MONITOR;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE:
+ case BTM_BLE_APPEARANCE_BLOOD_PRESSURE_ARM:
+ case BTM_BLE_APPEARANCE_BLOOD_PRESSURE_WRIST:
+ dev_class[1] = BTM_COD_MAJOR_HEALTH;
+ dev_class[2] = BTM_COD_MINOR_BLOOD_MONITOR;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_PULSE_OXIMETER:
+ case BTM_BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP:
+ case BTM_BLE_APPEARANCE_PULSE_OXIMETER_WRIST:
+ dev_class[1] = BTM_COD_MAJOR_HEALTH;
+ dev_class[2] = BTM_COD_MINOR_PULSE_OXIMETER;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_GLUCOSE:
+ dev_class[1] = BTM_COD_MAJOR_HEALTH;
+ dev_class[2] = BTM_COD_MINOR_GLUCOSE_METER;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_WEIGHT:
+ dev_class[1] = BTM_COD_MAJOR_HEALTH;
+ dev_class[2] = BTM_COD_MINOR_WEIGHING_SCALE;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_WALKING:
+ case BTM_BLE_APPEARANCE_WALKING_IN_SHOE:
+ case BTM_BLE_APPEARANCE_WALKING_ON_SHOE:
+ case BTM_BLE_APPEARANCE_WALKING_ON_HIP:
+ dev_class[1] = BTM_COD_MAJOR_HEALTH;
+ dev_class[2] = BTM_COD_MINOR_STEP_COUNTER;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_WATCH:
+ case BTM_BLE_APPEARANCE_SPORTS_WATCH:
+ dev_class[1] = BTM_COD_MAJOR_WEARABLE;
+ dev_class[2] = BTM_COD_MINOR_WRIST_WATCH;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_EYEGLASSES:
+ dev_class[1] = BTM_COD_MAJOR_WEARABLE;
+ dev_class[2] = BTM_COD_MINOR_GLASSES;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_DISPLAY:
+ dev_class[1] = BTM_COD_MAJOR_IMAGING;
+ dev_class[2] = BTM_COD_MINOR_DISPLAY;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_MEDIA_PLAYER:
+ dev_class[1] = BTM_COD_MAJOR_AUDIO;
+ dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_BARCODE_SCANNER:
+ case BTM_BLE_APPEARANCE_HID_BARCODE_SCANNER:
+ case BTM_BLE_APPEARANCE_GENERIC_HID:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED;
+ break;
+ case BTM_BLE_APPEARANCE_HID_KEYBOARD:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_KEYBOARD;
+ break;
+ case BTM_BLE_APPEARANCE_HID_MOUSE:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_POINTING;
+ break;
+ case BTM_BLE_APPEARANCE_HID_JOYSTICK:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_JOYSTICK;
+ break;
+ case BTM_BLE_APPEARANCE_HID_GAMEPAD:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_GAMEPAD;
+ break;
+ case BTM_BLE_APPEARANCE_HID_DIGITIZER_TABLET:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_DIGITIZING_TABLET;
+ break;
+ case BTM_BLE_APPEARANCE_HID_CARD_READER:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_CARD_READER;
+ break;
+ case BTM_BLE_APPEARANCE_HID_DIGITAL_PEN:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_DIGITAL_PAN;
+ break;
+ case BTM_BLE_APPEARANCE_UNKNOWN:
+ case BTM_BLE_APPEARANCE_GENERIC_CLOCK:
+ case BTM_BLE_APPEARANCE_GENERIC_TAG:
+ case BTM_BLE_APPEARANCE_GENERIC_KEYRING:
+ case BTM_BLE_APPEARANCE_GENERIC_CYCLING:
+ case BTM_BLE_APPEARANCE_CYCLING_COMPUTER:
+ case BTM_BLE_APPEARANCE_CYCLING_SPEED:
+ case BTM_BLE_APPEARANCE_CYCLING_CADENCE:
+ case BTM_BLE_APPEARANCE_CYCLING_POWER:
+ case BTM_BLE_APPEARANCE_CYCLING_SPEED_CADENCE:
+ case BTM_BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS:
+ case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION:
+ case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV:
+ case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD:
+ case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV:
+ default:
+ dev_class[1] = BTM_COD_MAJOR_UNCLASSIFIED;
+ dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED;
+ };
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_update_inq_result
+**
+** Description Update adv packet information into inquiry result.
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN btm_ble_update_inq_result(BD_ADDR bda, tINQ_DB_ENT *p_i, UINT8 addr_type, UINT8 evt_type, UINT8 *p)
+{
+ BOOLEAN to_report = TRUE;
+ tBTM_INQ_RESULTS *p_cur = &p_i->inq_info.results;
+ UINT8 len;
+ UINT8 *p_flag;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ UINT8 data_len, rssi;
+ tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+ UINT8 *p1;
+ UINT8 *p_uuid16;
+
+ STREAM_TO_UINT8 (data_len, p);
+
+ if (data_len > BTM_BLE_ADV_DATA_LEN_MAX) {
+ BTM_TRACE_WARNING("EIR data too long %d. discard", data_len);
+ return FALSE;
+ }
+ btm_ble_cache_adv_data(bda, p_cur, data_len, p, evt_type);
+
+ p1 = (p + data_len);
+ STREAM_TO_UINT8 (rssi, p1);
+
+ /* Save the info */
+ p_cur->inq_result_type = BTM_INQ_RESULT_BLE;
+ p_cur->ble_addr_type = addr_type;
+ p_cur->rssi = rssi;
+
+ /* active scan, always wait until get scan_rsp to report the result */
+ if ((btm_cb.ble_ctr_cb.inq_var.scan_type == BTM_BLE_SCAN_MODE_ACTI &&
+ (evt_type == BTM_BLE_CONNECT_EVT || evt_type == BTM_BLE_DISCOVER_EVT))) {
+ BTM_TRACE_DEBUG("btm_ble_update_inq_result scan_rsp=false, to_report=false,\
+ scan_type_active=%d", btm_cb.ble_ctr_cb.inq_var.scan_type);
+ p_i->scan_rsp = FALSE;
+#if BTM_BLE_ACTIVE_SCAN_REPORT_ADV_SCAN_RSP_INDIVIDUALLY == FALSE
+ to_report = FALSE;
+#endif
+ } else {
+ p_i->scan_rsp = TRUE;
+ }
+
+ if (p_i->inq_count != p_inq->inq_counter) {
+ p_cur->device_type = BT_DEVICE_TYPE_BLE;
+ } else {
+ p_cur->device_type |= BT_DEVICE_TYPE_BLE;
+ }
+
+ if (evt_type != BTM_BLE_SCAN_RSP_EVT) {
+ p_cur->ble_evt_type = evt_type;
+ }
+#if BTM_BLE_ACTIVE_SCAN_REPORT_ADV_SCAN_RSP_INDIVIDUALLY
+ if (evt_type == BTM_BLE_SCAN_RSP_EVT) {
+ p_cur->ble_evt_type = evt_type;
+ }
+#endif
+ p_i->inq_count = p_inq->inq_counter; /* Mark entry for current inquiry */
+
+ if (p_le_inq_cb->adv_len != 0) {
+ if ((p_flag = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache, BTM_BLE_AD_TYPE_FLAG, &len)) != NULL) {
+ p_cur->flag = * p_flag;
+ }
+ }
+
+ if (p_le_inq_cb->adv_len != 0) {
+ /* Check to see the BLE device has the Appearance UUID in the advertising data. If it does
+ * then try to convert the appearance value to a class of device value Bluedroid can use.
+ * Otherwise fall back to trying to infer if it is a HID device based on the service class.
+ */
+ p_uuid16 = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache, BTM_BLE_AD_TYPE_APPEARANCE, &len);
+ if (p_uuid16 && len == 2) {
+ btm_ble_appearance_to_cod((UINT16)p_uuid16[0] | (p_uuid16[1] << 8), p_cur->dev_class);
+ } else {
+ if ((p_uuid16 = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache,
+ BTM_BLE_AD_TYPE_16SRV_CMPL, &len)) != NULL) {
+ UINT8 i;
+ for (i = 0; i + 2 <= len; i = i + 2) {
+#if BTA_HH_LE_INCLUDED == TRUE
+ /* if this BLE device support HID over LE, set HID Major in class of device */
+ if ((p_uuid16[i] | (p_uuid16[i + 1] << 8)) == UUID_SERVCLASS_LE_HID) {
+ p_cur->dev_class[0] = 0;
+ p_cur->dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ p_cur->dev_class[2] = 0;
+ break;
+ }
+#endif /* BTA_HH_LE_INCLUDED */
+ }
+ }
+ }
+ }
+
+ /* if BR/EDR not supported is not set, assume is a DUMO device */
+ if ((p_cur->flag & BTM_BLE_BREDR_NOT_SPT) == 0 &&
+ evt_type != BTM_BLE_CONNECT_DIR_EVT) {
+ if (p_cur->ble_addr_type != BLE_ADDR_RANDOM) {
+ BTM_TRACE_DEBUG("BR/EDR NOT support bit not set, treat as DUMO");
+ p_cur->device_type |= BT_DEVICE_TYPE_DUMO;
+ } else {
+ BTM_TRACE_DEBUG("Random address, treating device as LE only");
+ }
+ } else {
+ BTM_TRACE_DEBUG("BR/EDR NOT SUPPORT bit set, LE only device");
+ }
+
+ return to_report;
+
+}
+
+/*******************************************************************************
+**
+** Function btm_clear_all_pending_le_entry
+**
+** Description This function is called to clear all LE pending entry in
+** inquiry database.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_clear_all_pending_le_entry(void)
+{
+ UINT16 xx;
+ tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db;
+
+ for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) {
+ /* mark all pending LE entry as unused if an LE only device has scan response outstanding */
+ if ((p_ent->in_use) &&
+ (p_ent->inq_info.results.device_type == BT_DEVICE_TYPE_BLE) &&
+ !p_ent->scan_rsp) {
+ p_ent->in_use = FALSE;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_send_sel_conn_callback
+**
+** Description send selection connection request callback.
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_send_sel_conn_callback(BD_ADDR remote_bda, UINT8 evt_type, UINT8 *p_data, UINT8 addr_type)
+{
+ UINT8 data_len, len;
+ UINT8 *p_dev_name, remname[31] = {0};
+ UNUSED(addr_type);
+
+ if (btm_cb.ble_ctr_cb.p_select_cback == NULL ||
+ /* non-connectable device */
+ (evt_type != BTM_BLE_EVT_CONN_ADV && evt_type != BTM_BLE_EVT_CONN_DIR_ADV)) {
+ return;
+ }
+
+ STREAM_TO_UINT8 (data_len, p_data);
+
+ /* get the device name if exist in ADV data */
+ if (data_len != 0) {
+ p_dev_name = BTM_CheckAdvData(p_data, BTM_BLE_AD_TYPE_NAME_CMPL, &len);
+
+ if (p_dev_name == NULL) {
+ p_dev_name = BTM_CheckAdvData(p_data, BTM_BLE_AD_TYPE_NAME_SHORT, &len);
+ }
+
+ if (p_dev_name) {
+ memcpy(remname, p_dev_name, len);
+ }
+ }
+ /* allow connection */
+ if ((* btm_cb.ble_ctr_cb.p_select_cback)(remote_bda, remname)) {
+ /* terminate selective connection, initiate connection */
+ btm_ble_initiate_select_conn(remote_bda);
+ }
+}
+
+static void btm_adv_pkt_handler(void *arg)
+{
+ UINT8 hci_evt_code, hci_evt_len;
+ UINT8 ble_sub_code;
+
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ size_t pkts_to_process = pkt_queue_length(p_cb->adv_rpt_queue);
+ if (pkts_to_process > BTM_BLE_GAP_ADV_RPT_BATCH_SIZE) {
+ pkts_to_process = BTM_BLE_GAP_ADV_RPT_BATCH_SIZE;
+ }
+
+ for (size_t i = 0; i < pkts_to_process; i++) {
+ pkt_linked_item_t *linked_pkt = pkt_queue_dequeue(p_cb->adv_rpt_queue);
+ assert(linked_pkt != NULL);
+ BT_HDR *packet = (BT_HDR *)linked_pkt->data;
+ uint8_t *p = packet->data + packet->offset;
+ STREAM_TO_UINT8 (hci_evt_code, p);
+ STREAM_TO_UINT8 (hci_evt_len, p);
+ STREAM_TO_UINT8 (ble_sub_code, p);
+ if (ble_sub_code == HCI_BLE_ADV_PKT_RPT_EVT) {
+ btm_ble_process_adv_pkt(p);
+ } else if (ble_sub_code == HCI_BLE_ADV_DISCARD_REPORT_EVT) {
+ btm_ble_process_adv_discard_evt(p);
+ } else if (ble_sub_code == HCI_BLE_DIRECT_ADV_EVT) {
+ btm_ble_process_direct_adv_pkt(p);
+ } else {
+ assert (0);
+ }
+
+ osi_free(linked_pkt);
+#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE)
+ hci_adv_credits_try_release(1);
+#endif
+ }
+
+ if (pkt_queue_length(p_cb->adv_rpt_queue) != 0) {
+ btu_task_post(SIG_BTU_HCI_ADV_RPT_MSG, NULL, OSI_THREAD_MAX_TIMEOUT);
+ }
+
+ UNUSED(hci_evt_code);
+ UNUSED(hci_evt_len);
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_process_adv_pkt
+**
+** Description This function is called when adv packet report events are
+** received from the device. It updates the inquiry database.
+** If the inquiry database is full, the oldest entry is discarded.
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_process_adv_pkt (UINT8 *p_data)
+{
+ BD_ADDR bda;
+ UINT8 evt_type = 0, *p = p_data;
+ UINT8 addr_type = 0;
+ UINT8 num_reports;
+ UINT8 data_len;
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+ BOOLEAN match = FALSE;
+#if (!CONTROLLER_RPA_LIST_ENABLE)
+ BD_ADDR temp_bda;
+ UINT8 temp_addr_type = 0;
+#endif // (!CONTROLLER_RPA_LIST_ENABLE)
+#endif//(defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+
+ /* Only process the results if the inquiry is still active */
+ if (!BTM_BLE_IS_SCAN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
+ return;
+ }
+
+ /* Extract the number of reports in this event. */
+ STREAM_TO_UINT8(num_reports, p);
+
+ while (num_reports--) {
+ /* Extract inquiry results */
+ STREAM_TO_UINT8 (evt_type, p);
+ STREAM_TO_UINT8 (addr_type, p);
+ STREAM_TO_BDADDR (bda, p);
+ //BTM_TRACE_ERROR("btm_ble_process_adv_pkt:bda= %0x:%0x:%0x:%0x:%0x:%0x\n",
+ // bda[0],bda[1],bda[2],bda[3],bda[4],bda[5]);
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+
+#if (!CONTROLLER_RPA_LIST_ENABLE)
+ temp_addr_type = addr_type;
+ memcpy(temp_bda, bda, BD_ADDR_LEN);
+#endif // (!CONTROLLER_RPA_LIST_ENABLE)
+
+ /* map address to security record */
+ match = btm_identity_addr_to_random_pseudo(bda, &addr_type, FALSE);
+
+ // BTM_TRACE_ERROR("btm_ble_process_adv_pkt:bda= %0x:%0x:%0x:%0x:%0x:%0x\n",
+ // bda[0],bda[1],bda[2],bda[3],bda[4],bda[5]);
+ /* always do RRA resolution on host */
+ if (!match && BTM_BLE_IS_RESOLVE_BDA(bda)) {
+ btm_ble_resolve_random_addr(bda, btm_ble_resolve_random_addr_on_adv, p_data);
+ } else
+#endif
+ btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, p);
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE && (!CONTROLLER_RPA_LIST_ENABLE))
+ //save current adv addr information if p_dev_rec!= NULL
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda);
+ if(p_dev_rec) {
+ p_dev_rec->ble.current_addr_type = temp_addr_type;
+ memcpy(p_dev_rec->ble.current_addr, temp_bda, BD_ADDR_LEN);
+ p_dev_rec->ble.current_addr_valid = true;
+ }
+#endif
+ STREAM_TO_UINT8(data_len, p);
+
+ /* Advance to the next event data_len + rssi byte */
+ p += data_len + 1;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_process_last_adv_pkt
+**
+** Description This function is called to report last adv packet
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void btm_ble_process_last_adv_pkt(void)
+{
+ UINT8 result = 0;
+ UINT8 null_bda[6] = {0};
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ tBTM_INQ_RESULTS_CB *p_inq_results_cb = p_inq->p_inq_results_cb;
+ tBTM_INQ_RESULTS_CB *p_obs_results_cb = btm_cb.ble_ctr_cb.p_obs_results_cb;
+ tBTM_INQ_RESULTS_CB *p_scan_results_cb = btm_cb.ble_ctr_cb.p_scan_results_cb;
+ tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+ tINQ_DB_ENT *p_i = btm_inq_db_find (p_le_inq_cb->adv_addr);
+
+ if(memcmp(null_bda, p_le_inq_cb->adv_addr, BD_ADDR_LEN) == 0) {
+ return;
+ }
+
+ if(p_i == NULL) {
+ BTM_TRACE_DEBUG("no last adv");
+ return;
+ }
+
+ if ((result = btm_ble_is_discoverable(p_le_inq_cb->adv_addr, p_i->inq_info.results.ble_evt_type, NULL)) == 0) {
+ BTM_TRACE_WARNING("%s device is no longer discoverable so discarding advertising packet pkt",
+ __func__);
+ return;
+ }
+ /* background connection in selective connection mode */
+ if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE) {
+ //do nothing
+ } else {
+ if (p_inq_results_cb && (result & BTM_BLE_INQ_RESULT)) {
+ (p_inq_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
+ p_le_inq_cb->adv_len = 0;
+ memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
+ p_i->inq_info.results.adv_data_len = 0;
+ p_i->inq_info.results.scan_rsp_len = 0;
+ }
+ if (p_obs_results_cb && (result & BTM_BLE_OBS_RESULT)) {
+ (p_obs_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
+ p_le_inq_cb->adv_len = 0;
+ memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
+ p_i->inq_info.results.adv_data_len = 0;
+ p_i->inq_info.results.scan_rsp_len = 0;
+ }
+ if (p_scan_results_cb && (result & BTM_BLE_DISCO_RESULT)) {
+ (p_scan_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
+ p_le_inq_cb->adv_len = 0;
+ memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
+ p_i->inq_info.results.adv_data_len = 0;
+ p_i->inq_info.results.scan_rsp_len = 0;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_process_adv_pkt_cont
+**
+** Description This function is called after random address resolution is
+** done, and proceed to process adv packet.
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt_type, UINT8 *p)
+{
+
+ tINQ_DB_ENT *p_i;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ tBTM_INQ_RESULTS_CB *p_inq_results_cb = p_inq->p_inq_results_cb;
+ tBTM_INQ_RESULTS_CB *p_obs_results_cb = btm_cb.ble_ctr_cb.p_obs_results_cb;
+ tBTM_INQ_RESULTS_CB *p_scan_results_cb = btm_cb.ble_ctr_cb.p_scan_results_cb;
+ tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+ BOOLEAN update = TRUE;
+ UINT8 result = 0;
+
+ /* Event_Type:
+ 0x00 Connectable undirected advertising (ADV_IND).
+ 0x01 Connectable directed advertising (ADV_DIRECT_IND)
+ 0x02 Scannable undirected advertising (ADV_SCAN_IND)
+ 0x03 Non connectable undirected advertising (ADV_NONCONN_IND)
+ 0x04 Scan Response (SCAN_RSP)
+ 0x05-0xFF Reserved for future use
+ */
+ // The adv packet without scan response is allowed to report to higher layer
+ /*
+ Bluedroid will put the advertising packet and scan response into a packet and send it to the higher layer.
+ If two advertising packets are not with the same address, or can't be combined into a packet, then the first advertising
+ packet will be discarded. So we added the following judgment:
+ 1. For different addresses, send the last advertising packet to higher layer
+ 2. For same address and same advertising type (not scan response), send the last advertising packet to higher layer
+ 3. For same address and scan response, do nothing
+ */
+ int same_addr = memcmp(bda, p_le_inq_cb->adv_addr, BD_ADDR_LEN);
+ if (same_addr != 0 || (same_addr == 0 && evt_type != BTM_BLE_SCAN_RSP_EVT)) {
+ btm_ble_process_last_adv_pkt();
+ }
+
+
+ p_i = btm_inq_db_find (bda);
+
+ /* Check if this address has already been processed for this inquiry */
+ if (btm_inq_find_bdaddr(bda)) {
+ /* never been report as an LE device */
+ if (p_i &&
+ (!(p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BLE) ||
+ /* scan repsonse to be updated */
+ (!p_i->scan_rsp))) {
+ update = TRUE;
+ } else if (BTM_BLE_IS_DISCO_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
+ update = FALSE;
+ } else {
+ /* if yes, skip it */
+ return; /* assumption: one result per event */
+ }
+ }
+ /* If existing entry, use that, else get a new one (possibly reusing the oldest) */
+ if (p_i == NULL) {
+ if ((p_i = btm_inq_db_new (bda)) != NULL) {
+ p_inq->inq_cmpl_info.num_resp++;
+ } else {
+ return;
+ }
+ } else if (p_i->inq_count != p_inq->inq_counter) { /* first time seen in this inquiry */
+ p_inq->inq_cmpl_info.num_resp++;
+ }
+ /* update the LE device information in inquiry database */
+ if (!btm_ble_update_inq_result(bda, p_i, addr_type, evt_type, p)) {
+ return;
+ }
+
+ if ((result = btm_ble_is_discoverable(bda, evt_type, p)) == 0) {
+ BTM_TRACE_WARNING("%s device is no longer discoverable so discarding advertising packet pkt",
+ __func__);
+ return;
+ }
+ if (!update) {
+ result &= ~BTM_BLE_INQ_RESULT;
+ }
+ /* If the number of responses found and limited, issue a cancel inquiry */
+ if (p_inq->inqparms.max_resps &&
+ p_inq->inq_cmpl_info.num_resp == p_inq->inqparms.max_resps) {
+ /* new device */
+ if (p_i == NULL ||
+ /* assume a DUMO device, BR/EDR inquiry is always active */
+ (p_i &&
+ (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE &&
+ p_i->scan_rsp)) {
+ BTM_TRACE_WARNING("INQ RES: Extra Response Received...cancelling inquiry..");
+
+ /* if is non-periodic inquiry active, cancel now */
+ if ((p_inq->inq_active & BTM_BR_INQ_ACTIVE_MASK) != 0 &&
+ (p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) == 0) {
+ btsnd_hcic_inq_cancel();
+ }
+
+ btm_ble_stop_inquiry();
+
+ btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);
+ }
+ }
+ /* background connection in selective connection mode */
+ if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE) {
+ if (result & BTM_BLE_SEL_CONN_RESULT) {
+ btm_send_sel_conn_callback(bda, evt_type, p, addr_type);
+ } else {
+ BTM_TRACE_DEBUG("None LE device, can not initiate selective connection\n");
+ }
+ } else {
+ if (p_inq_results_cb && (result & BTM_BLE_INQ_RESULT)) {
+ (p_inq_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
+ p_le_inq_cb->adv_len = 0;
+ memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
+ p_i->inq_info.results.adv_data_len = 0;
+ p_i->inq_info.results.scan_rsp_len = 0;
+ }
+ if (p_obs_results_cb && (result & BTM_BLE_OBS_RESULT)) {
+ (p_obs_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
+ p_le_inq_cb->adv_len = 0;
+ memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
+ p_i->inq_info.results.adv_data_len = 0;
+ p_i->inq_info.results.scan_rsp_len = 0;
+ }
+ if (p_scan_results_cb && (result & BTM_BLE_DISCO_RESULT)) {
+ (p_scan_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
+ p_le_inq_cb->adv_len = 0;
+ memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
+ p_i->inq_info.results.adv_data_len = 0;
+ p_i->inq_info.results.scan_rsp_len = 0;
+ }
+ }
+}
+
+void btm_ble_process_adv_discard_evt(UINT8 *p)
+{
+#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE)
+ uint32_t num_dis = 0;
+ STREAM_TO_UINT32 (num_dis, p);
+ tBTM_INQ_DIS_CB *p_obs_discard_cb = btm_cb.ble_ctr_cb.p_obs_discard_cb;
+ if(p_obs_discard_cb) {
+ (p_obs_discard_cb)(num_dis);
+ }
+#endif
+}
+
+void btm_ble_process_direct_adv_pkt(UINT8 *p)
+{
+ // TODO
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_start_scan
+**
+** Description Start the BLE scan.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_start_scan(void)
+{
+ tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
+ tBTM_STATUS status = BTM_CMD_STARTED;
+
+ osi_mutex_lock(&scan_enable_lock, OSI_MUTEX_MAX_TIMEOUT);
+
+ if(p_inq->scan_duplicate_filter > BTM_BLE_DUPLICATE_MAX) {
+ p_inq->scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;
+ }
+ /* start scan, disable duplicate filtering */
+ if (!btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter)) {
+ status = BTM_NO_RESOURCES;
+ } else {
+ osi_sem_take(&scan_enable_sem, OSI_SEM_MAX_TIMEOUT);
+ if(scan_enable_status != BTM_SUCCESS) {
+ status = BTM_NO_RESOURCES;
+ }
+ btm_cb.ble_ctr_cb.inq_var.state |= BTM_BLE_SCANNING;
+ if (p_inq->scan_type == BTM_BLE_SCAN_MODE_ACTI) {
+ btm_ble_set_topology_mask(BTM_BLE_STATE_ACTIVE_SCAN_BIT);
+ } else {
+ btm_ble_set_topology_mask(BTM_BLE_STATE_PASSIVE_SCAN_BIT);
+ }
+ }
+ osi_mutex_unlock(&scan_enable_lock);
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_stop_scan
+**
+** Description Stop the BLE scan.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_stop_scan(void)
+{
+ BTM_TRACE_EVENT ("btm_ble_stop_scan ");
+
+ /* Clear the inquiry callback if set */
+ btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
+ btm_cb.ble_ctr_cb.inq_var.state &= ~BTM_BLE_SCANNING;
+ /* stop discovery now */
+ btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+
+ btm_update_scanner_filter_policy(SP_ADV_ALL);
+
+ btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_SCAN;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_stop_inquiry
+**
+** Description Stop the BLE Inquiry.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_stop_inquiry(void)
+{
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb;
+
+ btu_stop_timer (&p_ble_cb->inq_var.inq_timer_ent);
+
+ p_ble_cb->scan_activity &= ~BTM_BLE_INQUIRY_MASK;
+
+ /* If no more scan activity, stop LE scan now */
+ if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) {
+ btm_ble_stop_scan();
+ } else if ((p_ble_cb->inq_var.scan_interval != BTM_BLE_LOW_LATENCY_SCAN_INT) ||
+ (p_ble_cb->inq_var.scan_window != BTM_BLE_LOW_LATENCY_SCAN_WIN)) {
+ BTM_TRACE_DEBUG("%s: setting default params for ongoing observe", __FUNCTION__);
+ btm_ble_stop_scan();
+ btm_ble_start_scan();
+ }
+
+ /* If we have a callback registered for inquiry complete, call it */
+ BTM_TRACE_DEBUG ("BTM Inq Compl Callback: status 0x%02x, num results %d",
+ p_inq->inq_cmpl_info.status, p_inq->inq_cmpl_info.num_resp);
+
+ btm_process_inq_complete(HCI_SUCCESS, (UINT8)(p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK));
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_stop_observe
+**
+** Description Stop the BLE Observe.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_stop_observe(void)
+{
+ tBTM_BLE_CB *p_ble_cb = & btm_cb.ble_ctr_cb;
+ tBTM_CMPL_CB *p_obs_cb = p_ble_cb->p_obs_cmpl_cb;
+
+ btu_stop_timer (&p_ble_cb->obs_timer_ent);
+
+ p_ble_cb->scan_activity &= ~BTM_LE_OBSERVE_ACTIVE;
+
+ p_ble_cb->p_obs_results_cb = NULL;
+ p_ble_cb->p_obs_cmpl_cb = NULL;
+
+ if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) {
+ btm_ble_stop_scan();
+ }
+
+ if (p_obs_cb) {
+ (p_obs_cb)((tBTM_INQUIRY_CMPL *) &btm_cb.btm_inq_vars.inq_cmpl_info);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_stop_observe
+**
+** Description Stop the BLE Observe.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_stop_discover(void)
+{
+ tBTM_BLE_CB *p_ble_cb = & btm_cb.ble_ctr_cb;
+ tBTM_CMPL_CB *p_scan_cb = p_ble_cb->p_scan_cmpl_cb;
+ btu_stop_timer (&p_ble_cb->scan_timer_ent);
+
+ osi_mutex_lock(&scan_enable_lock, OSI_MUTEX_MAX_TIMEOUT);
+ p_ble_cb->scan_activity &= ~BTM_LE_DISCOVER_ACTIVE;
+
+ p_ble_cb->p_scan_results_cb = NULL;
+ p_ble_cb->p_scan_cmpl_cb = NULL;
+
+ if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) {
+ /* Clear the inquiry callback if set */
+ btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
+ btm_cb.ble_ctr_cb.inq_var.state &= ~BTM_BLE_SCANNING;
+ /* stop discovery now */
+ if(btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE)) {
+ osi_sem_take(&scan_enable_sem, OSI_SEM_MAX_TIMEOUT);
+ }
+ }
+
+ if (p_scan_cb) {
+ (p_scan_cb)((tBTM_INQUIRY_CMPL *) &btm_cb.btm_inq_vars.inq_cmpl_info);
+ }
+ osi_mutex_unlock(&scan_enable_lock);
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_adv_states_operation
+**
+** Description Set or clear adv states in topology mask
+**
+** Returns operation status. TRUE if sucessful, FALSE otherwise.
+**
+*******************************************************************************/
+typedef BOOLEAN (BTM_TOPOLOGY_FUNC_PTR)(tBTM_BLE_STATE_MASK);
+static BOOLEAN btm_ble_adv_states_operation(BTM_TOPOLOGY_FUNC_PTR *p_handler, UINT8 adv_evt)
+{
+ BOOLEAN rt = FALSE;
+
+ switch (adv_evt) {
+ case BTM_BLE_CONNECT_EVT:
+ rt = (*p_handler)(BTM_BLE_STATE_CONN_ADV_BIT);
+ break;
+
+ case BTM_BLE_NON_CONNECT_EVT:
+ rt = (*p_handler) (BTM_BLE_STATE_NON_CONN_ADV_BIT);
+ break;
+ case BTM_BLE_CONNECT_DIR_EVT:
+ rt = (*p_handler) (BTM_BLE_STATE_HI_DUTY_DIR_ADV_BIT);
+ break;
+
+ case BTM_BLE_DISCOVER_EVT:
+ rt = (*p_handler) (BTM_BLE_STATE_SCAN_ADV_BIT);
+ break;
+
+ case BTM_BLE_CONNECT_LO_DUTY_DIR_EVT:
+ rt = (*p_handler) (BTM_BLE_STATE_LO_DUTY_DIR_ADV_BIT);
+ break;
+
+ default:
+ BTM_TRACE_ERROR("unknown adv event : %d", adv_evt);
+ break;
+ }
+
+ return rt;
+}
+
+
+/*******************************************************************************
+**
+** Function btm_ble_start_adv
+**
+** Description start the BLE advertising.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_start_adv(void)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ tBTM_STATUS rt = BTM_NO_RESOURCES;
+ BTM_TRACE_EVENT ("btm_ble_start_adv\n");
+
+
+ if (!btm_ble_adv_states_operation (btm_ble_topology_check, p_cb->evt_type)) {
+ return BTM_WRONG_MODE;
+ }
+
+ osi_mutex_lock(&adv_enable_lock, OSI_MUTEX_MAX_TIMEOUT);
+
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+ /* To relax resolving list, always have resolving list enabled, unless directed adv */
+ if (p_cb->evt_type != BTM_BLE_CONNECT_LO_DUTY_DIR_EVT &&
+ p_cb->evt_type != BTM_BLE_CONNECT_DIR_EVT)
+ /* enable resolving list is desired */
+ {
+ //btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_ADV);
+ }
+#endif
+ if (p_cb->afp != AP_SCAN_CONN_ALL) {
+ //find the device in the btm dev buffer and write it to the controller white list
+ btm_execute_wl_dev_operation();
+ btm_cb.ble_ctr_cb.wl_state |= BTM_BLE_WL_ADV;
+ }
+ /* The complete event comes up immediately after the 'btsnd_hcic_ble_set_adv_enable' being called in dual core,
+ this causes the 'adv_mode' and 'state' not be set yet, so we set the state first */
+ tBTM_BLE_GAP_STATE temp_state = p_cb->state;
+ UINT8 adv_mode = p_cb->adv_mode;
+ p_cb->adv_mode = BTM_BLE_ADV_ENABLE;
+ p_cb->state |= BTM_BLE_ADVERTISING;
+ btm_ble_adv_states_operation(btm_ble_set_topology_mask, p_cb->evt_type);
+ if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE)) {
+ osi_sem_take(&adv_enable_sem, OSI_SEM_MAX_TIMEOUT);
+ rt = adv_enable_status;
+ BTM_TRACE_EVENT ("BTM_SUCCESS\n");
+ } else {
+ p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
+ p_cb->state = temp_state;
+ p_cb->adv_mode = adv_mode;
+ btm_ble_adv_states_operation(btm_ble_clear_topology_mask, p_cb->evt_type);
+ btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_ADV;
+ }
+
+ if(adv_enable_status != HCI_SUCCESS) {
+ p_cb->adv_mode = adv_mode;
+ }
+ osi_mutex_unlock(&adv_enable_lock);
+ return rt;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_stop_adv
+**
+** Description Stop the BLE advertising.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_stop_adv(void)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ tBTM_STATUS rt = BTM_SUCCESS;
+ if (p_cb) {
+ osi_mutex_lock(&adv_enable_lock, OSI_MUTEX_MAX_TIMEOUT);
+ UINT8 temp_adv_mode = p_cb->adv_mode;
+ BOOLEAN temp_fast_adv_on = p_cb->fast_adv_on;
+ tBTM_BLE_GAP_STATE temp_state = p_cb->state;
+ tBTM_BLE_WL_STATE temp_wl_state = btm_cb.ble_ctr_cb.wl_state;
+ tBTM_BLE_STATE_MASK temp_mask = btm_ble_get_topology_mask ();
+
+ p_cb->fast_adv_on = FALSE;
+ p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
+ p_cb->state &= ~BTM_BLE_ADVERTISING;
+ btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_ADV;
+
+ /* clear all adv states */
+ btm_ble_clear_topology_mask (BTM_BLE_STATE_ALL_ADV_MASK);
+
+ if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE)) {
+ osi_sem_take(&adv_enable_sem, OSI_SEM_MAX_TIMEOUT);
+ rt = adv_enable_status;
+ } else {
+ // reset state
+ p_cb->fast_adv_on = temp_fast_adv_on;
+ p_cb->adv_mode = temp_adv_mode;
+ p_cb->state = temp_state;
+ btm_cb.ble_ctr_cb.wl_state = temp_wl_state;
+ btm_ble_set_topology_mask (temp_mask);
+
+ rt = BTM_NO_RESOURCES;
+ }
+ if(adv_enable_status != HCI_SUCCESS) {
+ p_cb->adv_mode = temp_adv_mode;
+ }
+ osi_mutex_unlock(&adv_enable_lock);
+ }
+ return rt;
+}
+
+tBTM_STATUS btm_ble_set_random_addr(BD_ADDR random_bda)
+{
+ tBTM_STATUS rt = BTM_SUCCESS;
+
+ osi_mutex_lock(&adv_enable_lock, OSI_MUTEX_MAX_TIMEOUT);
+ osi_mutex_lock(&scan_enable_lock, OSI_MUTEX_MAX_TIMEOUT);
+
+ if (btm_cb.ble_ctr_cb.inq_var.adv_mode == BTM_BLE_ADV_ENABLE) {
+ if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE)) {
+ osi_sem_take(&adv_enable_sem, OSI_SEM_MAX_TIMEOUT);
+ rt = adv_enable_status;
+ } else {
+ rt = BTM_BAD_VALUE_RET;
+ }
+ }
+
+ if (BTM_BLE_IS_DISCO_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
+ if (btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_SCAN_DUPLICATE_DISABLE)) {
+ osi_sem_take(&scan_enable_sem, OSI_SEM_MAX_TIMEOUT);
+ rt = scan_enable_status;
+ } else {
+ rt = BTM_BAD_VALUE_RET;
+ }
+ }
+
+ if (rt == BTM_SUCCESS) {
+ btsnd_hcic_ble_set_random_addr(random_bda);
+ }
+
+ if (btm_cb.ble_ctr_cb.inq_var.adv_mode == BTM_BLE_ADV_ENABLE) {
+ if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE)) {
+ osi_sem_take(&adv_enable_sem, OSI_SEM_MAX_TIMEOUT);
+ rt = adv_enable_status;
+ } else {
+ rt = BTM_BAD_VALUE_RET;
+ }
+ }
+
+ if (BTM_BLE_IS_DISCO_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
+ if (btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, btm_cb.ble_ctr_cb.inq_var.scan_duplicate_filter)) {
+ osi_sem_take(&scan_enable_sem, OSI_SEM_MAX_TIMEOUT);
+ rt = scan_enable_status;
+ } else {
+ rt = BTM_BAD_VALUE_RET;
+ }
+ }
+
+ osi_mutex_unlock(&adv_enable_lock);
+ osi_mutex_unlock(&scan_enable_lock);
+
+ return rt;
+}
+
+
+/*******************************************************************************
+**
+** Function btm_ble_start_slow_adv
+**
+** Description Restart adv with slow adv interval
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_start_slow_adv (void)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) {
+ tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ BD_ADDR p_addr_ptr = {0};
+ tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC;
+ tBLE_ADDR_TYPE own_addr_type = p_addr_cb->own_addr_type;
+
+ btm_ble_stop_adv();
+
+ p_cb->evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &init_addr_type,
+ &own_addr_type);
+
+ /* slow adv mode never goes into directed adv */
+ btsnd_hcic_ble_write_adv_params (BTM_BLE_GAP_ADV_SLOW_INT, BTM_BLE_GAP_ADV_SLOW_INT,
+ p_cb->evt_type, own_addr_type,
+ init_addr_type, p_addr_ptr,
+ p_cb->adv_chnl_map, p_cb->afp);
+
+ btm_ble_start_adv();
+ }
+}
+/*******************************************************************************
+**
+** Function btm_ble_timeout
+**
+** Description Called when BTM BLE inquiry timer expires
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_timeout(TIMER_LIST_ENT *p_tle)
+{
+ BTM_TRACE_EVENT ("btm_ble_timeout");
+
+ switch (p_tle->event) {
+ case BTU_TTYPE_BLE_OBSERVE:
+ btm_ble_stop_observe();
+ break;
+ case BTU_TTYPE_BLE_SCAN:
+ btm_ble_stop_discover();
+ break;
+ case BTU_TTYPE_BLE_INQUIRY:
+ btm_ble_stop_inquiry();
+ break;
+
+ case BTU_TTYPE_BLE_GAP_LIM_DISC:
+ /* lim_timeout expiried, limited discovery should exit now */
+ btm_cb.btm_inq_vars.discoverable_mode &= ~BTM_BLE_LIMITED_DISCOVERABLE;
+ btm_ble_set_adv_flag(btm_cb.btm_inq_vars.connectable_mode, btm_cb.btm_inq_vars.discoverable_mode);
+ break;
+
+ case BTU_TTYPE_BLE_RANDOM_ADDR:
+ if (btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type == BLE_ADDR_RANDOM) {
+ if (NULL == (void *)(p_tle->param)) {
+#if (CONTROLLER_RPA_LIST_ENABLE == FALSE)
+ /* refresh the random addr */
+ btm_gen_resolvable_private_addr((void *)btm_gen_resolve_paddr_low);
+#endif
+ } else {
+ if (BTM_BleMaxMultiAdvInstanceCount() > 0) {
+ btm_ble_multi_adv_configure_rpa((tBTM_BLE_MULTI_ADV_INST *)p_tle->param);
+ }
+ }
+ }
+ break;
+
+ case BTU_TTYPE_BLE_GAP_FAST_ADV:
+ /* fast adv is completed, fall back to slow adv interval */
+ btm_ble_start_slow_adv();
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_ble_read_remote_features_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the read LE remote feature supported
+** complete event.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_read_remote_features_complete(UINT8 *p)
+{
+ tACL_CONN *p_acl_cb = NULL;
+ UINT16 handle;
+ UINT8 status;
+
+ BTM_TRACE_EVENT ("btm_ble_read_remote_features_complete ");
+
+ STREAM_TO_UINT8(status, p);
+
+ // if LE read remote feature failed for HCI_ERR_CONN_FAILED_ESTABLISHMENT,
+ // expect disconnect complete to be received
+ if (status != HCI_ERR_CONN_FAILED_ESTABLISHMENT) {
+ STREAM_TO_UINT16 (handle, p);
+
+ /* Look up the connection by handle and copy features */
+ p_acl_cb = btm_handle_to_acl(handle);
+ if (p_acl_cb) {
+ {
+ STREAM_TO_ARRAY(p_acl_cb->peer_le_features, p, BD_FEATURES_LEN);
+#if BLE_INCLUDED == TRUE
+ /* In the original Bluedroid version, slave need to send LL_VERSION_IND(call btsnd_hcic_rmt_ver_req)
+ * to remote device if it has not received ll_version_ind.
+ * Delete it to resolve Android 7.0 incompatible problem. But it may cause that slave host
+ * can't get remote device's version.*/
+ if (p_acl_cb->link_role == HCI_ROLE_MASTER){
+ btsnd_hcic_rmt_ver_req (p_acl_cb->hci_handle);
+ }
+ else{
+ uint16_t data_length = controller_get_interface()->get_ble_default_data_packet_length();
+ uint16_t data_txtime = controller_get_interface()->get_ble_default_data_packet_txtime();
+ if (p_acl_cb->transport == BT_TRANSPORT_LE) {
+ if (HCI_LE_DATA_LEN_EXT_SUPPORTED(p_acl_cb->peer_le_features) &&
+ (p_acl_cb->data_length_params.tx_len != data_length)) {
+ p_acl_cb->data_len_updating = true;
+ btsnd_hcic_ble_set_data_length(p_acl_cb->hci_handle, data_length, data_txtime);
+ }
+ l2cble_notify_le_connection (p_acl_cb->remote_addr);
+ }
+ }
+#endif
+ }
+ }
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_write_adv_enable_complete
+**
+** Description This function process the write adv enable command complete.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_write_adv_enable_complete(UINT8 *p)
+{
+ /* if write adv enable/disbale not succeed */
+ if (*p != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("%s failed", __func__);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_dir_adv_tout
+**
+** Description when directed adv time out
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_dir_adv_tout(void)
+{
+ btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+
+ /* make device fall back into undirected adv mode by default */
+ btm_cb.ble_ctr_cb.inq_var.directed_conn = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_set_topology_mask
+**
+** Description set BLE topology mask
+**
+** Returns TRUE is request is allowed, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_set_topology_mask(tBTM_BLE_STATE_MASK request_state_mask)
+{
+ request_state_mask &= BTM_BLE_STATE_ALL_MASK;
+ btm_cb.ble_ctr_cb.cur_states |= (request_state_mask & BTM_BLE_STATE_ALL_MASK);
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_clear_topology_mask
+**
+** Description Clear BLE topology bit mask
+**
+** Returns TRUE is request is allowed, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_clear_topology_mask (tBTM_BLE_STATE_MASK request_state_mask)
+{
+ request_state_mask &= BTM_BLE_STATE_ALL_MASK;
+ btm_cb.ble_ctr_cb.cur_states &= ~request_state_mask;
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_get_topology_mask
+**
+** Description Get BLE topology bit mask
+**
+** Returns state mask.
+**
+*******************************************************************************/
+tBTM_BLE_STATE_MASK btm_ble_get_topology_mask (void)
+{
+ return btm_cb.ble_ctr_cb.cur_states;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_update_link_topology_mask
+**
+** Description This function update the link topology mask
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_update_link_topology_mask(UINT8 link_role, BOOLEAN increase)
+{
+ btm_ble_clear_topology_mask (BTM_BLE_STATE_ALL_CONN_MASK);
+
+ if (increase) {
+ btm_cb.ble_ctr_cb.link_count[link_role]++;
+ } else if (btm_cb.ble_ctr_cb.link_count[link_role] > 0) {
+ btm_cb.ble_ctr_cb.link_count[link_role]--;
+ }
+
+ if (btm_cb.ble_ctr_cb.link_count[HCI_ROLE_MASTER]) {
+ btm_ble_set_topology_mask (BTM_BLE_STATE_MASTER_BIT);
+ }
+
+ if (btm_cb.ble_ctr_cb.link_count[HCI_ROLE_SLAVE]) {
+ btm_ble_set_topology_mask(BTM_BLE_STATE_SLAVE_BIT);
+ }
+
+ if (link_role == HCI_ROLE_SLAVE && increase) {
+ btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+ /* make device fall back into undirected adv mode by default */
+ btm_cb.ble_ctr_cb.inq_var.directed_conn = BTM_BLE_CONNECT_EVT;
+ /* clear all adv states */
+ btm_ble_clear_topology_mask(BTM_BLE_STATE_ALL_ADV_MASK);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_update_mode_operation
+**
+** Description This function update the GAP role operation when a link status
+** is updated.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN btm_ble_update_mode_operation(UINT8 link_role, BD_ADDR bd_addr, UINT8 status)
+{
+ BOOLEAN bg_con = FALSE;
+ if (status == HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT) {
+ btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+ /* make device fall back into undirected adv mode by default */
+ btm_cb.ble_ctr_cb.inq_var.directed_conn = BTM_BLE_CONNECT_EVT;
+ /* clear all adv states */
+ btm_ble_clear_topology_mask (BTM_BLE_STATE_ALL_ADV_MASK);
+ }
+
+ if (btm_cb.ble_ctr_cb.inq_var.connectable_mode == BTM_BLE_CONNECTABLE) {
+ btm_ble_set_connectability(btm_cb.btm_inq_vars.connectable_mode |
+ btm_cb.ble_ctr_cb.inq_var.connectable_mode);
+ }
+
+ /* when no connection is attempted, and controller is not rejecting last request
+ due to resource limitation, start next direct connection or background connection
+ now in order */
+ if (btm_ble_get_conn_st() == BLE_CONN_IDLE && status != HCI_ERR_HOST_REJECT_RESOURCES &&
+ !btm_send_pending_direct_conn()) {
+ bg_con = btm_ble_resume_bg_conn();
+ }
+
+ return bg_con;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_init
+**
+** Description Initialize the control block variable values.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_init (void)
+{
+ BTM_TRACE_DEBUG("%s", __func__);
+
+#if BTM_DYNAMIC_MEMORY == TRUE
+ cmn_ble_gap_vsc_cb_ptr = (tBTM_BLE_VSC_CB *)osi_malloc(sizeof(tBTM_BLE_VSC_CB));
+ if (cmn_ble_gap_vsc_cb_ptr == NULL) {
+ BTM_TRACE_ERROR("%s malloc failed", __func__);
+ return;
+ }
+#endif
+
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+
+ btu_free_timer(&p_cb->obs_timer_ent);
+ btu_free_timer(&p_cb->scan_timer_ent);
+ btu_free_timer(&p_cb->inq_var.fast_adv_timer);
+ memset(p_cb, 0, sizeof(tBTM_BLE_CB));
+ memset(&(btm_cb.cmn_ble_vsc_cb), 0 , sizeof(tBTM_BLE_VSC_CB));
+ btm_cb.cmn_ble_vsc_cb.values_read = FALSE;
+ p_cb->cur_states = 0;
+
+ p_cb->conn_pending_q = fixed_queue_new(QUEUE_SIZE_MAX);
+
+ p_cb->inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+ p_cb->inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
+ p_cb->inq_var.adv_chnl_map = BTM_BLE_DEFAULT_ADV_CHNL_MAP;
+ p_cb->inq_var.afp = BTM_BLE_DEFAULT_AFP;
+ p_cb->inq_var.sfp = BTM_BLE_DEFAULT_SFP;
+ p_cb->inq_var.connectable_mode = BTM_BLE_NON_CONNECTABLE;
+ p_cb->inq_var.discoverable_mode = BTM_BLE_NON_DISCOVERABLE;
+
+ /* for background connection, reset connection params to be undefined */
+ p_cb->scan_int = p_cb->scan_win = BTM_BLE_SCAN_PARAM_UNDEF;
+
+ p_cb->inq_var.evt_type = BTM_BLE_NON_CONNECT_EVT;
+
+ p_cb->adv_rpt_queue = pkt_queue_create();
+ assert(p_cb->adv_rpt_queue != NULL);
+
+ p_cb->adv_rpt_ready = osi_event_create(btm_adv_pkt_handler, NULL);
+ assert(p_cb->adv_rpt_ready != NULL);
+ osi_event_bind(p_cb->adv_rpt_ready, btu_get_current_thread(), 0);
+
+#if BLE_VND_INCLUDED == FALSE
+ btm_ble_adv_filter_init();
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_free
+**
+** Description free the control block variable values.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_free (void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+
+ BTM_TRACE_DEBUG("%s", __func__);
+
+ fixed_queue_free(p_cb->conn_pending_q, osi_free_func);
+
+ pkt_queue_destroy(p_cb->adv_rpt_queue, NULL);
+ p_cb->adv_rpt_queue = NULL;
+
+ osi_event_delete(p_cb->adv_rpt_ready);
+ p_cb->adv_rpt_ready = NULL;
+
+#if BTM_DYNAMIC_MEMORY == TRUE
+ osi_free(cmn_ble_gap_vsc_cb_ptr);
+ cmn_ble_gap_vsc_cb_ptr = NULL;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_topology_check
+**
+** Description check to see requested state is supported. One state check at
+** a time is supported
+**
+** Returns TRUE is request is allowed, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_topology_check(tBTM_BLE_STATE_MASK request_state_mask)
+{
+ BOOLEAN rt = FALSE;
+
+ UINT8 state_offset = 0;
+ UINT16 cur_states = btm_cb.ble_ctr_cb.cur_states;
+ UINT8 mask, offset;
+ UINT8 request_state = 0;
+
+ /* check only one bit is set and within valid range */
+ if (request_state_mask == BTM_BLE_STATE_INVALID ||
+ request_state_mask > BTM_BLE_STATE_SCAN_ADV_BIT ||
+ (request_state_mask & (request_state_mask - 1 )) != 0) {
+ BTM_TRACE_ERROR("illegal state requested: %d", request_state_mask);
+ return rt;
+ }
+
+ while (request_state_mask) {
+ request_state_mask >>= 1;
+ request_state ++;
+ }
+
+ /* check if the requested state is supported or not */
+ mask = btm_le_state_combo_tbl[0][request_state - 1][0];
+ offset = btm_le_state_combo_tbl[0][request_state - 1][1];
+
+ const uint8_t *ble_supported_states = controller_get_interface()->get_ble_supported_states();
+
+ if (!BTM_LE_STATES_SUPPORTED(ble_supported_states, mask, offset)) {
+ BTM_TRACE_ERROR("state requested not supported: %d", request_state);
+ return rt;
+ }
+
+ rt = TRUE;
+ /* make sure currently active states are all supported in conjunction with the requested
+ state. If the bit in table is not set, the combination is not supported */
+ while (cur_states != 0) {
+ if (cur_states & 0x01) {
+ mask = btm_le_state_combo_tbl[request_state][state_offset][0];
+ offset = btm_le_state_combo_tbl[request_state][state_offset][1];
+
+ if (mask != 0 && offset != 0) {
+ if (!BTM_LE_STATES_SUPPORTED(ble_supported_states, mask, offset)) {
+ rt = FALSE;
+ break;
+ }
+ }
+ }
+ cur_states >>= 1;
+ state_offset ++;
+ }
+ return rt;
+}
+
+/*******************************************************************************
+ **
+ ** Function BTM_Ble_Authorization
+ **
+ ** Description This function is used to authorize a specified device
+ **
+ ** Returns TRUE or FALSE
+ **
+ *******************************************************************************/
+BOOLEAN BTM_Ble_Authorization(BD_ADDR bd_addr, BOOLEAN authorize)
+{
+ if (bd_addr == NULL) {
+ BTM_TRACE_ERROR("bd_addr is NULL");
+ return FALSE;
+ }
+
+ if (btm_sec_dev_authorization(bd_addr, authorize)) {
+ return TRUE;
+ }
+
+ BTM_TRACE_ERROR("Authorization fail");
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleClearAdv
+**
+** Description This function is called to clear legacy advertising
+**
+** Parameter p_clear_adv_cback - Command complete callback
+**
+*******************************************************************************/
+BOOLEAN BTM_BleClearAdv(tBTM_CLEAR_ADV_CMPL_CBACK *p_clear_adv_cback)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+
+ if (btsnd_hcic_ble_clear_adv() == FALSE) {
+ BTM_TRACE_ERROR("%s: Unable to Clear Advertising", __FUNCTION__);
+ return FALSE;
+ }
+
+ p_cb->inq_var.p_clear_adv_cb = p_clear_adv_cback;
+ return TRUE;
+}
+
+bool btm_ble_adv_pkt_ready(void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ osi_thread_post_event(p_cb->adv_rpt_ready, OSI_THREAD_MAX_TIMEOUT);
+
+ return true;
+}
+
+bool btm_ble_adv_pkt_post(pkt_linked_item_t *pkt)
+{
+ if (pkt == NULL) {
+ return false;
+ }
+
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ pkt_queue_enqueue(p_cb->adv_rpt_queue, pkt);
+ return true;
+}
+#endif /* BLE_INCLUDED */
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_ble_multi_adv.c b/lib/bt/host/bluedroid/stack/btm/btm_ble_multi_adv.c
new file mode 100644
index 00000000..443dd64e
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_ble_multi_adv.c
@@ -0,0 +1,878 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 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 "device/controller.h"
+
+#if (BLE_INCLUDED == TRUE)
+#include "stack/bt_types.h"
+#include "stack/hcimsgs.h"
+#include "stack/btu.h"
+#include "btm_int.h"
+//#include "bt_utils.h"
+#include "stack/hcidefs.h"
+#include "stack/btm_ble_api.h"
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+/* length of each multi adv sub command */
+#define BTM_BLE_MULTI_ADV_ENB_LEN 3
+#define BTM_BLE_MULTI_ADV_SET_PARAM_LEN 24
+#define BTM_BLE_MULTI_ADV_WRITE_DATA_LEN (BTM_BLE_AD_DATA_LEN + 3)
+#define BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN 8
+
+#define BTM_BLE_MULTI_ADV_CB_EVT_MASK 0xF0
+#define BTM_BLE_MULTI_ADV_SUBCODE_MASK 0x0F
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+#if BTM_DYNAMIC_MEMORY == FALSE
+tBTM_BLE_MULTI_ADV_CB btm_multi_adv_cb;
+tBTM_BLE_MULTI_ADV_INST_IDX_Q btm_multi_adv_idx_q;
+#else
+tBTM_BLE_MULTI_ADV_CB *btm_multi_adv_cb_ptr;
+tBTM_BLE_MULTI_ADV_INST_IDX_Q *btm_multi_adv_idx_q_ptr;
+#define btm_multi_adv_cb (*btm_multi_adv_cb_ptr)
+#define btm_multi_adv_idx_q (*btm_multi_adv_idx_q_ptr)
+#endif
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+extern void btm_ble_update_dmt_flag_bits(UINT8 *flag_value,
+ const UINT16 connect_mode, const UINT16 disc_mode);
+
+/*******************************************************************************
+**
+** Function btm_ble_multi_adv_enq_op_q
+**
+** Description enqueue a multi adv operation in q to check command complete
+** status.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_multi_adv_enq_op_q(UINT8 opcode, UINT8 inst_id, UINT8 cb_evt)
+{
+ tBTM_BLE_MULTI_ADV_OPQ *p_op_q = &btm_multi_adv_cb.op_q;
+
+ p_op_q->p_inst_id[p_op_q->next_idx] = inst_id;
+
+ p_op_q->p_sub_code[p_op_q->next_idx] = (opcode | (cb_evt << 4));
+
+ p_op_q->next_idx = (p_op_q->next_idx + 1) % BTM_BleMaxMultiAdvInstanceCount();
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_multi_adv_deq_op_q
+**
+** Description dequeue a multi adv operation from q when command complete
+** is received.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_multi_adv_deq_op_q(UINT8 *p_opcode, UINT8 *p_inst_id, UINT8 *p_cb_evt)
+{
+ tBTM_BLE_MULTI_ADV_OPQ *p_op_q = &btm_multi_adv_cb.op_q;
+
+ *p_inst_id = p_op_q->p_inst_id[p_op_q->pending_idx] & 0x7F;
+ *p_cb_evt = (p_op_q->p_sub_code[p_op_q->pending_idx] >> 4);
+ *p_opcode = (p_op_q->p_sub_code[p_op_q->pending_idx] & BTM_BLE_MULTI_ADV_SUBCODE_MASK);
+
+ p_op_q->pending_idx = (p_op_q->pending_idx + 1) % BTM_BleMaxMultiAdvInstanceCount();
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_multi_adv_vsc_cmpl_cback
+**
+** Description Multi adv VSC complete callback
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_multi_adv_vsc_cmpl_cback (tBTM_VSC_CMPL *p_params)
+{
+ UINT8 status, subcode;
+ UINT8 *p = p_params->p_param_buf, inst_id;
+ UINT16 len = p_params->param_len;
+ tBTM_BLE_MULTI_ADV_INST *p_inst ;
+ UINT8 cb_evt = 0, opcode;
+
+ if (len < 2) {
+ BTM_TRACE_ERROR("wrong length for btm_ble_multi_adv_vsc_cmpl_cback");
+ return;
+ }
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT8(subcode, p);
+
+ btm_ble_multi_adv_deq_op_q(&opcode, &inst_id, &cb_evt);
+
+ BTM_TRACE_DEBUG("op_code = %02x inst_id = %d cb_evt = %02x", opcode, inst_id, cb_evt);
+
+ if (opcode != subcode || inst_id == 0) {
+ BTM_TRACE_ERROR("get unexpected VSC cmpl, expect: %d get: %d", subcode, opcode);
+ return;
+ }
+
+ p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1];
+
+ switch (subcode) {
+ case BTM_BLE_MULTI_ADV_ENB: {
+ BTM_TRACE_DEBUG("BTM_BLE_MULTI_ADV_ENB status = %d", status);
+
+ /* Mark as not in use here, if instance cannot be enabled */
+ if (HCI_SUCCESS != status && BTM_BLE_MULTI_ADV_ENB_EVT == cb_evt) {
+ btm_multi_adv_cb.p_adv_inst[inst_id - 1].in_use = FALSE;
+ }
+ break;
+ }
+
+ case BTM_BLE_MULTI_ADV_SET_PARAM: {
+ BTM_TRACE_DEBUG("BTM_BLE_MULTI_ADV_SET_PARAM status = %d", status);
+ break;
+ }
+
+ case BTM_BLE_MULTI_ADV_WRITE_ADV_DATA: {
+ BTM_TRACE_DEBUG("BTM_BLE_MULTI_ADV_WRITE_ADV_DATA status = %d", status);
+ break;
+ }
+
+ case BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA: {
+ BTM_TRACE_DEBUG("BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA status = %d", status);
+ break;
+ }
+
+ case BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR: {
+ BTM_TRACE_DEBUG("BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR status = %d", status);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if (cb_evt != 0 && p_inst->p_cback != NULL) {
+ (p_inst->p_cback)(cb_evt, inst_id, p_inst->p_ref, status);
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_enable_multi_adv
+**
+** Description This function enable the customer specific feature in controller
+**
+** Parameters enable: enable or disable
+** inst_id: adv instance ID, can not be 0
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_enable_multi_adv (BOOLEAN enable, UINT8 inst_id, UINT8 cb_evt)
+{
+ UINT8 param[BTM_BLE_MULTI_ADV_ENB_LEN], *pp;
+ UINT8 enb = enable ? 1 : 0;
+ tBTM_STATUS rt;
+
+ pp = param;
+ memset(param, 0, BTM_BLE_MULTI_ADV_ENB_LEN);
+
+ UINT8_TO_STREAM (pp, BTM_BLE_MULTI_ADV_ENB);
+ UINT8_TO_STREAM (pp, enb);
+ UINT8_TO_STREAM (pp, inst_id);
+
+ BTM_TRACE_EVENT (" btm_ble_enable_multi_adv: enb %d, Inst ID %d", enb, inst_id);
+
+ if ((rt = BTM_VendorSpecificCommand (HCI_BLE_MULTI_ADV_OCF,
+ BTM_BLE_MULTI_ADV_ENB_LEN,
+ param,
+ btm_ble_multi_adv_vsc_cmpl_cback))
+ == BTM_CMD_STARTED) {
+ btm_ble_multi_adv_enq_op_q(BTM_BLE_MULTI_ADV_ENB, inst_id, cb_evt);
+ }
+ return rt;
+}
+/*******************************************************************************
+**
+** Function btm_ble_map_adv_tx_power
+**
+** Description return the actual power in dBm based on the mapping in config file
+**
+** Parameters advertise parameters used for this instance.
+**
+** Returns tx power in dBm
+**
+*******************************************************************************/
+static const int btm_ble_tx_power[BTM_BLE_ADV_TX_POWER_MAX + 1] = BTM_BLE_ADV_TX_POWER;
+char btm_ble_map_adv_tx_power(int tx_power_index)
+{
+ if (0 <= tx_power_index && tx_power_index <= BTM_BLE_ADV_TX_POWER_MAX) {
+ return (char)btm_ble_tx_power[tx_power_index];
+ }
+ return 0;
+}
+/*******************************************************************************
+**
+** Function btm_ble_multi_adv_set_params
+**
+** Description This function enable the customer specific feature in controller
+**
+** Parameters advertise parameters used for this instance.
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_multi_adv_set_params (tBTM_BLE_MULTI_ADV_INST *p_inst,
+ tBTM_BLE_ADV_PARAMS *p_params,
+ UINT8 cb_evt)
+{
+ UINT8 param[BTM_BLE_MULTI_ADV_SET_PARAM_LEN], *pp;
+ tBTM_STATUS rt;
+ BD_ADDR dummy = {0, 0, 0, 0, 0, 0};
+
+ pp = param;
+ memset(param, 0, BTM_BLE_MULTI_ADV_SET_PARAM_LEN);
+
+ UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_SET_PARAM);
+
+ UINT16_TO_STREAM (pp, p_params->adv_int_min);
+ UINT16_TO_STREAM (pp, p_params->adv_int_max);
+ UINT8_TO_STREAM (pp, p_params->adv_type);
+
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+ if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) {
+ UINT8_TO_STREAM (pp, BLE_ADDR_RANDOM);
+ BDADDR_TO_STREAM (pp, p_inst->rpa);
+ } else
+#endif
+ {
+ UINT8_TO_STREAM (pp, BLE_ADDR_PUBLIC);
+ BDADDR_TO_STREAM (pp, controller_get_interface()->get_address()->address);
+ }
+
+ BTM_TRACE_EVENT (" btm_ble_multi_adv_set_params,Min %d, Max %d,adv_type %d",
+ p_params->adv_int_min, p_params->adv_int_max, p_params->adv_type);
+
+ UINT8_TO_STREAM (pp, 0);
+ BDADDR_TO_STREAM (pp, dummy);
+
+ if (p_params->channel_map == 0 || p_params->channel_map > BTM_BLE_DEFAULT_ADV_CHNL_MAP) {
+ p_params->channel_map = BTM_BLE_DEFAULT_ADV_CHNL_MAP;
+ }
+ UINT8_TO_STREAM (pp, p_params->channel_map);
+
+ if (p_params->adv_filter_policy >= AP_SCAN_CONN_POLICY_MAX) {
+ p_params->adv_filter_policy = AP_SCAN_CONN_ALL;
+ }
+ UINT8_TO_STREAM (pp, p_params->adv_filter_policy);
+
+ UINT8_TO_STREAM (pp, p_inst->inst_id);
+
+ if (p_params->tx_power > BTM_BLE_ADV_TX_POWER_MAX) {
+ p_params->tx_power = BTM_BLE_ADV_TX_POWER_MAX;
+ }
+ UINT8_TO_STREAM (pp, btm_ble_map_adv_tx_power(p_params->tx_power));
+
+ BTM_TRACE_EVENT("set_params:Chnl Map %d,adv_fltr policy %d,ID:%d, TX Power%d",
+ p_params->channel_map, p_params->adv_filter_policy, p_inst->inst_id, p_params->tx_power);
+
+ if ((rt = BTM_VendorSpecificCommand (HCI_BLE_MULTI_ADV_OCF,
+ BTM_BLE_MULTI_ADV_SET_PARAM_LEN,
+ param,
+ btm_ble_multi_adv_vsc_cmpl_cback))
+ == BTM_CMD_STARTED) {
+ p_inst->adv_evt = p_params->adv_type;
+
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+ if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) {
+ /* start timer */
+ p_inst->raddr_timer_ent.param = (TIMER_PARAM_TYPE) p_inst;
+ btu_start_timer_oneshot(&p_inst->raddr_timer_ent, BTU_TTYPE_BLE_RANDOM_ADDR,
+ BTM_BLE_PRIVATE_ADDR_INT);
+ }
+#endif
+ btm_ble_multi_adv_enq_op_q(BTM_BLE_MULTI_ADV_SET_PARAM, p_inst->inst_id, cb_evt);
+ }
+ return rt;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_multi_adv_write_rpa
+**
+** Description This function write the random address for the adv instance into
+** controller
+**
+** Parameters
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_multi_adv_write_rpa (tBTM_BLE_MULTI_ADV_INST *p_inst, BD_ADDR random_addr)
+{
+ UINT8 param[BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN], *pp = param;
+ tBTM_STATUS rt;
+
+ BTM_TRACE_EVENT ("%s-BD_ADDR:%02x-%02x-%02x-%02x-%02x-%02x,inst_id:%d",
+ __FUNCTION__, random_addr[5], random_addr[4], random_addr[3], random_addr[2],
+ random_addr[1], random_addr[0], p_inst->inst_id);
+
+ memset(param, 0, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN);
+
+ UINT8_TO_STREAM (pp, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR);
+ BDADDR_TO_STREAM(pp, random_addr);
+ UINT8_TO_STREAM(pp, p_inst->inst_id);
+
+ if ((rt = BTM_VendorSpecificCommand (HCI_BLE_MULTI_ADV_OCF,
+ BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN,
+ param,
+ btm_ble_multi_adv_vsc_cmpl_cback)) == BTM_CMD_STARTED) {
+ /* start a periodical timer to refresh random addr */
+ btu_stop_timer_oneshot(&p_inst->raddr_timer_ent);
+ p_inst->raddr_timer_ent.param = (TIMER_PARAM_TYPE) p_inst;
+ btu_start_timer_oneshot(&p_inst->raddr_timer_ent, BTU_TTYPE_BLE_RANDOM_ADDR,
+ BTM_BLE_PRIVATE_ADDR_INT);
+
+ btm_ble_multi_adv_enq_op_q(BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR, p_inst->inst_id, 0);
+ }
+ return rt;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_multi_adv_gen_rpa_cmpl
+**
+** Description RPA generation completion callback for each adv instance. Will
+** continue write the new RPA into controller.
+**
+** Returns none.
+**
+*******************************************************************************/
+void btm_ble_multi_adv_gen_rpa_cmpl(tBTM_RAND_ENC *p)
+{
+#if (SMP_INCLUDED == TRUE)
+ tSMP_ENC output;
+ UINT8 index = 0;
+ tBTM_BLE_MULTI_ADV_INST *p_inst = NULL;
+
+ /* Retrieve the index of adv instance from stored Q */
+ if (btm_multi_adv_idx_q.front == -1) {
+ BTM_TRACE_ERROR(" %s can't locate advertise instance", __FUNCTION__);
+ return;
+ } else {
+ index = btm_multi_adv_idx_q.inst_index_queue[btm_multi_adv_idx_q.front];
+ if (btm_multi_adv_idx_q.front == btm_multi_adv_idx_q.rear) {
+ btm_multi_adv_idx_q.front = -1;
+ btm_multi_adv_idx_q.rear = -1;
+ } else {
+ btm_multi_adv_idx_q.front = (btm_multi_adv_idx_q.front + 1) % BTM_BLE_MULTI_ADV_MAX;
+ }
+ }
+
+ p_inst = &(btm_multi_adv_cb.p_adv_inst[index]);
+
+ BTM_TRACE_EVENT ("btm_ble_multi_adv_gen_rpa_cmpl inst_id = %d", p_inst->inst_id);
+ if (p) {
+ p->param_buf[2] &= (~BLE_RESOLVE_ADDR_MASK);
+ p->param_buf[2] |= BLE_RESOLVE_ADDR_MSB;
+
+ p_inst->rpa[2] = p->param_buf[0];
+ p_inst->rpa[1] = p->param_buf[1];
+ p_inst->rpa[0] = p->param_buf[2];
+
+ if (!SMP_Encrypt(btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN, p->param_buf, 3, &output)) {
+ BTM_TRACE_DEBUG("generate random address failed");
+ } else {
+ /* set hash to be LSB of rpAddress */
+ p_inst->rpa[5] = output.param_buf[0];
+ p_inst->rpa[4] = output.param_buf[1];
+ p_inst->rpa[3] = output.param_buf[2];
+ }
+
+ if (p_inst->inst_id != BTM_BLE_MULTI_ADV_DEFAULT_STD &&
+ p_inst->inst_id < BTM_BleMaxMultiAdvInstanceCount()) {
+ /* set it to controller */
+ btm_ble_multi_adv_write_rpa(p_inst, p_inst->rpa);
+ }
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_multi_adv_configure_rpa
+**
+** Description This function set the random address for the adv instance
+**
+** Parameters advertise parameters used for this instance.
+**
+** Returns none
+**
+*******************************************************************************/
+void btm_ble_multi_adv_configure_rpa (tBTM_BLE_MULTI_ADV_INST *p_inst)
+{
+ if (btm_multi_adv_idx_q.front == (btm_multi_adv_idx_q.rear + 1) % BTM_BLE_MULTI_ADV_MAX) {
+ BTM_TRACE_ERROR("outstanding rand generation exceeded max allowed ");
+ return;
+ } else {
+ if (btm_multi_adv_idx_q.front == -1) {
+ btm_multi_adv_idx_q.front = 0;
+ btm_multi_adv_idx_q.rear = 0;
+ } else {
+ btm_multi_adv_idx_q.rear = (btm_multi_adv_idx_q.rear + 1) % BTM_BLE_MULTI_ADV_MAX;
+ }
+ btm_multi_adv_idx_q.inst_index_queue[btm_multi_adv_idx_q.rear] = p_inst->index;
+ }
+ btm_gen_resolvable_private_addr((void *)btm_ble_multi_adv_gen_rpa_cmpl);
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_multi_adv_reenable
+**
+** Description This function re-enable adv instance upon a connection establishment.
+**
+** Parameters advertise parameters used for this instance.
+**
+** Returns none.
+**
+*******************************************************************************/
+void btm_ble_multi_adv_reenable(UINT8 inst_id)
+{
+ tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1];
+
+ if (TRUE == p_inst->in_use) {
+ if (p_inst->adv_evt != BTM_BLE_CONNECT_DIR_EVT) {
+ btm_ble_enable_multi_adv (TRUE, p_inst->inst_id, 0);
+ } else
+ /* mark directed adv as disabled if adv has been stopped */
+ {
+ (p_inst->p_cback)(BTM_BLE_MULTI_ADV_DISABLE_EVT, p_inst->inst_id, p_inst->p_ref, 0);
+ p_inst->in_use = FALSE;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_multi_adv_enb_privacy
+**
+** Description This function enable/disable privacy setting in multi adv
+**
+** Parameters enable: enable or disable the adv instance.
+**
+** Returns none.
+**
+*******************************************************************************/
+void btm_ble_multi_adv_enb_privacy(BOOLEAN enable)
+{
+ UINT8 i;
+ tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[0];
+
+ for (i = 0; i < BTM_BleMaxMultiAdvInstanceCount() - 1; i ++, p_inst++) {
+ p_inst->in_use = FALSE;
+ if (enable) {
+ btm_ble_multi_adv_configure_rpa (p_inst);
+ } else {
+ btu_stop_timer_oneshot(&p_inst->raddr_timer_ent);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleEnableAdvInstance
+**
+** Description This function enable a Multi-ADV instance with the specified
+** adv parameters
+**
+** Parameters p_params: pointer to the adv parameter structure, set as default
+** adv parameter when the instance is enabled.
+** p_cback: callback function for the adv instance.
+** p_ref: reference data attach to the adv instance to be enabled.
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleEnableAdvInstance (tBTM_BLE_ADV_PARAMS *p_params,
+ tBTM_BLE_MULTI_ADV_CBACK *p_cback, void *p_ref)
+{
+ UINT8 i;
+ tBTM_STATUS rt = BTM_NO_RESOURCES;
+ tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[0];
+
+ BTM_TRACE_EVENT("BTM_BleEnableAdvInstance called");
+
+ if (0 == btm_cb.cmn_ble_vsc_cb.adv_inst_max) {
+ BTM_TRACE_ERROR("Controller does not support Multi ADV");
+ return BTM_ERR_PROCESSING;
+ }
+
+ if (NULL == p_inst) {
+ BTM_TRACE_ERROR("Invalid instance in BTM_BleEnableAdvInstance");
+ return BTM_ERR_PROCESSING;
+ }
+
+ for (i = 0; i < BTM_BleMaxMultiAdvInstanceCount() - 1; i ++, p_inst++) {
+ if (FALSE == p_inst->in_use) {
+ p_inst->in_use = TRUE;
+ /* configure adv parameter */
+ if (p_params) {
+ rt = btm_ble_multi_adv_set_params(p_inst, p_params, 0);
+ } else {
+ rt = BTM_CMD_STARTED;
+ }
+
+ /* enable adv */
+ BTM_TRACE_EVENT("btm_ble_enable_multi_adv being called with inst_id:%d",
+ p_inst->inst_id);
+
+ if (BTM_CMD_STARTED == rt) {
+ if ((rt = btm_ble_enable_multi_adv (TRUE, p_inst->inst_id,
+ BTM_BLE_MULTI_ADV_ENB_EVT)) == BTM_CMD_STARTED) {
+ p_inst->p_cback = p_cback;
+ p_inst->p_ref = p_ref;
+ }
+ }
+
+ if (BTM_CMD_STARTED != rt) {
+ p_inst->in_use = FALSE;
+ BTM_TRACE_ERROR("BTM_BleEnableAdvInstance failed");
+ }
+ break;
+ }
+ }
+ return rt;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleUpdateAdvInstParam
+**
+** Description This function update a Multi-ADV instance with the specified
+** adv parameters.
+**
+** Parameters inst_id: adv instance ID
+** p_params: pointer to the adv parameter structure.
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleUpdateAdvInstParam (UINT8 inst_id, tBTM_BLE_ADV_PARAMS *p_params)
+{
+ tBTM_STATUS rt = BTM_ILLEGAL_VALUE;
+ tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1];
+
+ BTM_TRACE_EVENT("BTM_BleUpdateAdvInstParam called with inst_id:%d", inst_id);
+
+ if (0 == btm_cb.cmn_ble_vsc_cb.adv_inst_max) {
+ BTM_TRACE_ERROR("Controller does not support Multi ADV");
+ return BTM_ERR_PROCESSING;
+ }
+
+ if (inst_id < BTM_BleMaxMultiAdvInstanceCount() &&
+ inst_id != BTM_BLE_MULTI_ADV_DEFAULT_STD &&
+ p_params != NULL) {
+ if (FALSE == p_inst->in_use) {
+ BTM_TRACE_DEBUG("adv instance %d is not active", inst_id);
+ return BTM_WRONG_MODE;
+ } else {
+ btm_ble_enable_multi_adv(FALSE, inst_id, 0);
+ }
+
+ if (BTM_CMD_STARTED == btm_ble_multi_adv_set_params(p_inst, p_params, 0)) {
+ rt = btm_ble_enable_multi_adv(TRUE, inst_id, BTM_BLE_MULTI_ADV_PARAM_EVT);
+ }
+ }
+ return rt;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleCfgAdvInstData
+**
+** Description This function configure a Multi-ADV instance with the specified
+** adv data or scan response data.
+**
+** Parameters inst_id: adv instance ID
+** is_scan_rsp: is this scan response. if no, set as adv data.
+** data_mask: adv data mask.
+** p_data: pointer to the adv data structure.
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleCfgAdvInstData (UINT8 inst_id, BOOLEAN is_scan_rsp,
+ tBTM_BLE_AD_MASK data_mask,
+ tBTM_BLE_ADV_DATA *p_data)
+{
+ UINT8 param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN], *pp = param;
+ UINT8 sub_code = (is_scan_rsp) ?
+ BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA : BTM_BLE_MULTI_ADV_WRITE_ADV_DATA;
+ UINT8 *p_len;
+ tBTM_STATUS rt;
+ UINT8 *pp_temp = (UINT8 *)(param + BTM_BLE_MULTI_ADV_WRITE_DATA_LEN - 1);
+ tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+
+ BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+ if (0 == cmn_ble_vsc_cb.adv_inst_max) {
+ BTM_TRACE_ERROR("Controller does not support Multi ADV");
+ return BTM_ERR_PROCESSING;
+ }
+
+ btm_ble_update_dmt_flag_bits(&p_data->flag, btm_cb.btm_inq_vars.connectable_mode,
+ btm_cb.btm_inq_vars.discoverable_mode);
+
+ BTM_TRACE_EVENT("BTM_BleCfgAdvInstData called with inst_id:%d", inst_id);
+ if (inst_id > BTM_BLE_MULTI_ADV_MAX || inst_id == BTM_BLE_MULTI_ADV_DEFAULT_STD) {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ memset(param, 0, BTM_BLE_MULTI_ADV_WRITE_DATA_LEN);
+
+ UINT8_TO_STREAM(pp, sub_code);
+ p_len = pp ++;
+ btm_ble_build_adv_data(&data_mask, &pp, p_data);
+ *p_len = (UINT8)(pp - param - 2);
+ UINT8_TO_STREAM(pp_temp, inst_id);
+
+ if ((rt = BTM_VendorSpecificCommand (HCI_BLE_MULTI_ADV_OCF,
+ (UINT8)BTM_BLE_MULTI_ADV_WRITE_DATA_LEN,
+ param,
+ btm_ble_multi_adv_vsc_cmpl_cback))
+ == BTM_CMD_STARTED) {
+ btm_ble_multi_adv_enq_op_q(sub_code, inst_id, BTM_BLE_MULTI_ADV_DATA_EVT);
+ }
+ return rt;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleDisableAdvInstance
+**
+** Description This function disables a Multi-ADV instance.
+**
+** Parameters inst_id: adv instance ID
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleDisableAdvInstance (UINT8 inst_id)
+{
+ tBTM_STATUS rt = BTM_ILLEGAL_VALUE;
+ tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+
+ BTM_TRACE_EVENT("BTM_BleDisableAdvInstance with inst_id:%d", inst_id);
+
+ BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+ if (0 == cmn_ble_vsc_cb.adv_inst_max) {
+ BTM_TRACE_ERROR("Controller does not support Multi ADV");
+ return BTM_ERR_PROCESSING;
+ }
+
+ if (inst_id < BTM_BleMaxMultiAdvInstanceCount() &&
+ inst_id != BTM_BLE_MULTI_ADV_DEFAULT_STD) {
+ if ((rt = btm_ble_enable_multi_adv(FALSE, inst_id, BTM_BLE_MULTI_ADV_DISABLE_EVT))
+ == BTM_CMD_STARTED) {
+ btm_ble_multi_adv_configure_rpa(&btm_multi_adv_cb.p_adv_inst[inst_id - 1]);
+ btu_stop_timer_oneshot(&btm_multi_adv_cb.p_adv_inst[inst_id - 1].raddr_timer_ent);
+ btm_multi_adv_cb.p_adv_inst[inst_id - 1].in_use = FALSE;
+ }
+ }
+ return rt;
+}
+/*******************************************************************************
+**
+** Function btm_ble_multi_adv_vse_cback
+**
+** Description VSE callback for multi adv events.
+**
+** Returns
+**
+*******************************************************************************/
+void btm_ble_multi_adv_vse_cback(UINT8 len, UINT8 *p)
+{
+ UINT8 sub_event;
+ UINT8 adv_inst;
+ UINT16 conn_handle;
+ tACL_CONN *p_acl_cb = NULL;
+ /* Check if this is a BLE RSSI vendor specific event */
+ STREAM_TO_UINT8(sub_event, p);
+ len--;
+
+ BTM_TRACE_EVENT("btm_ble_multi_adv_vse_cback called with event:%d", sub_event);
+ if ((sub_event == HCI_VSE_SUBCODE_BLE_MULTI_ADV_ST_CHG) && (len >= 4)) {
+ STREAM_TO_UINT8(adv_inst, p);
+ ++p;
+ STREAM_TO_UINT16(conn_handle, p);
+
+ if ((p_acl_cb = btm_handle_to_acl(conn_handle)) != NULL) {
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+ if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE &&
+ adv_inst <= BTM_BLE_MULTI_ADV_MAX && adv_inst != BTM_BLE_MULTI_ADV_DEFAULT_STD) {
+ memcpy(p_acl_cb->conn_addr, btm_multi_adv_cb.p_adv_inst[adv_inst - 1].rpa,
+ BD_ADDR_LEN);
+ }
+#endif
+ }
+
+ if (adv_inst < BTM_BleMaxMultiAdvInstanceCount() &&
+ adv_inst != BTM_BLE_MULTI_ADV_DEFAULT_STD) {
+ BTM_TRACE_EVENT("btm_ble_multi_adv_reenable called");
+ btm_ble_multi_adv_reenable(adv_inst);
+ }
+ /* re-enable connectibility */
+ else if (adv_inst == BTM_BLE_MULTI_ADV_DEFAULT_STD) {
+ if (btm_cb.ble_ctr_cb.inq_var.connectable_mode == BTM_BLE_CONNECTABLE) {
+ btm_ble_set_connectability ( btm_cb.ble_ctr_cb.inq_var.connectable_mode );
+ }
+ }
+
+ }
+
+}
+/*******************************************************************************
+**
+** Function btm_ble_multi_adv_init
+**
+** Description This function initialize the multi adv control block.
+**
+** Parameters None
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_multi_adv_init(void)
+{
+#if BTM_DYNAMIC_MEMORY == TRUE
+ btm_multi_adv_cb_ptr = (tBTM_BLE_MULTI_ADV_CB *)osi_malloc(sizeof(tBTM_BLE_MULTI_ADV_CB));
+ btm_multi_adv_idx_q_ptr = (tBTM_BLE_MULTI_ADV_INST_IDX_Q *)osi_malloc(sizeof(tBTM_BLE_MULTI_ADV_INST_IDX_Q));
+ if (btm_multi_adv_cb_ptr == NULL || btm_multi_adv_idx_q_ptr == NULL) {
+ BTM_TRACE_ERROR("%s malloc failed", __func__);
+ return;
+ }
+#endif
+
+ UINT8 i = 0;
+ memset(&btm_multi_adv_cb, 0, sizeof(tBTM_BLE_MULTI_ADV_CB));
+ memset (&btm_multi_adv_idx_q, 0, sizeof (tBTM_BLE_MULTI_ADV_INST_IDX_Q));
+ btm_multi_adv_idx_q.front = -1;
+ btm_multi_adv_idx_q.rear = -1;
+
+ if (btm_cb.cmn_ble_vsc_cb.adv_inst_max > 0) {
+ btm_multi_adv_cb.p_adv_inst = osi_malloc( sizeof(tBTM_BLE_MULTI_ADV_INST) *
+ (btm_cb.cmn_ble_vsc_cb.adv_inst_max));
+ memset(btm_multi_adv_cb.p_adv_inst, 0, sizeof(tBTM_BLE_MULTI_ADV_INST) *
+ (btm_cb.cmn_ble_vsc_cb.adv_inst_max));
+
+ btm_multi_adv_cb.op_q.p_sub_code = osi_malloc( sizeof(UINT8) *
+ (btm_cb.cmn_ble_vsc_cb.adv_inst_max));
+ memset(btm_multi_adv_cb.op_q.p_sub_code, 0,
+ sizeof(UINT8) * (btm_cb.cmn_ble_vsc_cb.adv_inst_max));
+
+ btm_multi_adv_cb.op_q.p_inst_id = osi_malloc( sizeof(UINT8) *
+ (btm_cb.cmn_ble_vsc_cb.adv_inst_max));
+ memset(btm_multi_adv_cb.op_q.p_inst_id, 0,
+ sizeof(UINT8) * (btm_cb.cmn_ble_vsc_cb.adv_inst_max));
+ }
+
+ /* Initialize adv instance indices and IDs. */
+ for (i = 0; i < btm_cb.cmn_ble_vsc_cb.adv_inst_max; i++) {
+ btm_multi_adv_cb.p_adv_inst[i].index = i;
+ btm_multi_adv_cb.p_adv_inst[i].inst_id = i + 1;
+ }
+
+ BTM_RegisterForVSEvents(btm_ble_multi_adv_vse_cback, TRUE);
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_multi_adv_cleanup
+**
+** Description This function cleans up multi adv control block.
+**
+** Parameters
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_multi_adv_cleanup(void)
+{
+ if (btm_multi_adv_cb.p_adv_inst) {
+ osi_free(btm_multi_adv_cb.p_adv_inst);
+ btm_multi_adv_cb.p_adv_inst = NULL;
+ }
+
+ if (btm_multi_adv_cb.op_q.p_sub_code) {
+ osi_free(btm_multi_adv_cb.op_q.p_sub_code);
+ btm_multi_adv_cb.op_q.p_sub_code = NULL;
+ }
+
+ if (btm_multi_adv_cb.op_q.p_inst_id) {
+ osi_free(btm_multi_adv_cb.op_q.p_inst_id);
+ btm_multi_adv_cb.op_q.p_inst_id = NULL;
+ }
+
+#if BTM_DYNAMIC_MEMORY == TRUE
+ if(btm_multi_adv_cb_ptr) {
+ osi_free(btm_multi_adv_cb_ptr);
+ btm_multi_adv_cb_ptr = NULL;
+ }
+ if(btm_multi_adv_idx_q_ptr) {
+ osi_free(btm_multi_adv_idx_q_ptr);
+ btm_multi_adv_idx_q_ptr = NULL;
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_multi_adv_get_ref
+**
+** Description This function obtains the reference pointer for the instance ID provided
+**
+** Parameters inst_id - Instance ID
+**
+** Returns void*
+**
+*******************************************************************************/
+void *btm_ble_multi_adv_get_ref(UINT8 inst_id)
+{
+ tBTM_BLE_MULTI_ADV_INST *p_inst = NULL;
+
+ if (inst_id < BTM_BleMaxMultiAdvInstanceCount()) {
+ p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1];
+ if (NULL != p_inst) {
+ return p_inst->p_ref;
+ }
+ }
+
+ return NULL;
+}
+#endif
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_ble_privacy.c b/lib/bt/host/bluedroid/stack/btm/btm_ble_privacy.c
new file mode 100644
index 00000000..7058df20
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_ble_privacy.c
@@ -0,0 +1,1086 @@
+/******************************************************************************
+ *
+ * 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 functions for BLE controller based privacy.
+ *
+ ******************************************************************************/
+#include <string.h>
+#include "common/bt_target.h"
+
+#if (BLE_INCLUDED == TRUE && BLE_PRIVACY_SPT == TRUE)
+#include "stack/bt_types.h"
+#include "stack/hcimsgs.h"
+#include "stack/btu.h"
+//#include "vendor_hcidefs.h"
+#include "btm_int.h"
+#include "device/controller.h"
+#include "stack/hcidefs.h"
+
+#define HCI_VENDOR_BLE_RPA_VSC (0x0155 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* RPA offload VSC specifics */
+#define BTM_BLE_META_IRK_ENABLE 0x01
+#define BTM_BLE_META_ADD_IRK_ENTRY 0x02
+#define BTM_BLE_META_REMOVE_IRK_ENTRY 0x03
+#define BTM_BLE_META_CLEAR_IRK_LIST 0x04
+#define BTM_BLE_META_READ_IRK_ENTRY 0x05
+#define BTM_BLE_META_CS_RESOLVE_ADDR 0x00000001
+#define BTM_BLE_IRK_ENABLE_LEN 2
+
+#define BTM_BLE_META_ADD_IRK_LEN 24
+#define BTM_BLE_META_REMOVE_IRK_LEN 8
+#define BTM_BLE_META_CLEAR_IRK_LEN 1
+#define BTM_BLE_META_READ_IRK_LEN 2
+#define BTM_BLE_META_ADD_WL_ATTR_LEN 9
+
+/*******************************************************************************
+** Functions implemented controller based privacy using Resolving List
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function btm_ble_enq_resolving_list_pending
+**
+** Description add target address into resolving pending operation queue
+**
+** Parameters target_bda: target device address
+** add_entry: TRUE for add entry, FALSE for remove entry
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_enq_resolving_list_pending(BD_ADDR pseudo_bda, UINT8 op_code)
+{
+ tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+
+ memcpy(p_q->resolve_q_random_pseudo[p_q->q_next], pseudo_bda, BD_ADDR_LEN);
+ p_q->resolve_q_action[p_q->q_next] = op_code;
+ p_q->q_next ++;
+ p_q->q_next %= controller_get_interface()->get_ble_resolving_list_max_size();
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_brcm_find_resolving_pending_entry
+**
+** Description check to see if the action is in pending list
+**
+** Parameters TRUE: action pending;
+** FALSE: new action
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN btm_ble_brcm_find_resolving_pending_entry(BD_ADDR pseudo_addr, UINT8 action)
+{
+ tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+
+ for (UINT8 i = p_q->q_pending; i != p_q->q_next;) {
+ if (memcmp(p_q->resolve_q_random_pseudo[i], pseudo_addr, BD_ADDR_LEN) == 0 &&
+ action == p_q->resolve_q_action[i]) {
+ return TRUE;
+ }
+
+ i ++;
+ i %= controller_get_interface()->get_ble_resolving_list_max_size();
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_deq_resolving_pending
+**
+** Description dequeue target address from resolving pending operation queue
+**
+** Parameters pseudo_addr: pseudo_addr device address
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN btm_ble_deq_resolving_pending(BD_ADDR pseudo_addr)
+{
+ tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+
+ if (p_q->q_next != p_q->q_pending) {
+ memcpy(pseudo_addr, p_q->resolve_q_random_pseudo[p_q->q_pending], BD_ADDR_LEN);
+ memset(p_q->resolve_q_random_pseudo[p_q->q_pending], 0, BD_ADDR_LEN);
+ p_q->q_pending ++;
+ p_q->q_pending %= controller_get_interface()->get_ble_resolving_list_max_size();
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_clear_irk_index
+**
+** Description clear IRK list index mask for availability
+**
+** Returns none
+**
+*******************************************************************************/
+void btm_ble_clear_irk_index(UINT8 index)
+{
+ UINT8 byte;
+ UINT8 bit;
+
+ if (index < controller_get_interface()->get_ble_resolving_list_max_size()) {
+ byte = index / 8;
+ bit = index % 8;
+ btm_cb.ble_ctr_cb.irk_list_mask[byte] &= (~(1 << bit));
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_find_irk_index
+**
+** Description find the first available IRK list index
+**
+** Returns index from 0 ~ max (127 default)
+**
+*******************************************************************************/
+UINT8 btm_ble_find_irk_index(void)
+{
+ UINT8 i = 0;
+ UINT8 byte;
+ UINT8 bit;
+
+ while (i < controller_get_interface()->get_ble_resolving_list_max_size()) {
+ byte = i / 8;
+ bit = i % 8;
+
+ if ((btm_cb.ble_ctr_cb.irk_list_mask[byte] & (1 << bit)) == 0) {
+ btm_cb.ble_ctr_cb.irk_list_mask[byte] |= (1 << bit);
+ return i;
+ }
+ i++;
+ }
+
+ BTM_TRACE_ERROR ("%s failed, list full", __func__);
+ return i;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_update_resolving_list
+**
+** Description update resolving list entry in host maintained record
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_update_resolving_list(BD_ADDR pseudo_bda, BOOLEAN add)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(pseudo_bda);
+ if (p_dev_rec == NULL) {
+ return;
+ }
+
+ if (add) {
+ p_dev_rec->ble.in_controller_list |= BTM_RESOLVING_LIST_BIT;
+ if (!controller_get_interface()->supports_ble_privacy()) {
+ p_dev_rec->ble.resolving_list_index = btm_ble_find_irk_index();
+ }
+ } else {
+ p_dev_rec->ble.in_controller_list &= ~BTM_RESOLVING_LIST_BIT;
+ if (!controller_get_interface()->supports_ble_privacy()) {
+ /* clear IRK list index mask */
+ btm_ble_clear_irk_index(p_dev_rec->ble.resolving_list_index);
+ p_dev_rec->ble.resolving_list_index = 0;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_clear_resolving_list_complete
+**
+** Description This function is called when command complete for
+** clear resolving list
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_clear_resolving_list_complete(UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status = 0;
+ STREAM_TO_UINT8(status, p);
+
+ BTM_TRACE_DEBUG("%s status=%d", __func__, status);
+
+ if (status == HCI_SUCCESS) {
+ if (evt_len >= 3) {
+ /* VSC complete has one extra byte for op code and list size, skip it here */
+ p ++;
+
+ /* updated the available list size, and current list size */
+ uint8_t irk_list_sz_max = 0;
+ STREAM_TO_UINT8(irk_list_sz_max, p);
+
+ if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) {
+ btm_ble_resolving_list_init(irk_list_sz_max);
+ }
+
+ uint8_t irk_mask_size = (irk_list_sz_max % 8) ?
+ (irk_list_sz_max / 8 + 1) : (irk_list_sz_max / 8);
+ memset(btm_cb.ble_ctr_cb.irk_list_mask, 0, irk_mask_size);
+ }
+
+ btm_cb.ble_ctr_cb.resolving_list_avail_size =
+ controller_get_interface()->get_ble_resolving_list_max_size();
+
+ BTM_TRACE_DEBUG("%s resolving_list_avail_size=%d",
+ __func__, btm_cb.ble_ctr_cb.resolving_list_avail_size);
+
+ list_node_t *p_node = NULL;
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+ for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
+ p_dev_rec = list_node(p_node);
+ p_dev_rec->ble.in_controller_list &= ~BTM_RESOLVING_LIST_BIT;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_add_resolving_list_entry_complete
+**
+** Description This function is called when command complete for
+** add resolving list entry
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_add_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ STREAM_TO_UINT8(status, p);
+
+ BTM_TRACE_DEBUG("%s status = %d", __func__, status);
+
+ BD_ADDR pseudo_bda;
+ if (!btm_ble_deq_resolving_pending(pseudo_bda)) {
+ BTM_TRACE_DEBUG("no pending resolving list operation");
+ return;
+ }
+
+ if (status == HCI_SUCCESS) {
+ /* privacy 1.2 command complete does not have these extra byte */
+ if (evt_len > 2) {
+ /* VSC complete has one extra byte for op code, skip it here */
+ p ++;
+ STREAM_TO_UINT8(btm_cb.ble_ctr_cb.resolving_list_avail_size, p);
+ } else {
+ btm_cb.ble_ctr_cb.resolving_list_avail_size --;
+ }
+ } else if (status == HCI_ERR_MEMORY_FULL) { /* BT_ERROR_CODE_MEMORY_CAPACITY_EXCEEDED */
+ btm_cb.ble_ctr_cb.resolving_list_avail_size = 0;
+ BTM_TRACE_ERROR("%s Resolving list Full ", __func__);
+ } else {
+ BTM_TRACE_ERROR("%s Add resolving list error %d ", __func__, status);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_remove_resolving_list_entry_complete
+**
+** Description This function is called when command complete for
+** remove resolving list entry
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_remove_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len)
+{
+ BD_ADDR pseudo_bda;
+ UINT8 status;
+
+ STREAM_TO_UINT8(status, p);
+
+ BTM_TRACE_DEBUG("%s status = %d", __func__, status);
+
+ if (!btm_ble_deq_resolving_pending(pseudo_bda)) {
+ BTM_TRACE_ERROR("%s no pending resolving list operation", __func__);
+ return;
+ }
+
+ if (status == HCI_SUCCESS) {
+ /* proprietary: spec does not have these extra bytes */
+ if (evt_len > 2) {
+ p ++; /* skip opcode */
+ STREAM_TO_UINT8(btm_cb.ble_ctr_cb.resolving_list_avail_size, p);
+ } else {
+ btm_cb.ble_ctr_cb.resolving_list_avail_size++;
+ }
+ } else {
+ BTM_TRACE_ERROR("%s remove resolving list error 0x%x", __func__, status);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_read_resolving_list_entry_complete
+**
+** Description This function is called when command complete for
+** remove resolving list entry
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_read_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status, rra_type = BTM_BLE_ADDR_PSEUDO;
+ BD_ADDR rra, pseudo_bda;
+
+ STREAM_TO_UINT8 (status, p);
+
+ BTM_TRACE_DEBUG("%s status = %d", __func__, status);
+
+ if (!btm_ble_deq_resolving_pending(pseudo_bda)) {
+ BTM_TRACE_ERROR("no pending resolving list operation");
+ return;
+ }
+
+ if (status == HCI_SUCCESS) {
+ /* proprietary spec has extra bytes */
+ if (evt_len > 8) {
+ p += (2 + 16 + 1 + 6); /* skip subcode, index, IRK value, address type, identity addr type */
+ STREAM_TO_BDADDR(rra, p);
+
+ BTM_TRACE_ERROR("%s peer_addr: %02x:%02x:%02x:%02x:%02x:%02x",
+ __func__, rra[0], rra[1], rra[2], rra[3], rra[4], rra[5]);
+ } else {
+ STREAM_TO_BDADDR(rra, p);
+ }
+ btm_ble_refresh_peer_resolvable_private_addr(pseudo_bda, rra, rra_type);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_set_addr_resolution_enable_complete
+**
+** Description This function is called when the command to set address
+** resolution enable completes.
+**
+** Parameters p: Pointer to the command complete event data.
+** evt_len: Length of the event data.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_set_addr_resolution_enable_complete(UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+
+ STREAM_TO_UINT8(status, p);
+
+ BTM_TRACE_DEBUG("%s status = %d", __func__, status);
+
+ tBTM_LE_RANDOM_CB *random_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+
+ if (!(random_cb && random_cb->set_local_privacy_cback)) {
+ return;
+ }
+
+ if (status == HCI_SUCCESS) {
+ random_cb->set_local_privacy_cback(BTM_SUCCESS);
+ return;
+ } else if (status == HCI_ERR_COMMAND_DISALLOWED) {
+ BTM_TRACE_ERROR("a non-connected activity is ongoing, such as advertising and scanning");
+ } else {
+ BTM_TRACE_ERROR("set local privacy failed");
+ }
+ random_cb->set_local_privacy_cback(BTM_ILLEGAL_VALUE);
+}
+
+/*******************************************************************************
+ VSC that implement controller based privacy
+********************************************************************************/
+/*******************************************************************************
+**
+** Function btm_ble_resolving_list_vsc_op_cmpl
+**
+** Description IRK operation VSC complete handler
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_resolving_list_vsc_op_cmpl (tBTM_VSC_CMPL *p_params)
+{
+ UINT8 *p = p_params->p_param_buf, op_subcode;
+ UINT16 evt_len = p_params->param_len;
+
+ op_subcode = *(p + 1);
+
+ BTM_TRACE_DEBUG("%s op_subcode = %d", __func__, op_subcode);
+
+ if (op_subcode == BTM_BLE_META_CLEAR_IRK_LIST) {
+ btm_ble_clear_resolving_list_complete(p, evt_len);
+ } else if (op_subcode == BTM_BLE_META_ADD_IRK_ENTRY) {
+ btm_ble_add_resolving_list_entry_complete(p, evt_len);
+ } else if (op_subcode == BTM_BLE_META_REMOVE_IRK_ENTRY) {
+ btm_ble_remove_resolving_list_entry_complete(p, evt_len);
+ } else if (op_subcode == BTM_BLE_META_READ_IRK_ENTRY) {
+ btm_ble_read_resolving_list_entry_complete(p, evt_len);
+ } else if (op_subcode == BTM_BLE_META_IRK_ENABLE) {
+ /* RPA offloading enable/disabled */
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_remove_resolving_list_entry
+**
+** Description This function to remove an IRK entry from the list
+**
+** Parameters ble_addr_type: address type
+** ble_addr: LE adddress
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_remove_resolving_list_entry(tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ /* if controller does not support RPA offloading or privacy 1.2, skip */
+ if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) {
+ return BTM_WRONG_MODE;
+ }
+
+ tBTM_STATUS st = BTM_NO_RESOURCES;
+ if (controller_get_interface()->supports_ble_privacy()) {
+ #if CONTROLLER_RPA_LIST_ENABLE
+ if (btsnd_hcic_ble_rm_device_resolving_list(p_dev_rec->ble.static_addr_type,
+ p_dev_rec->ble.static_addr)) {
+ st = BTM_CMD_STARTED;
+ }
+ #else
+ // do nothing
+ /* It will cause that scanner doesn't send scan request to advertiser
+ * which has sent IRK to us and we have stored the IRK in controller.
+ * It is a hardware limitation. The preliminary solution is not to
+ * send key to the controller, but to resolve the random address in host. */
+ #endif
+ } else {
+ UINT8 param[20] = {0};
+ UINT8 *p = param;
+
+ UINT8_TO_STREAM(p, BTM_BLE_META_REMOVE_IRK_ENTRY);
+ UINT8_TO_STREAM(p, p_dev_rec->ble.static_addr_type);
+ BDADDR_TO_STREAM(p, p_dev_rec->ble.static_addr);
+
+ st = BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC,
+ BTM_BLE_META_REMOVE_IRK_LEN,
+ param,
+ btm_ble_resolving_list_vsc_op_cmpl);
+ }
+
+ if (st == BTM_CMD_STARTED) {
+ btm_ble_enq_resolving_list_pending( p_dev_rec->bd_addr, BTM_BLE_META_REMOVE_IRK_ENTRY);
+ }
+
+ return st;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_clear_resolving_list
+**
+** Description This function clears the resolving list
+**
+** Parameters None.
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_clear_resolving_list(void)
+{
+ tBTM_STATUS st = BTM_NO_RESOURCES;
+
+ if (controller_get_interface()->supports_ble_privacy()) {
+ if (btsnd_hcic_ble_clear_resolving_list()) {
+ st = BTM_SUCCESS;
+ }
+ } else {
+ UINT8 param[20] = {0};
+ UINT8 *p = param;
+
+ UINT8_TO_STREAM(p, BTM_BLE_META_CLEAR_IRK_LIST);
+ st = BTM_VendorSpecificCommand (HCI_VENDOR_BLE_RPA_VSC,
+ BTM_BLE_META_CLEAR_IRK_LEN,
+ param,
+ btm_ble_resolving_list_vsc_op_cmpl);
+ }
+
+ return st;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_read_resolving_list_entry
+**
+** Description This function read an IRK entry by index
+**
+** Parameters entry index.
+**
+** Returns status
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_read_resolving_list_entry(tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ tBTM_STATUS st = BTM_NO_RESOURCES;
+
+ if (!(p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT)) {
+ return BTM_WRONG_MODE;
+ }
+
+ if (controller_get_interface()->supports_ble_privacy()) {
+ if (btsnd_hcic_ble_read_resolvable_addr_peer(p_dev_rec->ble.static_addr_type,
+ p_dev_rec->ble.static_addr)) {
+ st = BTM_CMD_STARTED;
+ }
+ } else {
+ UINT8 param[20] = {0};
+ UINT8 *p = param;
+
+ UINT8_TO_STREAM(p, BTM_BLE_META_READ_IRK_ENTRY);
+ UINT8_TO_STREAM(p, p_dev_rec->ble.resolving_list_index);
+
+ st = BTM_VendorSpecificCommand (HCI_VENDOR_BLE_RPA_VSC,
+ BTM_BLE_META_READ_IRK_LEN,
+ param,
+ btm_ble_resolving_list_vsc_op_cmpl);
+ }
+
+ if (st == BTM_CMD_STARTED) {
+ btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr,
+ BTM_BLE_META_READ_IRK_ENTRY);
+ }
+
+ return st;
+}
+
+
+/*******************************************************************************
+**
+** Function btm_ble_suspend_resolving_list_activity
+**
+** Description This function suspends all resolving list activity, including
+** scan, initiating, and advertising, if resolving list is being
+** enabled.
+**
+** Parameters
+**
+** Returns TRUE if suspended; FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN btm_ble_suspend_resolving_list_activity(void)
+{
+ tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb;
+
+ /* if resolving list is not enabled, do not need to terminate any activity */
+ /* if asking for stop all activity */
+ /* if already suspended */
+ if (p_ble_cb->suspended_rl_state != BTM_BLE_RL_IDLE) {
+ return TRUE;
+ }
+
+ /* direct connection active, wait until it completed */
+ if (btm_ble_get_conn_st() == BLE_DIR_CONN) {
+ BTM_TRACE_ERROR("resolving list can not be edited, EnQ now");
+ return FALSE;
+ }
+
+ p_ble_cb->suspended_rl_state = BTM_BLE_RL_IDLE;
+
+ if (p_ble_cb->inq_var.adv_mode == BTM_BLE_ADV_ENABLE) {
+ btm_ble_stop_adv();
+ p_ble_cb->suspended_rl_state |= BTM_BLE_RL_ADV;
+ }
+
+ if (BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) {
+ btm_ble_stop_scan();
+ p_ble_cb->suspended_rl_state |= BTM_BLE_RL_SCAN;
+ }
+
+ if (btm_ble_suspend_bg_conn()) {
+ p_ble_cb->suspended_rl_state |= BTM_BLE_RL_INIT;
+ }
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_resume_resolving_list_activity
+**
+** Description This function resumes the resolving list activity, including
+** scanning, initiating, and advertising, if any of these
+** activities has been suspended earlier.
+**
+** Returns none
+**
+*******************************************************************************/
+void btm_ble_resume_resolving_list_activity(void)
+{
+ tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb;
+
+ if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_ADV) {
+ btm_ble_start_adv();
+ }
+
+ if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_SCAN) {
+ btm_ble_start_scan();
+ }
+
+ if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_INIT) {
+ btm_ble_resume_bg_conn();
+ }
+
+ p_ble_cb->suspended_rl_state = BTM_BLE_RL_IDLE;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_vendor_enable_irk_feature
+**
+** Description This function is called to enable or disable the RRA
+** offloading feature.
+**
+** Parameters enable: enable or disable the RRA offloading feature
+**
+** Returns BTM_SUCCESS if successful
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_vendor_enable_irk_feature(BOOLEAN enable)
+{
+ UINT8 param[20], *p;
+ tBTM_STATUS st = BTM_MODE_UNSUPPORTED;
+
+ p = param;
+ memset(param, 0, 20);
+
+ /* select feature based on control block settings */
+ UINT8_TO_STREAM(p, BTM_BLE_META_IRK_ENABLE);
+ UINT8_TO_STREAM(p, enable ? 0x01 : 0x00);
+
+ st = BTM_VendorSpecificCommand (HCI_VENDOR_BLE_RPA_VSC, BTM_BLE_IRK_ENABLE_LEN,
+ param, btm_ble_resolving_list_vsc_op_cmpl);
+
+ return st;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_exe_disable_resolving_list
+**
+** Description execute resolving list disable
+**
+** Returns none
+**
+*******************************************************************************/
+BOOLEAN btm_ble_exe_disable_resolving_list(void)
+{
+ if (!btm_ble_suspend_resolving_list_activity()) {
+ return FALSE;
+ }
+
+ if (!controller_get_interface()->supports_ble_privacy()) {
+ btm_ble_vendor_enable_irk_feature(FALSE);
+ } else {
+ //btsnd_hcic_ble_set_addr_resolution_enable(FALSE);
+ }
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_exe_enable_resolving_list
+**
+** Description enable LE resolve address list
+**
+** Returns none
+**
+*******************************************************************************/
+void btm_ble_exe_enable_resolving_list(void)
+{
+ if (!btm_ble_suspend_resolving_list_activity()) {
+ return;
+ }
+
+ if (!controller_get_interface()->supports_ble_privacy()) {
+ btm_ble_vendor_enable_irk_feature(TRUE);
+ } else {
+ //btsnd_hcic_ble_set_addr_resolution_enable(TRUE);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_disable_resolving_list
+**
+** Description Disable LE Address resolution
+**
+** Returns none
+**
+*******************************************************************************/
+BOOLEAN btm_ble_disable_resolving_list(UINT8 rl_mask, BOOLEAN to_resume )
+{
+ UINT8 rl_state = btm_cb.ble_ctr_cb.rl_state;
+
+ /* if controller does not support RPA offloading or privacy 1.2, skip */
+ if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) {
+ return FALSE;
+ }
+
+ btm_cb.ble_ctr_cb.rl_state &= ~rl_mask;
+
+ if (rl_state != BTM_BLE_RL_IDLE && btm_cb.ble_ctr_cb.rl_state == BTM_BLE_RL_IDLE) {
+ if (btm_ble_exe_disable_resolving_list()) {
+ if (to_resume) {
+ btm_ble_resume_resolving_list_activity();
+ }
+
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_resolving_list_load_dev
+**
+** Description This function add a device which is using RPA into white list
+**
+** Parameters pointer to device security record
+**
+** Returns TRUE if device added, otherwise falase.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ BOOLEAN rt = FALSE;
+#if (SMP_INCLUDED == TRUE)
+ UINT8 rl_mask = btm_cb.ble_ctr_cb.rl_state;
+
+ BTM_TRACE_DEBUG("%s btm_cb.ble_ctr_cb.privacy_mode = %d\n", __func__,
+ btm_cb.ble_ctr_cb.privacy_mode);
+
+ /* if controller does not support RPA offloading or privacy 1.2, skip */
+ if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) {
+ return FALSE;
+ }
+
+ BTM_TRACE_DEBUG("%s btm_cb.ble_ctr_cb.privacy_mode = %d\n",
+ __func__, btm_cb.ble_ctr_cb.privacy_mode);
+
+ /* only add RPA enabled device into resolving list */
+ if (p_dev_rec != NULL && /* RPA is being used and PID is known */
+ (p_dev_rec->sec_flags & BTM_SEC_IN_USE) != 0 &&
+ ((p_dev_rec->ble.key_type & BTM_LE_KEY_PID) != 0 ||
+ (p_dev_rec->ble.key_type & BTM_LE_KEY_LID) != 0)) {
+ if (!(p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) &&
+ btm_ble_brcm_find_resolving_pending_entry(p_dev_rec->bd_addr,
+ BTM_BLE_META_ADD_IRK_ENTRY) == FALSE) {
+ if (btm_cb.ble_ctr_cb.resolving_list_avail_size > 0) {
+ if (rl_mask) {
+ if (!btm_ble_disable_resolving_list (rl_mask, FALSE)) {
+ return FALSE;
+ }
+ }
+
+ btm_ble_update_resolving_list(p_dev_rec->bd_addr, TRUE);
+ if (controller_get_interface()->supports_ble_privacy()) {
+ BD_ADDR dummy_bda = {0};
+ if (memcmp(p_dev_rec->ble.static_addr, dummy_bda, BD_ADDR_LEN) == 0) {
+ memcpy(p_dev_rec->ble.static_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ p_dev_rec->ble.static_addr_type = p_dev_rec->ble.ble_addr_type;
+ }
+
+#if CONTROLLER_RPA_LIST_ENABLE
+ BTM_TRACE_DEBUG("%s:adding device to controller resolving list\n", __func__);
+ UINT8 *peer_irk = p_dev_rec->ble.keys.irk;
+ UINT8 *local_irk = btm_cb.devcb.id_keys.irk;
+ //use identical IRK for now
+ rt = btsnd_hcic_ble_add_device_resolving_list(p_dev_rec->ble.static_addr_type,
+ p_dev_rec->ble.static_addr, peer_irk, local_irk);
+#else
+ // do nothing
+ /* It will cause that scanner doesn't send scan request to advertiser
+ * which has sent IRK to us and we have stored the IRK in controller.
+ * It is a hardware limitation. The preliminary solution is not to
+ * send key to the controller, but to resolve the random address in host. */
+
+#endif
+
+ } else {
+ UINT8 param[40] = {0};
+ UINT8 *p = param;
+
+ UINT8_TO_STREAM(p, BTM_BLE_META_ADD_IRK_ENTRY);
+ ARRAY_TO_STREAM(p, p_dev_rec->ble.keys.irk, BT_OCTET16_LEN);
+ UINT8_TO_STREAM(p, p_dev_rec->ble.static_addr_type);
+ BDADDR_TO_STREAM(p, p_dev_rec->ble.static_addr);
+
+ if (BTM_VendorSpecificCommand (HCI_VENDOR_BLE_RPA_VSC,
+ BTM_BLE_META_ADD_IRK_LEN,
+ param,
+ btm_ble_resolving_list_vsc_op_cmpl)
+ == BTM_CMD_STARTED) {
+ rt = TRUE;
+ }
+ }
+
+ if (rt) {
+ btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr,
+ BTM_BLE_META_ADD_IRK_ENTRY);
+ }
+
+ /* if resolving list has been turned on, re-enable it */
+ // if (rl_mask) {
+ // btm_ble_enable_resolving_list(rl_mask);
+ // } else {
+ // btm_ble_enable_resolving_list(BTM_BLE_RL_INIT);
+ // }
+ } else {
+ BTM_TRACE_WARNING("%s Resolving list full ", __func__);
+ }
+ } else {
+ BTM_TRACE_DEBUG("Device already in Resolving list\n");
+ rt = TRUE;
+ }
+ } else {
+ BTM_TRACE_DEBUG("Device not a RPA enabled device\n");
+ }
+#endif ///SMP_INCLUDED == TRUE
+ return rt;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_resolving_list_remove_dev
+**
+** Description This function removes the device from resolving list
+**
+** Parameters
+**
+** Returns status
+**
+*******************************************************************************/
+void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ UINT8 rl_mask = btm_cb.ble_ctr_cb.rl_state;
+
+ BTM_TRACE_EVENT ("%s\n", __func__);
+ if (rl_mask) {
+ if (!btm_ble_disable_resolving_list (rl_mask, FALSE)) {
+ return;
+ }
+ }
+
+ if ((p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) &&
+ btm_ble_brcm_find_resolving_pending_entry(p_dev_rec->bd_addr,
+ BTM_BLE_META_REMOVE_IRK_ENTRY) == FALSE) {
+ btm_ble_update_resolving_list( p_dev_rec->bd_addr, FALSE);
+ btm_ble_remove_resolving_list_entry(p_dev_rec);
+ } else {
+ BTM_TRACE_DEBUG("Device not in resolving list\n");
+ }
+
+ /* if resolving list has been turned on, re-enable it */
+ // if (rl_mask) {
+ // btm_ble_enable_resolving_list(rl_mask);
+ // }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_enable_resolving_list
+**
+** Description enable LE resolve address list
+**
+** Returns none
+**
+*******************************************************************************/
+void btm_ble_enable_resolving_list(UINT8 rl_mask)
+{
+ UINT8 rl_state = btm_cb.ble_ctr_cb.rl_state;
+
+ btm_cb.ble_ctr_cb.rl_state |= rl_mask;
+ if (rl_state == BTM_BLE_RL_IDLE &&
+ btm_cb.ble_ctr_cb.rl_state != BTM_BLE_RL_IDLE &&
+ controller_get_interface()->get_ble_resolving_list_max_size() != 0) {
+ btm_ble_exe_enable_resolving_list();
+ btm_ble_resume_resolving_list_activity();
+ }
+}
+
+#if 0 //Unused
+/*******************************************************************************
+**
+** Function btm_ble_resolving_list_empty
+**
+** Description check to see if resoving list is empty or not
+**
+** Returns TRUE: empty; FALSE non-empty
+**
+*******************************************************************************/
+BOOLEAN btm_ble_resolving_list_empty(void)
+{
+ return (controller_get_interface()->get_ble_resolving_list_max_size() ==
+ btm_cb.ble_ctr_cb.resolving_list_avail_size);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function btm_ble_enable_resolving_list_for_platform
+**
+** Description enable/disable resolving list feature depending on if any
+** resolving list is empty and whitelist is involoved in the
+** operation.
+**
+** Returns none
+**
+*******************************************************************************/
+void btm_ble_enable_resolving_list_for_platform (UINT8 rl_mask)
+{
+ /* if controller does not support, skip */
+ if (controller_get_interface()->get_ble_resolving_list_max_size() == 0) {
+ return;
+ }
+
+ if (btm_cb.ble_ctr_cb.wl_state == BTM_BLE_WL_IDLE) {
+ if (controller_get_interface()->get_ble_resolving_list_max_size() >
+ btm_cb.ble_ctr_cb.resolving_list_avail_size) {
+ btm_ble_enable_resolving_list(rl_mask);
+ } else {
+ btm_ble_disable_resolving_list(rl_mask, TRUE);
+ }
+ return;
+ }
+
+ tBTM_SEC_DEV_REC *p_dev = NULL;
+ list_node_t *p_node = NULL;
+ for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
+ p_dev = list_node(p_node);
+ if ((p_dev->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) &&
+ (p_dev->ble.in_controller_list & BTM_WHITE_LIST_BIT)) {
+ btm_ble_enable_resolving_list(rl_mask);
+ return;
+ }
+ }
+ btm_ble_disable_resolving_list(rl_mask, TRUE);
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_resolving_list_init
+**
+** Description Initialize resolving list in host stack
+**
+** Parameters Max resolving list size
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_resolving_list_init(UINT8 max_irk_list_sz)
+{
+ tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+ UINT8 irk_mask_size = (max_irk_list_sz % 8) ?
+ (max_irk_list_sz / 8 + 1) : (max_irk_list_sz / 8);
+
+ if (max_irk_list_sz > 0) {
+ p_q->resolve_q_random_pseudo = (BD_ADDR *)osi_malloc(sizeof(BD_ADDR) * max_irk_list_sz);
+ p_q->resolve_q_action = (UINT8 *)osi_malloc(max_irk_list_sz);
+
+ /* RPA offloading feature */
+ if (btm_cb.ble_ctr_cb.irk_list_mask == NULL) {
+ btm_cb.ble_ctr_cb.irk_list_mask = (UINT8 *)osi_malloc(irk_mask_size);
+ }
+
+ BTM_TRACE_DEBUG ("%s max_irk_list_sz = %d", __func__, max_irk_list_sz);
+ }
+
+ controller_get_interface()->set_ble_resolving_list_max_size(max_irk_list_sz);
+ btm_ble_clear_resolving_list();
+ btm_cb.ble_ctr_cb.resolving_list_avail_size = max_irk_list_sz;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_resolving_list_cleanup
+**
+** Description Cleanup resolving list dynamic memory
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_resolving_list_cleanup(void)
+{
+ tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+
+ if (p_q->resolve_q_random_pseudo) {
+ osi_free(p_q->resolve_q_random_pseudo);
+ p_q->resolve_q_random_pseudo = NULL;
+ }
+
+ if (p_q->resolve_q_action) {
+ osi_free(p_q->resolve_q_action);
+ p_q->resolve_q_action = NULL;
+ }
+
+ controller_get_interface()->set_ble_resolving_list_max_size(0);
+ if (btm_cb.ble_ctr_cb.irk_list_mask) {
+ osi_free(btm_cb.ble_ctr_cb.irk_list_mask);
+ btm_cb.ble_ctr_cb.irk_list_mask = NULL;
+ }
+
+}
+
+void btm_ble_add_default_entry_to_resolving_list(void)
+{
+ /*
+ * Add local IRK entry with 00:00:00:00:00:00 address. This entry will
+ * be used to generate RPA for non-directed advertising if own_addr_type
+ * is set to rpa_pub since we use all-zero address as peer addres in
+ * such case. Peer IRK should be left all-zero since this is not for an
+ * actual peer.
+ */
+ BD_ADDR peer_addr = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+ BT_OCTET16 peer_irk = {0x0};
+
+ btsnd_hcic_ble_add_device_resolving_list (BLE_ADDR_PUBLIC, peer_addr, peer_irk, btm_cb.devcb.id_keys.irk);
+}
+#endif
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_dev.c b/lib/bt/host/bluedroid/stack/btm/btm_dev.c
new file mode 100644
index 00000000..f9e3ed2b
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_dev.c
@@ -0,0 +1,741 @@
+/******************************************************************************
+ *
+ * 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 functions for the Bluetooth Device Manager
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+//#include <stdio.h>
+#include <stddef.h>
+
+#include "stack/bt_types.h"
+#include "device/controller.h"
+#include "stack/hcimsgs.h"
+#include "stack/btu.h"
+#include "stack/btm_api.h"
+#include "btm_int.h"
+#include "stack/hcidefs.h"
+#include "stack/l2c_api.h"
+
+static tBTM_SEC_DEV_REC *btm_find_oldest_dev (void);
+
+/*******************************************************************************
+**
+** Function BTM_SecAddDevice
+**
+** Description Add/modify device. This function will be normally called
+** during host startup to restore all required information
+** stored in the NVRAM.
+**
+** Parameters: bd_addr - BD address of the peer
+** dev_class - Device Class
+** bd_name - Name of the peer device. NULL if unknown.
+** features - Remote device's features (up to 3 pages). NULL if not known
+** trusted_mask - Bitwise OR of services that do not
+** require authorization. (array of UINT32)
+** link_key - Connection link key. NULL if unknown.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name,
+ UINT8 *features, UINT32 trusted_mask[],
+ LINK_KEY link_key, UINT8 key_type, tBTM_IO_CAP io_cap,
+ UINT8 pin_length, UINT8 sc_support)
+{
+#if (SMP_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ int i, j;
+ BOOLEAN found = FALSE;
+
+ BTM_TRACE_API("%s, link key type:%x\n", __FUNCTION__, key_type);
+ p_dev_rec = btm_find_dev (bd_addr);
+ if (!p_dev_rec) {
+ /* There is no device record, allocate one.
+ * If we can not find an empty spot for this one, let it fail. */
+ if (list_length(btm_cb.p_sec_dev_rec_list) < BTM_SEC_MAX_DEVICE_RECORDS) {
+ p_dev_rec = (tBTM_SEC_DEV_REC *)osi_malloc(sizeof(tBTM_SEC_DEV_REC));
+ if(p_dev_rec) {
+ list_append(btm_cb.p_sec_dev_rec_list, p_dev_rec);
+ /* Mark this record as in use and initialize */
+ memset (p_dev_rec, 0, sizeof (tBTM_SEC_DEV_REC));
+ p_dev_rec->sec_flags = BTM_SEC_IN_USE;
+ memcpy (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN);
+ p_dev_rec->hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_BR_EDR);
+ p_dev_rec->ble_hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_LE);
+ p_dev_rec->enc_mode = BTM_ENC_MODE_UNKNOWN;
+
+#if BLE_INCLUDED == TRUE
+ /* use default value for background connection params */
+ /* update conn params, use default value for background connection params */
+ memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS));
+#endif
+ }
+ }
+
+ if (!p_dev_rec) {
+ return (FALSE);
+ }
+ }
+ p_dev_rec->bond_type = BOND_TYPE_UNKNOWN; /* Default value */
+ p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+ p_dev_rec->remote_secure_connection_previous_state = sc_support;
+
+ if (dev_class) {
+ memcpy (p_dev_rec->dev_class, dev_class, DEV_CLASS_LEN);
+ }
+
+ memset(p_dev_rec->sec_bd_name, 0, sizeof(tBTM_BD_NAME));
+
+ if (bd_name && bd_name[0]) {
+ p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
+ BCM_STRNCPY_S ((char *)p_dev_rec->sec_bd_name, (char *)bd_name, BTM_MAX_REM_BD_NAME_LEN);
+ }
+
+ p_dev_rec->num_read_pages = 0;
+ if (features) {
+ memcpy (p_dev_rec->features, features, sizeof (p_dev_rec->features));
+ for (i = HCI_EXT_FEATURES_PAGE_MAX; i >= 0; i--) {
+ for (j = 0; j < HCI_FEATURE_BYTES_PER_PAGE; j++) {
+ if (p_dev_rec->features[i][j] != 0) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found) {
+ p_dev_rec->num_read_pages = i + 1;
+ break;
+ }
+ }
+ } else {
+ memset (p_dev_rec->features, 0, sizeof (p_dev_rec->features));
+ }
+
+ BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
+
+ if (link_key) {
+ BTM_TRACE_EVENT ("BTM_SecAddDevice() BDA: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bd_addr[0], bd_addr[1], bd_addr[2],
+ bd_addr[3], bd_addr[4], bd_addr[5]);
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;
+ memcpy (p_dev_rec->link_key, link_key, LINK_KEY_LEN);
+ p_dev_rec->link_key_type = key_type;
+ p_dev_rec->pin_code_length = pin_length;
+
+ if (pin_length >= 16 ||
+ key_type == BTM_LKEY_TYPE_AUTH_COMB ||
+ key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) {
+ // Set the fiag if the link key was made by using either a 16 digit
+ // pin or MITM.
+ p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+ }
+ }
+
+#if defined(BTIF_MIXED_MODE_INCLUDED) && (BTIF_MIXED_MODE_INCLUDED == TRUE)
+ if (key_type < BTM_MAX_PRE_SM4_LKEY_TYPE) {
+ p_dev_rec->sm4 = BTM_SM4_KNOWN;
+ } else {
+ p_dev_rec->sm4 = BTM_SM4_TRUE;
+ }
+#endif
+
+ p_dev_rec->rmt_io_caps = io_cap;
+ p_dev_rec->device_type |= BT_DEVICE_TYPE_BREDR;
+#endif ///SMP_INCLUDED == TRUE
+ return (TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SecDeleteDevice
+**
+** Description Free resources associated with the device.
+**
+** Parameters: bd_addr - BD address of the peer
+** transport - BT_TRANSPORT_BR_EDR or BT_TRANSPORT_LE
+**
+** Returns TRUE if removed OK, FALSE if not found or ACL link is active
+**
+*******************************************************************************/
+BOOLEAN BTM_SecDeleteDevice (BD_ADDR bd_addr, tBT_TRANSPORT transport)
+{
+
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ if (BTM_IsAclConnectionUp(bd_addr, transport)) {
+ BTM_TRACE_WARNING("%s FAILED: Cannot Delete when connection is active\n", __func__);
+ return FALSE;
+ }
+ if ((p_dev_rec = btm_find_dev(bd_addr)) != NULL) {
+ /* Tell controller to get rid of the link key, if it has one stored */
+ BTM_DeleteStoredLinkKey (p_dev_rec->bd_addr, NULL);
+
+ btm_sec_free_dev(p_dev_rec, transport);
+ }
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function BTM_SecClearSecurityFlags
+**
+** Description Reset the security flags (mark as not-paired) for a given
+** remove device.
+**
+*******************************************************************************/
+extern void BTM_SecClearSecurityFlags (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec == NULL) {
+ return;
+ }
+
+ p_dev_rec->sec_flags = 0;
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ p_dev_rec->sm4 = BTM_SM4_UNKNOWN;
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SecReadDevName
+**
+** Description Looks for the device name in the security database for the
+** specified BD address.
+**
+** Returns Pointer to the name or NULL
+**
+*******************************************************************************/
+char *BTM_SecReadDevName (BD_ADDR bd_addr)
+{
+ char *p_name = NULL;
+ tBTM_SEC_DEV_REC *p_srec;
+
+ if ((p_srec = btm_find_dev(bd_addr)) != NULL) {
+ p_name = (char *)p_srec->sec_bd_name;
+ }
+
+ return (p_name);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_find_sec_dev_in_list
+**
+** Description Look for the record in the device database for the record
+** with specified address
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+BOOLEAN btm_find_sec_dev_in_list (void *p_node_data, void *context)
+{
+ tBTM_SEC_DEV_REC *p_sec_dev = (tBTM_SEC_DEV_REC *)p_node_data;
+ BOOLEAN ret = TRUE;
+ BOOLEAN dev_free = !(p_sec_dev->sec_flags & BTM_SEC_IN_USE);
+ tSecDevContext *p_context = (tSecDevContext *)context;
+
+ if (dev_free == p_context->free_check) {
+ switch (p_context->type) {
+ case SEC_DEV_BDA:
+ if (!memcmp(p_context->context.p_bd_addr, p_sec_dev->bd_addr, BD_ADDR_LEN)) {
+ ret = FALSE;
+ }
+ break;
+ case SEC_DEV_HDL:
+ if (p_context->context.handle == p_sec_dev->hci_handle
+#if BLE_INCLUDED == TRUE
+ || (p_context->context.handle == p_sec_dev->ble_hci_handle)
+#endif
+ ) {
+ ret = FALSE;
+ }
+ break;
+#if BLE_PRIVACY_SPT == TRUE
+ case SEC_DEV_ID_ADDR:
+ if (!memcmp(p_context->context.p_bd_addr, p_sec_dev->ble.static_addr, BD_ADDR_LEN)) {
+ ret = FALSE;
+ }
+ break;
+#endif //BLE_PRIVACY_SPT == TRUE
+ case SEC_DEV_BTDM_BDA:
+ if (!memcmp(p_context->context.p_bd_addr, p_sec_dev->bd_addr, BD_ADDR_LEN)) {
+ ret = FALSE;
+ }
+#if BLE_INCLUDED == TRUE
+ // If a LE random address is looking for device record
+ if (!memcmp(p_sec_dev->ble.pseudo_addr, p_context->context.p_bd_addr, BD_ADDR_LEN)) {
+ ret = FALSE;
+ }
+
+ if (btm_ble_addr_resolvable(p_context->context.p_bd_addr, p_sec_dev)) {
+ ret = FALSE;
+ }
+#endif
+ break;
+ default:
+ break;
+ }
+ }
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_alloc_dev
+**
+** Description Look for the record in the device database for the record
+** with specified address
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+ tBTM_SEC_DEV_REC *p_dev_new_rec = NULL;
+ tBTM_SEC_DEV_REC *p_dev_old_rec = NULL;
+ tBTM_INQ_INFO *p_inq_info;
+ list_node_t *p_node = NULL;
+ BOOLEAN new_entry_found = FALSE;
+ BOOLEAN old_entry_found = FALSE;
+ BOOLEAN malloc_new_entry = FALSE;
+ BTM_TRACE_EVENT ("btm_sec_alloc_dev\n");
+ for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
+ p_dev_old_rec = list_node(p_node);
+ /* look for old entry which match the bd_addr and the BTM_SEC_IN_USE is cleared */
+ if (!(p_dev_old_rec->sec_flags & BTM_SEC_IN_USE) &&
+ (!memcmp (p_dev_old_rec->bd_addr, bd_addr, BD_ADDR_LEN))) {
+ old_entry_found = TRUE;
+ BTM_TRACE_EVENT ("btm_sec_alloc_dev old device found\n");
+ break;
+ }
+ }
+ for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
+ p_dev_new_rec = list_node(p_node);
+ /* find the first entry whose BTM_SEC_IN_USE is cleared */
+ if (!(p_dev_new_rec->sec_flags & BTM_SEC_IN_USE)) {
+ new_entry_found = TRUE;
+ break;
+ }
+ }
+ if (!new_entry_found) {
+ /* We can not find new device. We need malloc a new one if p_sec_dev_rec_list is not full */
+ if (list_length(btm_cb.p_sec_dev_rec_list) < BTM_SEC_MAX_DEVICE_RECORDS){
+ p_dev_new_rec = (tBTM_SEC_DEV_REC *)osi_malloc(sizeof(tBTM_SEC_DEV_REC));
+ if (p_dev_new_rec) {
+ new_entry_found = TRUE;
+ malloc_new_entry = TRUE;
+ } else {
+ return NULL;
+ }
+ }
+ }
+ if (!new_entry_found) {
+ p_dev_rec = btm_find_oldest_dev();
+ } else {
+ /* if the old device entry not present go with new entry */
+ if (old_entry_found) {
+ p_dev_rec = p_dev_old_rec;
+ if (malloc_new_entry) {
+ osi_free(p_dev_new_rec);
+ }
+ } else {
+ if (malloc_new_entry) {
+ list_append(btm_cb.p_sec_dev_rec_list, p_dev_new_rec);
+ }
+ p_dev_rec = p_dev_new_rec;
+ }
+ }
+ memset (p_dev_rec, 0, sizeof (tBTM_SEC_DEV_REC));
+
+ p_dev_rec->bond_type = BOND_TYPE_UNKNOWN; /* Default value */
+ p_dev_rec->sec_flags = BTM_SEC_IN_USE;
+
+ /* Check with the BT manager if details about remote device are known */
+ /* outgoing connection */
+ if ((p_inq_info = BTM_InqDbRead(bd_addr)) != NULL) {
+ memcpy (p_dev_rec->dev_class, p_inq_info->results.dev_class, DEV_CLASS_LEN);
+
+#if BLE_INCLUDED == TRUE
+ p_dev_rec->device_type = p_inq_info->results.device_type;
+ p_dev_rec->ble.ble_addr_type = p_inq_info->results.ble_addr_type;
+
+ /* update conn params, use default value for background connection params */
+ memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS));
+#endif
+ } else {
+#if BLE_INCLUDED == TRUE
+ /* update conn params, use default value for background connection params */
+ memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS));
+#endif
+
+ if (!memcmp (bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN)) {
+ memcpy (p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN);
+ }
+ }
+
+ memcpy (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN);
+
+#if BLE_INCLUDED == TRUE
+ p_dev_rec->ble_hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_LE);
+#endif
+ p_dev_rec->hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_BR_EDR);
+ p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+
+ return (p_dev_rec);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_sec_free_dev
+**
+** Description Mark device record as not used
+**
+*******************************************************************************/
+void btm_sec_free_dev (tBTM_SEC_DEV_REC *p_dev_rec, tBT_TRANSPORT transport)
+{
+ if (transport == BT_TRANSPORT_BR_EDR) {
+ memset(p_dev_rec->link_key, 0, LINK_KEY_LEN);
+ p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED
+ | BTM_SEC_ENCRYPTED | BTM_SEC_NAME_KNOWN
+ | BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED
+ | BTM_SEC_ROLE_SWITCHED | BTM_SEC_16_DIGIT_PIN_AUTHED);
+ } else if (transport == BT_TRANSPORT_LE) {
+ p_dev_rec->bond_type = BOND_TYPE_UNKNOWN;
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LE_AUTHENTICATED | BTM_SEC_LE_ENCRYPTED
+ | BTM_SEC_LE_NAME_KNOWN | BTM_SEC_LE_LINK_KEY_KNOWN
+ | BTM_SEC_LE_LINK_KEY_AUTHED | BTM_SEC_ROLE_SWITCHED);
+#if BLE_INCLUDED == TRUE
+ /* Clear out any saved BLE keys */
+ btm_sec_clear_ble_keys (p_dev_rec);
+#endif
+ } else {
+ p_dev_rec->bond_type = BOND_TYPE_UNKNOWN;
+ memset(p_dev_rec->link_key, 0, LINK_KEY_LEN);
+ p_dev_rec->sec_flags = 0;
+
+#if BLE_INCLUDED == TRUE
+ /* Clear out any saved BLE keys */
+ btm_sec_clear_ble_keys (p_dev_rec);
+#endif
+ }
+ /* No BLE keys and BT keys, clear the sec_flags */
+ if(p_dev_rec->sec_flags == BTM_SEC_IN_USE) {
+ p_dev_rec->sec_flags = 0;
+ }
+ list_remove(btm_cb.p_sec_dev_rec_list, p_dev_rec);
+}
+
+/*******************************************************************************
+**
+** Function btm_dev_support_switch
+**
+** Description This function is called by the L2CAP to check if remote
+** device supports role switch
+**
+** Parameters: bd_addr - Address of the peer device
+**
+** Returns TRUE if device is known and role switch is supported
+**
+*******************************************************************************/
+BOOLEAN btm_dev_support_switch (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ UINT8 xx;
+ BOOLEAN feature_empty = TRUE;
+
+#if BTM_SCO_INCLUDED == TRUE
+ /* Role switch is not allowed if a SCO is up */
+ if (btm_is_sco_active_by_bdaddr(bd_addr)) {
+ return (FALSE);
+ }
+#endif
+ p_dev_rec = btm_find_dev (bd_addr);
+ if (p_dev_rec && controller_get_interface()->supports_master_slave_role_switch()) {
+ if (HCI_SWITCH_SUPPORTED(p_dev_rec->features[HCI_EXT_FEATURES_PAGE_0])) {
+ BTM_TRACE_DEBUG("btm_dev_support_switch return TRUE (feature found)\n");
+ return (TRUE);
+ }
+
+ /* If the feature field is all zero, we never received them */
+ for (xx = 0 ; xx < BD_FEATURES_LEN ; xx++) {
+ if (p_dev_rec->features[HCI_EXT_FEATURES_PAGE_0][xx] != 0x00) {
+ feature_empty = FALSE; /* at least one is != 0 */
+ break;
+ }
+ }
+
+ /* If we don't know peer's capabilities, assume it supports Role-switch */
+ if (feature_empty) {
+ BTM_TRACE_DEBUG("btm_dev_support_switch return TRUE (feature empty)\n");
+ return (TRUE);
+ }
+ }
+
+ BTM_TRACE_DEBUG("btm_dev_support_switch return FALSE\n");
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function btm_find_dev_by_handle
+**
+** Description Look for the record in the device database for the record
+** with specified handle
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_find_dev_by_handle (UINT16 handle)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+ list_node_t *p_node = NULL;
+ tSecDevContext context;
+ context.type = SEC_DEV_HDL;
+ context.context.handle = handle;
+ context.free_check = FALSE;
+
+ p_node = list_foreach(btm_cb.p_sec_dev_rec_list, btm_find_sec_dev_in_list, &context);
+ if (p_node) {
+ p_dev_rec = list_node(p_node);
+ }
+ return (p_dev_rec);
+}
+/*******************************************************************************
+**
+** Function btm_find_dev
+**
+** Description Look for the record in the device database for the record
+** with specified BD address
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_find_dev(BD_ADDR bd_addr)
+{
+ if(bd_addr) {
+ list_node_t *p_node = NULL;
+ tSecDevContext context;
+ context.type = SEC_DEV_BTDM_BDA;
+ context.context.p_bd_addr = bd_addr;
+ context.free_check = FALSE;
+ p_node = list_foreach(btm_cb.p_sec_dev_rec_list, btm_find_sec_dev_in_list, &context);
+ if (p_node) {
+ return(list_node(p_node));
+ }
+ }
+ return (NULL);
+}
+/*******************************************************************************
+**
+** Function btm_consolidate_dev
+**
+** Description combine security records if identified as same peer
+**
+** Returns none
+**
+*******************************************************************************/
+void btm_consolidate_dev(tBTM_SEC_DEV_REC *p_target_rec)
+{
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+ tBTM_SEC_DEV_REC temp_rec = *p_target_rec;
+ list_node_t *p_node = NULL;
+ BTM_TRACE_DEBUG("%s\n", __func__);
+
+ for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
+ p_dev_rec = list_node(p_node);
+ if (p_target_rec != p_dev_rec && p_dev_rec->sec_flags & BTM_SEC_IN_USE) {
+ if (!memcmp (p_dev_rec->bd_addr, p_target_rec->bd_addr, BD_ADDR_LEN)) {
+ memcpy(p_target_rec, p_dev_rec, sizeof(tBTM_SEC_DEV_REC));
+ p_target_rec->ble = temp_rec.ble;
+ p_target_rec->ble_hci_handle = temp_rec.ble_hci_handle;
+ p_target_rec->enc_key_size = temp_rec.enc_key_size;
+ p_target_rec->conn_params = temp_rec.conn_params;
+ p_target_rec->device_type |= temp_rec.device_type;
+ p_target_rec->sec_flags |= temp_rec.sec_flags;
+
+ p_target_rec->new_encryption_key_is_p256 = temp_rec.new_encryption_key_is_p256;
+ p_target_rec->no_smp_on_br = temp_rec.no_smp_on_br;
+ p_target_rec->bond_type = temp_rec.bond_type;
+ /* Remove the unused device from the list */
+ list_remove(btm_cb.p_sec_dev_rec_list, p_dev_rec);
+ break;
+ }
+
+ /* an RPA device entry is a duplicate of the target record */
+ if (btm_ble_addr_resolvable(p_dev_rec->bd_addr, p_target_rec)) {
+ if (memcmp(p_target_rec->ble.pseudo_addr, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0) {
+ p_target_rec->ble.ble_addr_type = p_dev_rec->ble.ble_addr_type;
+ p_target_rec->device_type |= p_dev_rec->device_type;
+ /* Remove the unused device from the list */
+ list_remove(btm_cb.p_sec_dev_rec_list, p_dev_rec);
+ }
+ break;
+ }
+ }
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_find_or_alloc_dev
+**
+** Description Look for the record in the device database for the record
+** with specified BD address
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_find_or_alloc_dev (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BTM_TRACE_EVENT ("btm_find_or_alloc_dev\n");
+ if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL) {
+
+ /* Allocate a new device record or reuse the oldest one */
+ p_dev_rec = btm_sec_alloc_dev (bd_addr);
+ }
+ return (p_dev_rec);
+}
+
+/*******************************************************************************
+**
+** Function btm_find_oldest_dev
+**
+** Description Locates the oldest device in use. It first looks for
+** the oldest non-paired device. If all devices are paired it
+** deletes the oldest paired device.
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_find_oldest_dev (void)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+ tBTM_SEC_DEV_REC *p_oldest = NULL;
+ list_node_t *p_node = NULL;
+ UINT32 ot = 0xFFFFFFFF;
+
+ /* First look for the non-paired devices for the oldest entry */
+ for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
+ p_dev_rec = list_node(p_node);
+ if (((p_dev_rec->sec_flags & BTM_SEC_IN_USE) == 0)
+ || ((p_dev_rec->sec_flags & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LE_LINK_KEY_KNOWN)) != 0)) {
+ continue; /* Device is paired so skip it */
+ }
+
+ if (p_dev_rec->timestamp < ot) {
+ p_oldest = p_dev_rec;
+ ot = p_dev_rec->timestamp;
+ }
+ }
+
+ if (ot != 0xFFFFFFFF) {
+ return (p_oldest);
+ }
+
+ /* All devices are paired; find the oldest */
+ for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
+ if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE) == 0) {
+ continue;
+ }
+
+ if (p_dev_rec->timestamp < ot) {
+ p_oldest = p_dev_rec;
+ ot = p_dev_rec->timestamp;
+ }
+ }
+ return (p_oldest);
+}
+/*******************************************************************************
+**
+** Function btm_get_bond_type_dev
+**
+** Description Get the bond type for a device in the device database
+** with specified BD address
+**
+** Returns The device bond type if known, otherwise BOND_TYPE_UNKNOWN
+**
+*******************************************************************************/
+tBTM_BOND_TYPE btm_get_bond_type_dev(BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr);
+
+ if (p_dev_rec == NULL) {
+ return BOND_TYPE_UNKNOWN;
+ }
+
+ return p_dev_rec->bond_type;
+}
+
+/*******************************************************************************
+**
+** Function btm_set_bond_type_dev
+**
+** Description Set the bond type for a device in the device database
+** with specified BD address
+**
+** Returns TRUE on success, otherwise FALSE
+**
+*******************************************************************************/
+BOOLEAN btm_set_bond_type_dev(BD_ADDR bd_addr, tBTM_BOND_TYPE bond_type)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr);
+
+ if (p_dev_rec == NULL) {
+ return FALSE;
+ }
+
+ p_dev_rec->bond_type = bond_type;
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_dev_init
+**
+** Description Create new linked list for dynamic allocation on sec_dev_rec
+**
+*******************************************************************************/
+void btm_sec_dev_init(void)
+{
+ btm_cb.p_sec_dev_rec_list = list_new(osi_free_func);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_dev_free
+**
+** Description Delete sec_dev_rec list when btm_cb is being released
+**
+*******************************************************************************/
+void btm_sec_dev_free(void)
+{
+ list_free(btm_cb.p_sec_dev_rec_list);
+}
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_devctl.c b/lib/bt/host/bluedroid/stack/btm/btm_devctl.c
new file mode 100644
index 00000000..bffb5bbe
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_devctl.c
@@ -0,0 +1,1294 @@
+/******************************************************************************
+ *
+ * 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 functions that handle BTM interface functions for the
+ * Bluetooth device including Rest, HCI buffer size and others
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+//#include <stdio.h>
+#include <stddef.h>
+#include "common/bt_trace.h"
+#include "stack/bt_types.h"
+//#include "bt_utils.h"
+#include "btm_int.h"
+#include "stack/btu.h"
+#include "device/controller.h"
+#include "hci/hci_layer.h"
+#include "stack/hcimsgs.h"
+#include "l2c_int.h"
+//#include "btcore/include/module.h"
+//#include "osi/include/osi/thread.h"
+
+#if BLE_INCLUDED == TRUE
+#include "gatt_int.h"
+#endif /* BLE_INCLUDED */
+
+//extern thread_t *bt_workqueue_thread;
+
+/********************************************************************************/
+/* L O C A L D A T A D E F I N I T I O N S */
+/********************************************************************************/
+
+#ifndef BTM_DEV_RESET_TIMEOUT
+#define BTM_DEV_RESET_TIMEOUT 4
+#endif
+
+#define BTM_DEV_REPLY_TIMEOUT 2 /* 1 second expiration time is not good. Timer may start between 0 and 1 second. */
+/* if it starts at the very end of the 0 second, timer will expire really easily. */
+
+#define BTM_INFO_TIMEOUT 5 /* 5 seconds for info response */
+
+/********************************************************************************/
+/* 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 btm_decode_ext_features_page (UINT8 page_number, const BD_FEATURES p_features);
+
+/*******************************************************************************
+**
+** Function btm_dev_init
+**
+** Description This function is on the BTM startup
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_dev_init (void)
+{
+#if 0 /* cleared in btm_init; put back in if called from anywhere else! */
+ memset (&btm_cb.devcb, 0, sizeof (tBTM_DEVCB));
+#endif
+
+ /* Initialize nonzero defaults */
+#if (BTM_MAX_LOC_BD_NAME_LEN > 0)
+ memset(btm_cb.cfg.bd_name, 0, sizeof(tBTM_LOC_BD_NAME));
+#endif
+
+ btm_cb.devcb.reset_timer.param = (TIMER_PARAM_TYPE)TT_DEV_RESET;
+ btm_cb.devcb.rln_timer.param = (TIMER_PARAM_TYPE)TT_DEV_RLN;
+
+ btm_cb.btm_acl_pkt_types_supported = BTM_ACL_PKT_TYPES_MASK_DH1 + BTM_ACL_PKT_TYPES_MASK_DM1 +
+ BTM_ACL_PKT_TYPES_MASK_DH3 + BTM_ACL_PKT_TYPES_MASK_DM3 +
+ BTM_ACL_PKT_TYPES_MASK_DH5 + BTM_ACL_PKT_TYPES_MASK_DM5;
+
+ btm_cb.btm_sco_pkt_types_supported = BTM_SCO_PKT_TYPES_MASK_HV1 +
+ BTM_SCO_PKT_TYPES_MASK_HV2 +
+ BTM_SCO_PKT_TYPES_MASK_HV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV4 +
+ BTM_SCO_PKT_TYPES_MASK_EV5;
+}
+
+
+/*******************************************************************************
+**
+** Function btm_db_reset
+**
+** Description This function is called by BTM_DeviceReset and clears out any
+** pending callbacks for inquiries, discoveries, other pending
+** functions that may be in progress.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_db_reset (void)
+{
+ tBTM_CMPL_CB *p_cb;
+ tBTM_STATUS status = BTM_DEV_RESET;
+
+ btm_inq_db_reset();
+
+ if (btm_cb.devcb.p_rln_cmpl_cb) {
+ p_cb = btm_cb.devcb.p_rln_cmpl_cb;
+ btm_cb.devcb.p_rln_cmpl_cb = NULL;
+
+ if (p_cb) {
+ (*p_cb)((void *) NULL);
+ }
+ }
+
+ if (btm_cb.devcb.p_rssi_cmpl_cb) {
+ p_cb = btm_cb.devcb.p_rssi_cmpl_cb;
+ btm_cb.devcb.p_rssi_cmpl_cb = NULL;
+
+ if (p_cb) {
+ (*p_cb)((tBTM_RSSI_RESULTS *) &status);
+ }
+ }
+}
+
+static void reset_complete(void)
+{
+ const controller_t *controller = controller_get_interface();
+
+ /* Tell L2CAP that all connections are gone */
+ l2cu_device_reset ();
+#if (SMP_INCLUDED == TRUE)
+ /* Clear current security state */
+ {
+ list_node_t *p_node = NULL;
+ for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
+ tBTM_SEC_DEV_REC *p_dev_rec = (tBTM_SEC_DEV_REC *) list_node(p_node);
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ }
+ }
+#endif ///SMP_INCLUDED == TRUE
+ /* After the reset controller should restore all parameters to defaults. */
+ btm_cb.btm_inq_vars.inq_counter = 1;
+ btm_cb.btm_inq_vars.inq_scan_window = HCI_DEF_INQUIRYSCAN_WINDOW;
+ btm_cb.btm_inq_vars.inq_scan_period = HCI_DEF_INQUIRYSCAN_INTERVAL;
+ btm_cb.btm_inq_vars.inq_scan_type = HCI_DEF_SCAN_TYPE;
+
+ btm_cb.btm_inq_vars.page_scan_window = HCI_DEF_PAGESCAN_WINDOW;
+ btm_cb.btm_inq_vars.page_scan_period = HCI_DEF_PAGESCAN_INTERVAL;
+ btm_cb.btm_inq_vars.page_scan_type = HCI_DEF_SCAN_TYPE;
+ btm_cb.btm_inq_vars.page_timeout = HCI_DEFAULT_PAGE_TOUT;
+
+#if (BLE_INCLUDED == TRUE)
+ btm_cb.ble_ctr_cb.conn_state = BLE_CONN_IDLE;
+ btm_cb.ble_ctr_cb.bg_conn_type = BTM_BLE_CONN_NONE;
+ btm_cb.ble_ctr_cb.p_select_cback = NULL;
+ gatt_reset_bgdev_list();
+ btm_ble_multi_adv_init();
+#endif
+
+ btm_pm_reset();
+
+ l2c_link_processs_num_bufs(controller->get_acl_buffer_count_classic());
+#if BTM_SCO_HCI_INCLUDED == TRUE
+ btm_sco_process_num_bufs(controller->get_sco_buffer_count());
+#endif
+#if (BLE_INCLUDED == TRUE)
+
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+ /* Set up the BLE privacy settings */
+ if (controller->supports_ble() && controller->supports_ble_privacy() &&
+ controller->get_ble_resolving_list_max_size() > 0) {
+ btm_ble_resolving_list_init(controller->get_ble_resolving_list_max_size());
+ /* set the default random private address timeout */
+ btsnd_hcic_ble_set_rand_priv_addr_timeout(BTM_BLE_PRIVATE_ADDR_INT);
+ }
+#endif
+
+ if (controller->supports_ble()) {
+ btm_ble_white_list_init(controller->get_ble_white_list_size());
+ l2c_link_processs_ble_num_bufs(controller->get_acl_buffer_count_ble());
+ }
+#endif
+#if (SMP_INCLUDED == TRUE && CLASSIC_BT_INCLUDED == TRUE)
+ BTM_SetPinType (btm_cb.cfg.pin_type, btm_cb.cfg.pin_code, btm_cb.cfg.pin_code_len);
+#endif ///SMP_INCLUDED == TRUE && CLASSIC_BT_INCLUDED == TRUE
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ BTM_WritePageTimeout(btm_cb.btm_inq_vars.page_timeout, NULL);
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+ for (int i = 0; i <= controller->get_last_features_classic_index(); i++) {
+ btm_decode_ext_features_page(i, controller->get_features_classic(i)->as_array);
+ }
+
+ btm_report_device_status(BTM_DEV_STATUS_UP);
+}
+
+// TODO(zachoverflow): remove this function
+void BTM_DeviceReset (UNUSED_ATTR tBTM_CMPL_CB *p_cb)
+{
+ /* Flush all ACL connections */
+ btm_acl_device_down();
+
+ /* Clear the callback, so application would not hang on reset */
+ btm_db_reset();
+
+ /* todo: review the below logic; start_up executes under another task context
+ * reset_complete runs in btu task */
+ controller_get_interface()->start_up();
+ reset_complete();
+}
+
+/*******************************************************************************
+**
+** Function BTM_IsDeviceUp
+**
+** Description This function is called to check if the device is up.
+**
+** Returns TRUE if device is up, else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_IsDeviceUp (void)
+{
+ return controller_get_interface()->get_is_ready();
+}
+
+/*******************************************************************************
+**
+** Function btm_dev_timeout
+**
+** Description This function is called when a timer list entry expires.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_dev_timeout (TIMER_LIST_ENT *p_tle)
+{
+ TIMER_PARAM_TYPE timer_type = (TIMER_PARAM_TYPE)p_tle->param;
+
+ if (timer_type == (TIMER_PARAM_TYPE)TT_DEV_RLN) {
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_rln_cmpl_cb;
+
+ btm_cb.devcb.p_rln_cmpl_cb = NULL;
+
+ if (p_cb) {
+ (*p_cb)((void *) NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_decode_ext_features_page
+**
+** Description This function is decodes a features page.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_decode_ext_features_page (UINT8 page_number, const BD_FEATURES p_features)
+{
+ BTM_TRACE_DEBUG ("btm_decode_ext_features_page page: %d", page_number);
+ switch (page_number) {
+ /* Extended (Legacy) Page 0 */
+ case HCI_EXT_FEATURES_PAGE_0:
+
+ /* Create ACL supported packet types mask */
+ btm_cb.btm_acl_pkt_types_supported = (BTM_ACL_PKT_TYPES_MASK_DH1 +
+ BTM_ACL_PKT_TYPES_MASK_DM1);
+
+ if (HCI_3_SLOT_PACKETS_SUPPORTED(p_features)) {
+ btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_DH3 +
+ BTM_ACL_PKT_TYPES_MASK_DM3);
+ }
+
+ if (HCI_5_SLOT_PACKETS_SUPPORTED(p_features)) {
+ btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_DH5 +
+ BTM_ACL_PKT_TYPES_MASK_DM5);
+ }
+
+ /* Add in EDR related ACL types */
+ if (!HCI_EDR_ACL_2MPS_SUPPORTED(p_features)) {
+ btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH1 +
+ BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 +
+ BTM_ACL_PKT_TYPES_MASK_NO_2_DH5);
+ }
+
+ if (!HCI_EDR_ACL_3MPS_SUPPORTED(p_features)) {
+ btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_3_DH1 +
+ BTM_ACL_PKT_TYPES_MASK_NO_3_DH3 +
+ BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+ }
+
+ /* Check to see if 3 and 5 slot packets are available */
+ if (HCI_EDR_ACL_2MPS_SUPPORTED(p_features) ||
+ HCI_EDR_ACL_3MPS_SUPPORTED(p_features)) {
+ if (!HCI_3_SLOT_EDR_ACL_SUPPORTED(p_features)) {
+ btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 +
+ BTM_ACL_PKT_TYPES_MASK_NO_3_DH3);
+ }
+
+ if (!HCI_5_SLOT_EDR_ACL_SUPPORTED(p_features)) {
+ btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH5 +
+ BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+ }
+ }
+
+ BTM_TRACE_DEBUG("Local supported ACL packet types: 0x%04x",
+ btm_cb.btm_acl_pkt_types_supported);
+
+ /* Create (e)SCO supported packet types mask */
+ btm_cb.btm_sco_pkt_types_supported = 0;
+#if BTM_SCO_INCLUDED == TRUE
+ btm_cb.sco_cb.esco_supported = FALSE;
+#endif
+ if (HCI_SCO_LINK_SUPPORTED(p_features)) {
+ btm_cb.btm_sco_pkt_types_supported = BTM_SCO_PKT_TYPES_MASK_HV1;
+
+ if (HCI_HV2_PACKETS_SUPPORTED(p_features)) {
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_HV2;
+ }
+
+ if (HCI_HV3_PACKETS_SUPPORTED(p_features)) {
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_HV3;
+ }
+ }
+
+ if (HCI_ESCO_EV3_SUPPORTED(p_features)) {
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_EV3;
+ }
+
+ if (HCI_ESCO_EV4_SUPPORTED(p_features)) {
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_EV4;
+ }
+
+ if (HCI_ESCO_EV5_SUPPORTED(p_features)) {
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_EV5;
+ }
+#if BTM_SCO_INCLUDED == TRUE
+ if (btm_cb.btm_sco_pkt_types_supported & BTM_ESCO_LINK_ONLY_MASK) {
+ btm_cb.sco_cb.esco_supported = TRUE;
+
+ /* Add in EDR related eSCO types */
+ if (HCI_EDR_ESCO_2MPS_SUPPORTED(p_features)) {
+ if (!HCI_3_SLOT_EDR_ESCO_SUPPORTED(p_features)) {
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_NO_2_EV5;
+ }
+ } else {
+ btm_cb.btm_sco_pkt_types_supported |= (BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 +
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5);
+ }
+
+ if (HCI_EDR_ESCO_3MPS_SUPPORTED(p_features)) {
+ if (!HCI_3_SLOT_EDR_ESCO_SUPPORTED(p_features)) {
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_NO_3_EV5;
+ }
+ } else {
+ btm_cb.btm_sco_pkt_types_supported |= (BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 +
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5);
+ }
+ }
+#endif
+
+ BTM_TRACE_DEBUG("Local supported SCO packet types: 0x%04x",
+ btm_cb.btm_sco_pkt_types_supported);
+
+ /* Create Default Policy Settings */
+ if (HCI_SWITCH_SUPPORTED(p_features)) {
+ btm_cb.btm_def_link_policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ } else {
+ btm_cb.btm_def_link_policy &= ~HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ }
+
+ if (HCI_HOLD_MODE_SUPPORTED(p_features)) {
+ btm_cb.btm_def_link_policy |= HCI_ENABLE_HOLD_MODE;
+ } else {
+ btm_cb.btm_def_link_policy &= ~HCI_ENABLE_HOLD_MODE;
+ }
+
+ if (HCI_SNIFF_MODE_SUPPORTED(p_features)) {
+ btm_cb.btm_def_link_policy |= HCI_ENABLE_SNIFF_MODE;
+ } else {
+ btm_cb.btm_def_link_policy &= ~HCI_ENABLE_SNIFF_MODE;
+ }
+
+ if (HCI_PARK_MODE_SUPPORTED(p_features)) {
+ btm_cb.btm_def_link_policy |= HCI_ENABLE_PARK_MODE;
+ } else {
+ btm_cb.btm_def_link_policy &= ~HCI_ENABLE_PARK_MODE;
+ }
+
+ btm_sec_dev_reset ();
+
+ if (HCI_LMP_INQ_RSSI_SUPPORTED(p_features)) {
+ if (HCI_EXT_INQ_RSP_SUPPORTED(p_features)) {
+ BTM_SetInquiryMode (BTM_INQ_RESULT_EXTENDED);
+ } else {
+ BTM_SetInquiryMode (BTM_INQ_RESULT_WITH_RSSI);
+ }
+ }
+
+#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE
+ if ( HCI_NON_FLUSHABLE_PB_SUPPORTED(p_features)) {
+ l2cu_set_non_flushable_pbf(TRUE);
+ } else {
+ l2cu_set_non_flushable_pbf(FALSE);
+ }
+#endif
+ BTM_SetPageScanType (BTM_DEFAULT_SCAN_TYPE);
+ BTM_SetInquiryScanType (BTM_DEFAULT_SCAN_TYPE);
+
+ break;
+
+ /* Extended Page 1 */
+ case HCI_EXT_FEATURES_PAGE_1:
+ /* Nothing to do for page 1 */
+ break;
+
+ /* Extended Page 2 */
+ case HCI_EXT_FEATURES_PAGE_2:
+ /* Nothing to do for page 2 */
+ break;
+
+ default:
+ BTM_TRACE_ERROR("btm_decode_ext_features_page page=%d unknown", page_number);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetLocalDeviceName
+**
+** Description This function is called to set the local device name.
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetLocalDeviceName (char *p_name)
+{
+ UINT8 *p;
+
+ if (!p_name || !p_name[0] || (strlen ((char *)p_name) > BD_NAME_LEN)) {
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ if (!controller_get_interface()->get_is_ready()) {
+ return (BTM_DEV_RESET);
+ }
+
+#if BTM_MAX_LOC_BD_NAME_LEN > 0
+ /* Save the device name if local storage is enabled */
+ p = (UINT8 *)btm_cb.cfg.bd_name;
+ if (p != (UINT8 *)p_name) {
+ BCM_STRNCPY_S(btm_cb.cfg.bd_name, p_name, BTM_MAX_LOC_BD_NAME_LEN);
+ btm_cb.cfg.bd_name[BTM_MAX_LOC_BD_NAME_LEN] = '\0';
+ }
+#else
+ p = (UINT8 *)p_name;
+#endif
+#if CLASSIC_BT_INCLUDED
+ if (btsnd_hcic_change_name(p)) {
+ return (BTM_CMD_STARTED);
+ } else
+#endif
+ {
+ return (BTM_NO_RESOURCES);
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalDeviceName
+**
+** Description This function is called to read the local device name.
+**
+** Returns status of the operation
+** If success, BTM_SUCCESS is returned and p_name points stored
+** local device name
+** If BTM doesn't store local device name, BTM_NO_RESOURCES is
+** is returned and p_name is set to NULL
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadLocalDeviceName (char **p_name)
+{
+#if BTM_MAX_LOC_BD_NAME_LEN > 0
+ *p_name = btm_cb.cfg.bd_name;
+ return (BTM_SUCCESS);
+#else
+ *p_name = NULL;
+ return (BTM_NO_RESOURCES);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalDeviceNameFromController
+**
+** Description Get local device name from controller. Do not use cached
+** name (used to get chip-id prior to btm reset complete).
+**
+** Returns BTM_CMD_STARTED if successful, otherwise an error
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadLocalDeviceNameFromController (tBTM_CMPL_CB *p_rln_cmpl_cback)
+{
+ /* Check if rln already in progress */
+ if (btm_cb.devcb.p_rln_cmpl_cb) {
+ return (BTM_NO_RESOURCES);
+ }
+
+ /* Save callback */
+ btm_cb.devcb.p_rln_cmpl_cb = p_rln_cmpl_cback;
+
+ btsnd_hcic_read_name();
+ btu_start_timer (&btm_cb.devcb.rln_timer, BTU_TTYPE_BTM_DEV_CTL, BTM_DEV_REPLY_TIMEOUT);
+
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function btm_read_local_name_complete
+**
+** Description This function is called when local name read complete.
+** message is received from the HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_local_name_complete (UINT8 *p, UINT16 evt_len)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_rln_cmpl_cb;
+ UINT8 status;
+ UNUSED(evt_len);
+
+ btu_free_timer (&btm_cb.devcb.rln_timer);
+
+ /* If there was a callback address for read local name, call it */
+ btm_cb.devcb.p_rln_cmpl_cb = NULL;
+
+ if (p_cb) {
+ STREAM_TO_UINT8 (status, p);
+
+ if (status == HCI_SUCCESS) {
+ (*p_cb)(p);
+ } else {
+ (*p_cb)(NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetDeviceClass
+**
+** Description This function is called to set the local device class
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetDeviceClass (DEV_CLASS dev_class)
+{
+ if (!memcmp (btm_cb.devcb.dev_class, dev_class, DEV_CLASS_LEN)) {
+ return (BTM_SUCCESS);
+ }
+
+ memcpy (btm_cb.devcb.dev_class, dev_class, DEV_CLASS_LEN);
+
+ if (!controller_get_interface()->get_is_ready()) {
+ return (BTM_DEV_RESET);
+ }
+
+ if (!btsnd_hcic_write_dev_class (dev_class)) {
+ return (BTM_NO_RESOURCES);
+ }
+
+ return (BTM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadDeviceClass
+**
+** Description This function is called to read the local device class
+**
+** Returns pointer to the device class
+**
+*******************************************************************************/
+UINT8 *BTM_ReadDeviceClass (void)
+{
+ return ((UINT8 *)btm_cb.devcb.dev_class);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalFeatures
+**
+** Description This function is called to read the local features
+**
+** Returns pointer to the local features string
+**
+*******************************************************************************/
+// TODO(zachoverflow): get rid of this function
+UINT8 *BTM_ReadLocalFeatures (void)
+{
+ // Discarding const modifier for now, until this function dies
+ return (UINT8 *)controller_get_interface()->get_features_classic(0)->as_array;
+}
+
+/*******************************************************************************
+**
+** Function BTM_RegisterForDeviceStatusNotif
+**
+** Description This function is called to register for device status
+** change notifications.
+**
+** If one registration is already there calling function should
+** save the pointer to the function that is return and
+** call it when processing of the event is complete
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_DEV_STATUS_CB *BTM_RegisterForDeviceStatusNotif (tBTM_DEV_STATUS_CB *p_cb)
+{
+ tBTM_DEV_STATUS_CB *p_prev = btm_cb.devcb.p_dev_status_cb;
+
+ btm_cb.devcb.p_dev_status_cb = p_cb;
+ return (p_prev);
+}
+
+/*******************************************************************************
+**
+** Function BTM_VendorSpecificCommand
+**
+** Description Send a vendor specific HCI command to the controller.
+**
+** Returns
+** BTM_SUCCESS Command sent. Does not expect command complete
+** event. (command cmpl callback param is NULL)
+** BTM_CMD_STARTED Command sent. Waiting for command cmpl event.
+**
+** Notes
+** Opcode will be OR'd with HCI_GRP_VENDOR_SPECIFIC.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_VendorSpecificCommand(UINT16 opcode, UINT8 param_len,
+ UINT8 *p_param_buf, tBTM_VSC_CMPL_CB *p_cb)
+{
+ BT_HDR *p_buf;
+
+ BTM_TRACE_EVENT ("BTM: BTM_VendorSpecificCommand: Opcode: 0x%04X, ParamLen: %i.",
+ opcode, param_len);
+
+ /* Allocate a buffer to hold HCI command plus the callback function */
+ if ((p_buf = HCI_GET_CMD_BUF(param_len)) != NULL) {
+ /* Send the HCI command (opcode will be OR'd with HCI_GRP_VENDOR_SPECIFIC) */
+ btsnd_hcic_vendor_spec_cmd (p_buf, opcode, param_len, p_param_buf, (void *)p_cb);
+
+ /* Return value */
+ if (p_cb != NULL) {
+ return (BTM_CMD_STARTED);
+ } else {
+ return (BTM_SUCCESS);
+ }
+ } else {
+ return (BTM_NO_RESOURCES);
+ }
+
+}
+
+#if (ESP_COEX_VSC_INCLUDED == TRUE)
+tBTM_STATUS BTM_ConfigCoexStatus(tBTM_COEX_OPERATION op, tBTM_COEX_TYPE type, UINT8 status)
+{
+ UINT8 param[3];
+ UINT8 *p = (UINT8 *)param;
+
+ UINT8_TO_STREAM(p, type);
+ UINT8_TO_STREAM(p, op);
+ UINT8_TO_STREAM(p, status);
+
+ return BTM_VendorSpecificCommand(HCI_VENDOR_COMMON_COEX_STATUS_CMD_OPCODE, 3, param, NULL);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function btm_vsc_complete
+**
+** Description This function is called when local HCI Vendor Specific
+** Command complete message is received from the HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_vsc_complete (UINT8 *p, UINT16 opcode, UINT16 evt_len,
+ tBTM_CMPL_CB *p_vsc_cplt_cback)
+{
+#if (BLE_INCLUDED == TRUE)
+ tBTM_BLE_CB *ble_cb = &btm_cb.ble_ctr_cb;
+ switch(opcode) {
+ case HCI_VENDOR_BLE_LONG_ADV_DATA:
+ BTM_TRACE_EVENT("Set long adv data complete\n");
+ break;
+ case HCI_VENDOR_BLE_UPDATE_DUPLICATE_EXCEPTIONAL_LIST: {
+ uint8_t subcode, status; uint32_t length;
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT8(subcode, p);
+ STREAM_TO_UINT32(length, p);
+ if(ble_cb && ble_cb->update_exceptional_list_cmp_cb) {
+ (*ble_cb->update_exceptional_list_cmp_cb)(status, subcode, length, p);
+ }
+ break;
+ }
+ case HCI_VENDOR_BLE_CLEAR_ADV: {
+ uint8_t status;
+ STREAM_TO_UINT8(status, p);
+ if (ble_cb && ble_cb->inq_var.p_clear_adv_cb) {
+ ble_cb->inq_var.p_clear_adv_cb(status);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ tBTM_VSC_CMPL vcs_cplt_params;
+
+ /* If there was a callback address for vcs complete, call it */
+ if (p_vsc_cplt_cback) {
+ /* Pass paramters to the callback function */
+ vcs_cplt_params.opcode = opcode; /* Number of bytes in return info */
+ vcs_cplt_params.param_len = evt_len; /* Number of bytes in return info */
+ vcs_cplt_params.p_param_buf = p;
+ (*p_vsc_cplt_cback)(&vcs_cplt_params); /* Call the VSC complete callback function */
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_RegisterForVSEvents
+**
+** Description This function is called to register/deregister for vendor
+** specific HCI events.
+**
+** If is_register=TRUE, then the function will be registered;
+** if is_register=FALSE, then the function will be deregistered.
+**
+** Returns BTM_SUCCESS if successful,
+** BTM_BUSY if maximum number of callbacks have already been
+** registered.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_RegisterForVSEvents (tBTM_VS_EVT_CB *p_cb, BOOLEAN is_register)
+{
+ tBTM_STATUS retval = BTM_SUCCESS;
+ UINT8 i, free_idx = BTM_MAX_VSE_CALLBACKS;
+
+ /* See if callback is already registered */
+ for (i = 0; i < BTM_MAX_VSE_CALLBACKS; i++) {
+ if (btm_cb.devcb.p_vend_spec_cb[i] == NULL) {
+ /* Found a free slot. Store index */
+ free_idx = i;
+ } else if (btm_cb.devcb.p_vend_spec_cb[i] == p_cb) {
+ /* Found callback in lookup table. If deregistering, clear the entry. */
+ if (is_register == FALSE) {
+ btm_cb.devcb.p_vend_spec_cb[i] = NULL;
+ BTM_TRACE_EVENT("BTM Deregister For VSEvents is successfully");
+ }
+ return (BTM_SUCCESS);
+ }
+ }
+
+ /* Didn't find callback. Add callback to free slot if registering */
+ if (is_register) {
+ if (free_idx < BTM_MAX_VSE_CALLBACKS) {
+ btm_cb.devcb.p_vend_spec_cb[free_idx] = p_cb;
+ BTM_TRACE_EVENT("BTM Register For VSEvents is successfully");
+ } else {
+ /* No free entries available */
+ BTM_TRACE_ERROR ("BTM_RegisterForVSEvents: too many callbacks registered");
+
+ retval = BTM_NO_RESOURCES;
+ }
+ }
+
+ return (retval);
+}
+
+/*******************************************************************************
+**
+** Function btm_vendor_specific_evt
+**
+** Description Process event HCI_VENDOR_SPECIFIC_EVT
+**
+** Note: Some controllers do not send command complete, so
+** the callback and busy flag are cleared here also.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_vendor_specific_evt (UINT8 *p, UINT8 evt_len)
+{
+ UINT8 i;
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ UINT8 sub_event;
+ UINT8 *p_evt = p;
+
+ STREAM_TO_UINT8(sub_event, p_evt);
+ /* Check in subevent if authentication is through Legacy Authentication. */
+ if (sub_event == ESP_VS_REM_LEGACY_AUTH_CMP) {
+ UINT16 hci_handle;
+ STREAM_TO_UINT16(hci_handle, p_evt);
+ btm_sec_handle_remote_legacy_auth_cmp(hci_handle);
+ }
+#endif /// (CLASSIC_BT_INCLUDED == TRUE)
+ for (i = 0; i < BTM_MAX_VSE_CALLBACKS; i++) {
+ if (btm_cb.devcb.p_vend_spec_cb[i]) {
+ (*btm_cb.devcb.p_vend_spec_cb[i])(evt_len, p);
+ }
+ }
+ BTM_TRACE_DEBUG ("BTM Event: Vendor Specific event from controller");
+}
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function BTM_WritePageTimeout
+**
+** Description Send HCI Write Page Timeout.
+**
+** Returns
+** BTM_SUCCESS Command sent.
+** BTM_NO_RESOURCES If out of resources to send the command.
+**
+**
+*******************************************************************************/
+tBTM_STATUS BTM_WritePageTimeout(UINT16 timeout, tBTM_CMPL_CB *p_cb)
+{
+ BTM_TRACE_EVENT ("BTM: BTM_WritePageTimeout: Timeout: %d.", timeout);
+
+ if (timeout >= HCI_MIN_PAGE_TOUT) {
+ btm_cb.btm_inq_vars.page_timeout = timeout;
+ }
+ btm_cb.devcb.p_page_to_set_cmpl_cb = p_cb;
+
+ /* Send the HCI command */
+ if (!btsnd_hcic_write_page_tout (timeout)) {
+ return (BTM_NO_RESOURCES);
+ }
+
+ if (p_cb) {
+ btu_start_timer(&btm_cb.devcb.page_timeout_set_timer, BTU_TTYPE_BTM_SET_PAGE_TO, BTM_DEV_REPLY_TIMEOUT);
+ }
+
+ return (BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+**
+** Function btm_set_page_timeout_complete
+**
+** Description This function is called when setting page timeout complete.
+** message is received from the HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_set_page_timeout_complete (const UINT8 *p)
+{
+ tBTM_SET_PAGE_TIMEOUT_RESULTS results;
+
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_page_to_set_cmpl_cb;
+ btm_cb.devcb.p_page_to_set_cmpl_cb = NULL;
+ btu_free_timer (&btm_cb.devcb.page_timeout_set_timer);
+
+ /* If there is a callback address for setting page timeout, call it */
+ if (p_cb) {
+ if (p) {
+ STREAM_TO_UINT8 (results.hci_status, p);
+ switch (results.hci_status) {
+ case HCI_SUCCESS:
+ results.status = BTM_SUCCESS;
+ break;
+ case HCI_ERR_UNSUPPORTED_VALUE:
+ case HCI_ERR_ILLEGAL_PARAMETER_FMT:
+ results.status = BTM_ILLEGAL_VALUE;
+ break;
+ default:
+ results.status = BTM_NO_RESOURCES;
+ break;
+ }
+ } else {
+ results.hci_status = HCI_ERR_HOST_TIMEOUT;
+ results.status = BTM_DEVICE_TIMEOUT;
+ }
+ (*p_cb)(&results);
+ }
+}
+#endif /// CLASSIC_BT_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_page_to_setup_timeout
+**
+** Description This function processes a timeout.
+** Currently, we just report an error log
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_page_to_setup_timeout (void *p_tle)
+{
+ UNUSED(p_tle);
+ BTM_TRACE_DEBUG ("%s\n", __func__);
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ btm_set_page_timeout_complete (NULL);
+#endif /// CLASSIC_BT_INCLUDED == TRUE
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadPageTimeout
+**
+** Description Send HCI Read Page Timeout.
+**
+** Returns
+** BTM_SUCCESS Command sent.
+** BTM_NO_RESOURCES If out of resources to send the command.
+**
+*******************************************************************************/
+//extern
+tBTM_STATUS BTM_ReadPageTimeout(tBTM_CMPL_CB *p_cb)
+{
+ BTM_TRACE_EVENT ("BTM: BTM_ReadPageTimeout");
+
+ /* Get the page timeout */
+ tBTM_GET_PAGE_TIMEOUT_RESULTS results;
+
+ if (p_cb) {
+ results.hci_status = HCI_SUCCESS;
+ results.status = BTM_SUCCESS;
+ results.page_to = btm_cb.btm_inq_vars.page_timeout;
+
+ (*p_cb)(&results);
+ return (BTM_SUCCESS);
+ } else {
+ return (BTM_NO_RESOURCES);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_WriteVoiceSettings
+**
+** Description Send HCI Write Voice Settings command.
+** See stack/hcidefs.h for settings bitmask values.
+**
+** Returns
+** BTM_SUCCESS Command sent.
+** BTM_NO_RESOURCES If out of resources to send the command.
+**
+**
+*******************************************************************************/
+tBTM_STATUS BTM_WriteVoiceSettings(UINT16 settings)
+{
+ BTM_TRACE_EVENT ("BTM: BTM_WriteVoiceSettings: Settings: 0x%04x.", settings);
+
+ /* Send the HCI command */
+ if (btsnd_hcic_write_voice_settings ((UINT16)(settings & 0x03ff))) {
+ return (BTM_SUCCESS);
+ }
+
+ return (BTM_NO_RESOURCES);
+}
+
+/*******************************************************************************
+**
+** Function BTM_EnableTestMode
+**
+** Description Send HCI the enable device under test command.
+**
+** Note: Controller can only be taken out of this mode by
+** resetting the controller.
+**
+** Returns
+** BTM_SUCCESS Command sent.
+** BTM_NO_RESOURCES If out of resources to send the command.
+**
+**
+*******************************************************************************/
+tBTM_STATUS BTM_EnableTestMode(void)
+{
+ UINT8 cond;
+
+ BTM_TRACE_EVENT ("BTM: BTM_EnableTestMode");
+
+ /* set auto accept connection as this is needed during test mode */
+ /* Allocate a buffer to hold HCI command */
+ cond = HCI_DO_AUTO_ACCEPT_CONNECT;
+ if (!btsnd_hcic_set_event_filter(HCI_FILTER_CONNECTION_SETUP,
+ HCI_FILTER_COND_NEW_DEVICE,
+ &cond, sizeof(cond))) {
+ return (BTM_NO_RESOURCES);
+ }
+
+ /* put device to connectable mode */
+ if (BTM_SetConnectability(BTM_CONNECTABLE, BTM_DEFAULT_CONN_WINDOW,
+ BTM_DEFAULT_CONN_INTERVAL) != BTM_SUCCESS) {
+ return BTM_NO_RESOURCES;
+ }
+
+ /* put device to discoverable mode */
+ if (BTM_SetDiscoverability(BTM_GENERAL_DISCOVERABLE, BTM_DEFAULT_DISC_WINDOW,
+ BTM_DEFAULT_DISC_INTERVAL) != BTM_SUCCESS) {
+ return BTM_NO_RESOURCES;
+ }
+
+ /* mask off all of event from controller */
+ hci_layer_get_interface()->transmit_command(
+ hci_packet_factory_get_interface()->make_set_event_mask((const bt_event_mask_t *)("\x00\x00\x00\x00\x00\x00\x00\x00")),
+ NULL,
+ NULL,
+ NULL);
+
+ /* Send the HCI command */
+ if (btsnd_hcic_enable_test_mode ()) {
+ return (BTM_SUCCESS);
+ } else {
+ return (BTM_NO_RESOURCES);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_DeleteStoredLinkKey
+**
+** Description This function is called to delete link key for the specified
+** device addresses from the NVRAM storage attached to the Bluetooth
+** controller.
+**
+** Parameters: bd_addr - Addresses of the devices
+** p_cb - Call back function to be called to return
+** the results
+**
+*******************************************************************************/
+tBTM_STATUS BTM_DeleteStoredLinkKey(BD_ADDR bd_addr, tBTM_CMPL_CB *p_cb)
+{
+ BD_ADDR local_bd_addr = {0};
+ BOOLEAN delete_all_flag = FALSE;
+
+ /* Check if the previous command is completed */
+ if (btm_cb.devcb.p_stored_link_key_cmpl_cb) {
+ return (BTM_BUSY);
+ }
+
+ if (!bd_addr) {
+ /* This is to delete all link keys */
+ delete_all_flag = TRUE;
+
+ /* We don't care the BD address. Just pass a non zero pointer */
+ bd_addr = local_bd_addr;
+ }
+
+ BTM_TRACE_EVENT ("BTM: BTM_DeleteStoredLinkKey: delete_all_flag: %s",
+ delete_all_flag ? "TRUE" : "FALSE");
+
+ /* Send the HCI command */
+ btm_cb.devcb.p_stored_link_key_cmpl_cb = p_cb;
+ if (!btsnd_hcic_delete_stored_key (bd_addr, delete_all_flag)) {
+ return (BTM_NO_RESOURCES);
+ } else {
+ return (BTM_SUCCESS);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_delete_stored_link_key_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the delete stored link key command.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_delete_stored_link_key_complete (UINT8 *p)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_stored_link_key_cmpl_cb;
+ tBTM_DELETE_STORED_LINK_KEY_COMPLETE result;
+
+ /* If there was a callback registered for read stored link key, call it */
+ btm_cb.devcb.p_stored_link_key_cmpl_cb = NULL;
+
+ if (p_cb) {
+ /* Set the call back event to indicate command complete */
+ result.event = BTM_CB_EVT_DELETE_STORED_LINK_KEYS;
+
+ /* Extract the result fields from the HCI event */
+ STREAM_TO_UINT8 (result.status, p);
+ STREAM_TO_UINT16 (result.num_keys, p);
+
+ /* Call the call back and pass the result */
+ (*p_cb)(&result);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_report_device_status
+**
+** Description This function is called when there is a change in the device
+** status. This function will report the new device status to
+** the application
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_report_device_status (tBTM_DEV_STATUS status)
+{
+ tBTM_DEV_STATUS_CB *p_cb = btm_cb.devcb.p_dev_status_cb;
+
+ /* Call the call back to pass the device status to application */
+ if (p_cb) {
+ (*p_cb)(status);
+ }
+}
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function BTM_SetAfhChannels
+**
+** Description This function is called to set AFH channels
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetAfhChannels (AFH_CHANNELS channels, tBTM_CMPL_CB *p_afh_channels_cmpl_cback)
+{
+ if (!controller_get_interface()->get_is_ready()) {
+ return (BTM_DEV_RESET);
+ }
+
+ /* Check if set afh already in progress */
+ if (btm_cb.devcb.p_afh_channels_cmpl_cb) {
+ return (BTM_NO_RESOURCES);
+ }
+
+ /* Save callback */
+ btm_cb.devcb.p_afh_channels_cmpl_cb = p_afh_channels_cmpl_cback;
+
+ if (!btsnd_hcic_set_afh_channels (channels)) {
+ return (BTM_NO_RESOURCES);
+ }
+
+ btu_start_timer (&btm_cb.devcb.afh_channels_timer, BTU_TTYPE_BTM_ACL, BTM_DEV_REPLY_TIMEOUT);
+
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function btm_set_afh_channels_complete
+**
+** Description This function is called when setting AFH channels complete.
+** message is received from the HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_set_afh_channels_complete (UINT8 *p)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_afh_channels_cmpl_cb;
+ tBTM_SET_AFH_CHANNELS_RESULTS results;
+
+ btu_free_timer (&btm_cb.devcb.afh_channels_timer);
+
+ /* If there is a callback address for setting AFH channels, call it */
+ btm_cb.devcb.p_afh_channels_cmpl_cb = NULL;
+
+ if (p_cb) {
+ STREAM_TO_UINT8 (results.hci_status, p);
+
+ switch (results.hci_status){
+ case HCI_SUCCESS:
+ results.status = BTM_SUCCESS;
+ break;
+ case HCI_ERR_UNSUPPORTED_VALUE:
+ case HCI_ERR_ILLEGAL_PARAMETER_FMT:
+ results.status = BTM_ILLEGAL_VALUE;
+ break;
+ default:
+ results.status = BTM_ERR_PROCESSING;
+ break;
+ }
+ (*p_cb)(&results);
+ }
+}
+#endif /// CLASSIC_BT_INCLUDED == TRUE
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function BTM_BleSetChannels
+**
+** Description This function is called to set BLE channels
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleSetChannels (BLE_CHANNELS channels, tBTM_CMPL_CB *p_ble_channels_cmpl_cback)
+{
+ if (!controller_get_interface()->get_is_ready()) {
+ return (BTM_DEV_RESET);
+ }
+
+ /* Check if set afh already in progress */
+ if (btm_cb.devcb.p_ble_channels_cmpl_cb) {
+ return (BTM_NO_RESOURCES);
+ }
+
+ /* Save callback */
+ btm_cb.devcb.p_ble_channels_cmpl_cb = p_ble_channels_cmpl_cback;
+
+ if (!btsnd_hcic_ble_set_channels (channels)) {
+ return (BTM_NO_RESOURCES);
+ }
+
+ btu_start_timer (&btm_cb.devcb.ble_channels_timer, BTU_TTYPE_BTM_ACL, BTM_DEV_REPLY_TIMEOUT);
+
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_set_channels_complete
+**
+** Description This function is called when setting AFH channels complete.
+** message is received from the HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_set_channels_complete (UINT8 *p)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_ble_channels_cmpl_cb;
+ tBTM_BLE_SET_CHANNELS_RESULTS results;
+
+ btu_free_timer (&btm_cb.devcb.ble_channels_timer);
+
+ /* If there is a callback address for setting AFH channels, call it */
+ btm_cb.devcb.p_ble_channels_cmpl_cb = NULL;
+
+ if (p_cb) {
+ STREAM_TO_UINT8 (results.hci_status, p);
+
+ switch (results.hci_status){
+ case HCI_SUCCESS:
+ results.status = BTM_SUCCESS;
+ break;
+ case HCI_ERR_UNSUPPORTED_VALUE:
+ case HCI_ERR_ILLEGAL_PARAMETER_FMT:
+ results.status = BTM_ILLEGAL_VALUE;
+ break;
+ default:
+ results.status = BTM_ERR_PROCESSING;
+ break;
+ }
+ (*p_cb)(&results);
+ }
+}
+#endif /// BLE_INCLUDED == TRUE
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_inq.c b/lib/bt/host/bluedroid/stack/btm/btm_inq.c
new file mode 100644
index 00000000..b8da2327
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_inq.c
@@ -0,0 +1,2973 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2014 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 functions that handle inquiries. These include
+ * setting discoverable mode, controlling the mode of the Baseband, and
+ * maintaining a small database of inquiry responses, with API for people
+ * to browse it.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "osi/alarm.h"
+#include "stack/bt_types.h"
+#include "device/controller.h"
+#include "stack/hcimsgs.h"
+#include "stack/btu.h"
+#include "stack/btm_api.h"
+#include "btm_int.h"
+#include "stack/hcidefs.h"
+#if (defined(SDP_INCLUDED) && SDP_INCLUDED == TRUE)
+#include "stack/sdpdefs.h"
+#endif
+
+#define BTM_INQ_REPLY_TIMEOUT 3 /* 3 second timeout waiting for responses */
+
+/* TRUE to enable DEBUG traces for btm_inq */
+#ifndef BTM_INQ_DEBUG
+#define BTM_INQ_DEBUG FALSE
+#endif
+/********************************************************************************/
+/* L O C A L D A T A D E F I N I T I O N S */
+/********************************************************************************/
+static const LAP general_inq_lap = {0x9e, 0x8b, 0x33};
+static const LAP limited_inq_lap = {0x9e, 0x8b, 0x00};
+
+#if (defined(SDP_INCLUDED) && SDP_INCLUDED == TRUE)
+static const UINT16 BTM_EIR_UUID_LKUP_TBL[BTM_EIR_MAX_SERVICES] = {
+ UUID_SERVCLASS_SERVICE_DISCOVERY_SERVER,
+ /* UUID_SERVCLASS_BROWSE_GROUP_DESCRIPTOR, */
+ /* UUID_SERVCLASS_PUBLIC_BROWSE_GROUP, */
+ UUID_SERVCLASS_SERIAL_PORT,
+ UUID_SERVCLASS_LAN_ACCESS_USING_PPP,
+ UUID_SERVCLASS_DIALUP_NETWORKING,
+ UUID_SERVCLASS_IRMC_SYNC,
+ UUID_SERVCLASS_OBEX_OBJECT_PUSH,
+ UUID_SERVCLASS_OBEX_FILE_TRANSFER,
+ UUID_SERVCLASS_IRMC_SYNC_COMMAND,
+ UUID_SERVCLASS_HEADSET,
+ UUID_SERVCLASS_CORDLESS_TELEPHONY,
+ UUID_SERVCLASS_AUDIO_SOURCE,
+ UUID_SERVCLASS_AUDIO_SINK,
+ UUID_SERVCLASS_AV_REM_CTRL_TARGET,
+ /* UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION, */
+ UUID_SERVCLASS_AV_REMOTE_CONTROL,
+ /* UUID_SERVCLASS_VIDEO_CONFERENCING, */
+ UUID_SERVCLASS_INTERCOM,
+ UUID_SERVCLASS_FAX,
+ UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
+ /* UUID_SERVCLASS_WAP, */
+ /* UUID_SERVCLASS_WAP_CLIENT, */
+ UUID_SERVCLASS_PANU,
+ UUID_SERVCLASS_NAP,
+ UUID_SERVCLASS_GN,
+ UUID_SERVCLASS_DIRECT_PRINTING,
+ /* UUID_SERVCLASS_REFERENCE_PRINTING, */
+ UUID_SERVCLASS_IMAGING,
+ UUID_SERVCLASS_IMAGING_RESPONDER,
+ UUID_SERVCLASS_IMAGING_AUTO_ARCHIVE,
+ UUID_SERVCLASS_IMAGING_REF_OBJECTS,
+ UUID_SERVCLASS_HF_HANDSFREE,
+ UUID_SERVCLASS_AG_HANDSFREE,
+ UUID_SERVCLASS_DIR_PRT_REF_OBJ_SERVICE,
+ /* UUID_SERVCLASS_REFLECTED_UI, */
+ UUID_SERVCLASS_BASIC_PRINTING,
+ UUID_SERVCLASS_PRINTING_STATUS,
+ UUID_SERVCLASS_HUMAN_INTERFACE,
+ UUID_SERVCLASS_CABLE_REPLACEMENT,
+ UUID_SERVCLASS_HCRP_PRINT,
+ UUID_SERVCLASS_HCRP_SCAN,
+ /* UUID_SERVCLASS_COMMON_ISDN_ACCESS, */
+ /* UUID_SERVCLASS_VIDEO_CONFERENCING_GW, */
+ /* UUID_SERVCLASS_UDI_MT, */
+ /* UUID_SERVCLASS_UDI_TA, */
+ /* UUID_SERVCLASS_VCP, */
+ UUID_SERVCLASS_SAP,
+ UUID_SERVCLASS_PBAP_PCE,
+ UUID_SERVCLASS_PBAP_PSE,
+ UUID_SERVCLASS_PHONE_ACCESS,
+ UUID_SERVCLASS_HEADSET_HS,
+ UUID_SERVCLASS_PNP_INFORMATION,
+ /* UUID_SERVCLASS_GENERIC_NETWORKING, */
+ /* UUID_SERVCLASS_GENERIC_FILETRANSFER, */
+ /* UUID_SERVCLASS_GENERIC_AUDIO, */
+ /* UUID_SERVCLASS_GENERIC_TELEPHONY, */
+ /* UUID_SERVCLASS_UPNP_SERVICE, */
+ /* UUID_SERVCLASS_UPNP_IP_SERVICE, */
+ /* UUID_SERVCLASS_ESDP_UPNP_IP_PAN, */
+ /* UUID_SERVCLASS_ESDP_UPNP_IP_LAP, */
+ /* UUID_SERVCLASS_ESDP_UPNP_IP_L2CAP, */
+ UUID_SERVCLASS_VIDEO_SOURCE,
+ UUID_SERVCLASS_VIDEO_SINK,
+ /* UUID_SERVCLASS_VIDEO_DISTRIBUTION */
+ UUID_SERVCLASS_MESSAGE_ACCESS,
+ UUID_SERVCLASS_MESSAGE_NOTIFICATION,
+ UUID_SERVCLASS_HDP_SOURCE,
+ UUID_SERVCLASS_HDP_SINK
+};
+#else
+static const UINT16 BTM_EIR_UUID_LKUP_TBL[BTM_EIR_MAX_SERVICES];
+#endif
+
+/********************************************************************************/
+/* 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 btm_initiate_inquiry (tBTM_INQUIRY_VAR_ST *p_inq);
+static tBTM_STATUS btm_set_inq_event_filter (UINT8 filter_cond_type, tBTM_INQ_FILT_COND *p_filt_cond);
+static void btm_clr_inq_result_flt (void);
+
+static UINT8 btm_convert_uuid_to_eir_service( UINT16 uuid16 );
+static void btm_set_eir_uuid( UINT8 *p_eir, tBTM_INQ_RESULTS *p_results );
+static UINT8 *btm_eir_get_uuid_list( UINT8 *p_eir, UINT8 uuid_size,
+ UINT8 *p_num_uuid, UINT8 *p_uuid_list_type );
+static UINT16 btm_convert_uuid_to_uuid16( UINT8 *p_uuid, UINT8 uuid_size );
+
+/*******************************************************************************
+**
+** Function BTM_SetDiscoverability
+**
+** Description This function is called to set the device into or out of
+** discoverable mode. Discoverable mode means inquiry
+** scans are enabled. If a value of '0' is entered for window or
+** interval, the default values are used.
+**
+** Returns BTM_SUCCESS if successful
+** BTM_BUSY if a setting of the filter is already in progress
+** BTM_NO_RESOURCES if couldn't get a memory pool buffer
+** BTM_ILLEGAL_VALUE if a bad parameter was detected
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetDiscoverability (UINT16 inq_mode, UINT16 window, UINT16 interval)
+{
+ UINT8 scan_mode = 0;
+ UINT16 service_class;
+ UINT8 *p_cod;
+ UINT8 major, minor;
+ DEV_CLASS cod;
+ LAP temp_lap[2];
+ BOOLEAN is_limited;
+ BOOLEAN cod_limited;
+
+ BTM_TRACE_API ("BTM_SetDiscoverability\n");
+
+ /*** Check mode parameter ***/
+ if (inq_mode > BTM_MAX_DISCOVERABLE) {
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ /* Make sure the controller is active */
+ if (!controller_get_interface()->get_is_ready()) {
+ return (BTM_DEV_RESET);
+ }
+
+ /* If the window and/or interval is '0', set to default values */
+ if (!window) {
+ window = BTM_DEFAULT_DISC_WINDOW;
+ }
+
+ if (!interval) {
+ interval = BTM_DEFAULT_DISC_INTERVAL;
+ }
+
+ BTM_TRACE_API ("BTM_SetDiscoverability: mode %d [NonDisc-0, Lim-1, Gen-2], window 0x%04x, interval 0x%04x\n",
+ inq_mode, window, interval);
+
+ /*** Check for valid window and interval parameters ***/
+ /*** Only check window and duration if mode is connectable ***/
+ if (inq_mode != BTM_NON_DISCOVERABLE) {
+ /* window must be less than or equal to interval */
+ if (window < HCI_MIN_INQUIRYSCAN_WINDOW ||
+ window > HCI_MAX_INQUIRYSCAN_WINDOW ||
+ interval < HCI_MIN_INQUIRYSCAN_INTERVAL ||
+ interval > HCI_MAX_INQUIRYSCAN_INTERVAL ||
+ window > interval) {
+ return (BTM_ILLEGAL_VALUE);
+ }
+ }
+
+ /* Set the IAC if needed */
+ if (inq_mode != BTM_NON_DISCOVERABLE) {
+ if (inq_mode & BTM_LIMITED_DISCOVERABLE) {
+ /* Use the GIAC and LIAC codes for limited discoverable mode */
+ memcpy (temp_lap[0], limited_inq_lap, LAP_LEN);
+ memcpy (temp_lap[1], general_inq_lap, LAP_LEN);
+
+ if (!btsnd_hcic_write_cur_iac_lap (2, (LAP * const) temp_lap)) {
+ return (BTM_NO_RESOURCES); /* Cannot continue */
+ }
+ } else {
+ if (!btsnd_hcic_write_cur_iac_lap (1, (LAP * const) &general_inq_lap)) {
+ return (BTM_NO_RESOURCES); /* Cannot continue */
+ }
+ }
+
+ scan_mode |= HCI_INQUIRY_SCAN_ENABLED;
+ }
+
+ /* Send down the inquiry scan window and period if changed */
+ if ((window != btm_cb.btm_inq_vars.inq_scan_window) ||
+ (interval != btm_cb.btm_inq_vars.inq_scan_period)) {
+ if (btsnd_hcic_write_inqscan_cfg (interval, window)) {
+ btm_cb.btm_inq_vars.inq_scan_window = window;
+ btm_cb.btm_inq_vars.inq_scan_period = interval;
+ } else {
+ return (BTM_NO_RESOURCES);
+ }
+ }
+
+ if (btm_cb.btm_inq_vars.connectable_mode & BTM_CONNECTABLE_MASK) {
+ scan_mode |= HCI_PAGE_SCAN_ENABLED;
+ }
+
+ if (btsnd_hcic_write_scan_enable (scan_mode)) {
+ btm_cb.btm_inq_vars.discoverable_mode &= (~BTM_DISCOVERABLE_MASK);
+ btm_cb.btm_inq_vars.discoverable_mode |= inq_mode;
+ } else {
+ return (BTM_NO_RESOURCES);
+ }
+
+ /* Change the service class bit if mode has changed */
+ p_cod = BTM_ReadDeviceClass();
+ BTM_COD_SERVICE_CLASS(service_class, p_cod);
+ is_limited = (inq_mode & BTM_LIMITED_DISCOVERABLE) ? TRUE : FALSE;
+ cod_limited = (service_class & BTM_COD_SERVICE_LMTD_DISCOVER) ? TRUE : FALSE;
+ if (is_limited ^ cod_limited) {
+ BTM_COD_MINOR_CLASS(minor, p_cod );
+ BTM_COD_MAJOR_CLASS(major, p_cod );
+ if (is_limited) {
+ service_class |= BTM_COD_SERVICE_LMTD_DISCOVER;
+ } else {
+ service_class &= ~BTM_COD_SERVICE_LMTD_DISCOVER;
+ }
+
+ FIELDS_TO_COD(cod, minor, major, service_class);
+ (void) BTM_SetDeviceClass (cod);
+ }
+
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetInquiryScanType
+**
+** Description This function is called to set the iquiry scan-type to
+** standard or interlaced.
+**
+** Returns BTM_SUCCESS if successful
+** BTM_MODE_UNSUPPORTED if not a 1.2 device
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetInquiryScanType (UINT16 scan_type)
+{
+
+ BTM_TRACE_API ("BTM_SetInquiryScanType\n");
+ if (scan_type != BTM_SCAN_TYPE_STANDARD && scan_type != BTM_SCAN_TYPE_INTERLACED) {
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ /* whatever app wants if device is not 1.2 scan type should be STANDARD */
+ if (!controller_get_interface()->supports_interlaced_inquiry_scan()) {
+ return (BTM_MODE_UNSUPPORTED);
+ }
+
+ /* Check for scan type if configuration has been changed */
+ if (scan_type != btm_cb.btm_inq_vars.inq_scan_type) {
+ if (BTM_IsDeviceUp()) {
+ if (btsnd_hcic_write_inqscan_type ((UINT8)scan_type)) {
+ btm_cb.btm_inq_vars.inq_scan_type = scan_type;
+ } else {
+ return (BTM_NO_RESOURCES);
+ }
+ } else {
+ return (BTM_WRONG_MODE);
+ }
+ }
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetPageScanType
+**
+** Description This function is called to set the page scan-type to
+** standard or interlaced.
+**
+** Returns BTM_SUCCESS if successful
+** BTM_MODE_UNSUPPORTED if not a 1.2 device
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetPageScanType (UINT16 scan_type)
+{
+ BTM_TRACE_API ("BTM_SetPageScanType\n");
+ if (scan_type != BTM_SCAN_TYPE_STANDARD && scan_type != BTM_SCAN_TYPE_INTERLACED) {
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ /* whatever app wants if device is not 1.2 scan type should be STANDARD */
+ if (!controller_get_interface()->supports_interlaced_inquiry_scan()) {
+ return (BTM_MODE_UNSUPPORTED);
+ }
+
+ /* Check for scan type if configuration has been changed */
+ if (scan_type != btm_cb.btm_inq_vars.page_scan_type) {
+ if (BTM_IsDeviceUp()) {
+ if (btsnd_hcic_write_pagescan_type ((UINT8)scan_type)) {
+ btm_cb.btm_inq_vars.page_scan_type = scan_type;
+ } else {
+ return (BTM_NO_RESOURCES);
+ }
+ } else {
+ return (BTM_WRONG_MODE);
+ }
+ }
+ return (BTM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetInquiryMode
+**
+** Description This function is called to set standard or with RSSI
+** mode of the inquiry for local device.
+**
+** Output Params: mode - standard, with RSSI, extended
+**
+** Returns BTM_SUCCESS if successful
+** BTM_NO_RESOURCES if couldn't get a memory pool buffer
+** BTM_ILLEGAL_VALUE if a bad parameter was detected
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetInquiryMode (UINT8 mode)
+{
+ const controller_t *controller = controller_get_interface();
+ BTM_TRACE_API ("BTM_SetInquiryMode\n");
+ if (mode == BTM_INQ_RESULT_STANDARD) {
+ /* mandatory mode */
+ } else if (mode == BTM_INQ_RESULT_WITH_RSSI) {
+ if (!controller->supports_rssi_with_inquiry_results()) {
+ return (BTM_MODE_UNSUPPORTED);
+ }
+ } else if (mode == BTM_INQ_RESULT_EXTENDED) {
+ if (!controller->supports_extended_inquiry_response()) {
+ return (BTM_MODE_UNSUPPORTED);
+ }
+ } else {
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ if (!BTM_IsDeviceUp()) {
+ return (BTM_WRONG_MODE);
+ }
+
+ if (!btsnd_hcic_write_inquiry_mode (mode)) {
+ return (BTM_NO_RESOURCES);
+ }
+
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadDiscoverability
+**
+** Description This function is called to read the current discoverability
+** mode of the device.
+**
+** Output Params: p_window - current inquiry scan duration
+** p_interval - current inquiry scan interval
+**
+** Returns BTM_NON_DISCOVERABLE, BTM_LIMITED_DISCOVERABLE, or
+** BTM_GENERAL_DISCOVERABLE
+**
+*******************************************************************************/
+UINT16 BTM_ReadDiscoverability (UINT16 *p_window, UINT16 *p_interval)
+{
+ BTM_TRACE_API ("BTM_ReadDiscoverability\n");
+ if (p_window) {
+ *p_window = btm_cb.btm_inq_vars.inq_scan_window;
+ }
+
+ if (p_interval) {
+ *p_interval = btm_cb.btm_inq_vars.inq_scan_period;
+ }
+
+ return (btm_cb.btm_inq_vars.discoverable_mode);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetPeriodicInquiryMode
+**
+** Description This function is called to set the device periodic inquiry mode.
+** If the duration is zero, the periodic inquiry mode is cancelled.
+**
+** Note: We currently do not allow concurrent inquiry and periodic inquiry.
+**
+** Parameters: p_inqparms - pointer to the inquiry information
+** mode - GENERAL or LIMITED inquiry
+** duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED)
+** max_resps - maximum amount of devices to search for before ending the inquiry
+** filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or
+** BTM_FILTER_COND_BD_ADDR
+** filter_cond - value for the filter (based on filter_cond_type)
+**
+** max_delay - maximum amount of time between successive inquiries
+** min_delay - minimum amount of time between successive inquiries
+** p_results_cb - callback returning pointer to results (tBTM_INQ_RESULTS)
+**
+** Returns BTM_CMD_STARTED if successfully started
+** BTM_ILLEGAL_VALUE if a bad parameter is detected
+** BTM_NO_RESOURCES if could not allocate a message buffer
+** BTM_SUCCESS - if cancelling the periodic inquiry
+** BTM_BUSY - if an inquiry is already active
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetPeriodicInquiryMode (tBTM_INQ_PARMS *p_inqparms, UINT16 max_delay,
+ UINT16 min_delay, tBTM_INQ_RESULTS_CB *p_results_cb)
+{
+ tBTM_STATUS status;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ BTM_TRACE_API ("BTM_SetPeriodicInquiryMode: mode: %d, dur: %d, rsps: %d, flt: %d, min: %d, max: %d\n",
+ p_inqparms->mode, p_inqparms->duration, p_inqparms->max_resps,
+ p_inqparms->filter_cond_type, min_delay, max_delay);
+
+ /*** Make sure the device is ready ***/
+ if (!BTM_IsDeviceUp()) {
+ return (BTM_WRONG_MODE);
+ }
+
+ /* Only one active inquiry is allowed in this implementation.
+ Also do not allow an inquiry if the inquiry filter is being updated */
+ if (p_inq->inq_active || p_inq->inqfilt_active) {
+ return (BTM_BUSY);
+ }
+
+ /* If illegal parameters return FALSE */
+ if (p_inqparms->mode != BTM_GENERAL_INQUIRY &&
+ p_inqparms->mode != BTM_LIMITED_INQUIRY) {
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ /* Verify the parameters for this command */
+ if (p_inqparms->duration < BTM_MIN_INQUIRY_LEN ||
+ p_inqparms->duration > BTM_MAX_INQUIRY_LENGTH ||
+ min_delay <= p_inqparms->duration ||
+ min_delay < BTM_PER_INQ_MIN_MIN_PERIOD ||
+ min_delay > BTM_PER_INQ_MAX_MIN_PERIOD ||
+ max_delay <= min_delay ||
+ max_delay < BTM_PER_INQ_MIN_MAX_PERIOD)
+ /* max_delay > BTM_PER_INQ_MAX_MAX_PERIOD)*/
+ /* BTM_PER_INQ_MAX_MAX_PERIOD set to 1's in all bits. Condition resulting in false always*/
+ {
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ /* Save the inquiry parameters to be used upon the completion of setting/clearing the inquiry filter */
+ p_inq->inqparms = *p_inqparms;
+ p_inq->per_min_delay = min_delay;
+ p_inq->per_max_delay = max_delay;
+ p_inq->inq_cmpl_info.num_resp = 0; /* Clear the results counter */
+ p_inq->p_inq_results_cb = p_results_cb;
+
+ p_inq->inq_active = (UINT8)((p_inqparms->mode == BTM_LIMITED_INQUIRY) ?
+ (BTM_LIMITED_INQUIRY_ACTIVE | BTM_PERIODIC_INQUIRY_ACTIVE) :
+ (BTM_GENERAL_INQUIRY_ACTIVE | BTM_PERIODIC_INQUIRY_ACTIVE));
+
+ /* If a filter is specified, then save it for later and clear the current filter.
+ The setting of the filter is done upon completion of clearing of the previous
+ filter.
+ */
+ if (p_inqparms->filter_cond_type != BTM_CLR_INQUIRY_FILTER) {
+ p_inq->state = BTM_INQ_CLR_FILT_STATE;
+ p_inqparms->filter_cond_type = BTM_CLR_INQUIRY_FILTER;
+ } else { /* The filter is not being used so simply clear it; the inquiry can start after this operation */
+ p_inq->state = BTM_INQ_SET_FILT_STATE;
+ }
+
+ /* Before beginning the inquiry the current filter must be cleared, so initiate the command */
+ if ((status = btm_set_inq_event_filter (p_inqparms->filter_cond_type, &p_inqparms->filter_cond)) != BTM_CMD_STARTED) {
+ /* If set filter command is not succesful reset the state */
+ p_inq->p_inq_results_cb = NULL;
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_CancelPeriodicInquiry
+**
+** Description This function cancels a periodic inquiry
+**
+** Returns
+** BTM_NO_RESOURCES if could not allocate a message buffer
+** BTM_SUCCESS - if cancelling the periodic inquiry
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_CancelPeriodicInquiry(void)
+{
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ tBTM_STATUS status = BTM_SUCCESS;
+ BTM_TRACE_API ("BTM_CancelPeriodicInquiry called\n");
+
+ /*** Make sure the device is ready ***/
+ if (!BTM_IsDeviceUp()) {
+ return (BTM_WRONG_MODE);
+ }
+
+ /* Only cancel if one is active */
+ if (btm_cb.btm_inq_vars.inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) {
+ btm_cb.btm_inq_vars.inq_active = BTM_INQUIRY_INACTIVE;
+ btm_cb.btm_inq_vars.p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL;
+
+ if (!btsnd_hcic_exit_per_inq ()) {
+ status = BTM_NO_RESOURCES;
+ }
+
+ /* If the event filter is in progress, mark it so that the processing of the return
+ event will be ignored */
+ if (p_inq->inqfilt_active) {
+ p_inq->pending_filt_complete_event++;
+ }
+
+ p_inq->inqfilt_active = FALSE;
+ p_inq->inq_counter++;
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetConnectability
+**
+** Description This function is called to set the device into or out of
+** connectable mode. Discoverable mode means page scans enabled.
+**
+** Returns BTM_SUCCESS if successful
+** BTM_ILLEGAL_VALUE if a bad parameter is detected
+** BTM_NO_RESOURCES if could not allocate a message buffer
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetConnectability (UINT16 page_mode, UINT16 window, UINT16 interval)
+{
+ UINT8 scan_mode = 0;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ BTM_TRACE_API ("BTM_SetConnectability\n");
+
+ /*** Check mode parameter ***/
+ if (page_mode != BTM_NON_CONNECTABLE && page_mode != BTM_CONNECTABLE) {
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ /* Make sure the controller is active */
+ if (!controller_get_interface()->get_is_ready()) {
+ return (BTM_DEV_RESET);
+ }
+
+ /* If the window and/or interval is '0', set to default values */
+ if (!window) {
+ window = BTM_DEFAULT_CONN_WINDOW;
+ }
+
+ if (!interval) {
+ interval = BTM_DEFAULT_CONN_INTERVAL;
+ }
+
+ BTM_TRACE_API ("BTM_SetConnectability: mode %d [NonConn-0, Conn-1], window 0x%04x, interval 0x%04x\n",
+ page_mode, window, interval);
+
+ /*** Check for valid window and interval parameters ***/
+ /*** Only check window and duration if mode is connectable ***/
+ if (page_mode == BTM_CONNECTABLE) {
+ /* window must be less than or equal to interval */
+ if (window < HCI_MIN_PAGESCAN_WINDOW ||
+ window > HCI_MAX_PAGESCAN_WINDOW ||
+ interval < HCI_MIN_PAGESCAN_INTERVAL ||
+ interval > HCI_MAX_PAGESCAN_INTERVAL ||
+ window > interval) {
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ scan_mode |= HCI_PAGE_SCAN_ENABLED;
+ }
+
+ if ((window != p_inq->page_scan_window) ||
+ (interval != p_inq->page_scan_period)) {
+ p_inq->page_scan_window = window;
+ p_inq->page_scan_period = interval;
+ if (!btsnd_hcic_write_pagescan_cfg (interval, window)) {
+ return (BTM_NO_RESOURCES);
+ }
+ }
+
+ /* Keep the inquiry scan as previouosly set */
+ if (p_inq->discoverable_mode & BTM_DISCOVERABLE_MASK) {
+ scan_mode |= HCI_INQUIRY_SCAN_ENABLED;
+ }
+
+ if (btsnd_hcic_write_scan_enable (scan_mode)) {
+ p_inq->connectable_mode &= (~BTM_CONNECTABLE_MASK);
+ p_inq->connectable_mode |= page_mode;
+
+ return (BTM_SUCCESS);
+ }
+
+ return (BTM_NO_RESOURCES);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadConnectability
+**
+** Description This function is called to read the current discoverability
+** mode of the device.
+** Output Params p_window - current page scan duration
+** p_interval - current time between page scans
+**
+** Returns BTM_NON_CONNECTABLE or BTM_CONNECTABLE
+**
+*******************************************************************************/
+UINT16 BTM_ReadConnectability (UINT16 *p_window, UINT16 *p_interval)
+{
+ BTM_TRACE_API ("BTM_ReadConnectability\n");
+ if (p_window) {
+ *p_window = btm_cb.btm_inq_vars.page_scan_window;
+ }
+
+ if (p_interval) {
+ *p_interval = btm_cb.btm_inq_vars.page_scan_period;
+ }
+
+ return (btm_cb.btm_inq_vars.connectable_mode);
+}
+
+
+
+/*******************************************************************************
+**
+** Function BTM_IsInquiryActive
+**
+** Description This function returns a bit mask of the current inquiry state
+**
+** Returns BTM_INQUIRY_INACTIVE if inactive (0)
+** BTM_LIMITED_INQUIRY_ACTIVE if a limted inquiry is active
+** BTM_GENERAL_INQUIRY_ACTIVE if a general inquiry is active
+** BTM_PERIODIC_INQUIRY_ACTIVE if a periodic inquiry is active
+**
+*******************************************************************************/
+UINT16 BTM_IsInquiryActive (void)
+{
+ BTM_TRACE_API ("BTM_IsInquiryActive\n");
+
+ return (btm_cb.btm_inq_vars.inq_active);
+}
+
+
+
+/*******************************************************************************
+**
+** Function BTM_CancelInquiry
+**
+** Description This function cancels an inquiry if active
+**
+** Returns BTM_SUCCESS if successful
+** BTM_NO_RESOURCES if could not allocate a message buffer
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_CancelInquiry(void)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ UINT8 active_mode = p_inq->inq_active;
+#endif
+ BTM_TRACE_API ("BTM_CancelInquiry called\n");
+
+ /*** Make sure the device is ready ***/
+ if (!BTM_IsDeviceUp()) {
+ return (BTM_WRONG_MODE);
+ }
+
+ /* Only cancel if not in periodic mode, otherwise the caller should call BTM_CancelPeriodicMode */
+ if ((p_inq->inq_active & BTM_INQUIRY_ACTIVE_MASK) != 0 &&
+ (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE))) {
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+ p_inq->p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL; /* Do not notify caller anymore */
+ p_inq->p_inq_cmpl_cb = (tBTM_CMPL_CB *) NULL; /* Do not notify caller anymore */
+
+ /* If the event filter is in progress, mark it so that the processing of the return
+ event will be ignored */
+ if (p_inq->inqfilt_active) {
+ p_inq->inqfilt_active = FALSE;
+ p_inq->pending_filt_complete_event++;
+ }
+ /* Initiate the cancel inquiry */
+ else {
+ if (((p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK) != 0)
+#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ && (active_mode & BTM_BR_INQUIRY_MASK)
+#endif
+ ) {
+ if (!btsnd_hcic_inq_cancel()) {
+ status = BTM_NO_RESOURCES;
+ }
+ }
+#if BLE_INCLUDED == TRUE
+ if (((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0)
+#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ && (active_mode & BTM_BLE_INQ_ACTIVE_MASK)
+#endif
+ ) {
+ btm_ble_stop_inquiry();
+ }
+#endif
+ }
+
+ /* Do not send the BUSY_LEVEL event yet. Wait for the cancel_complete event
+ * and then send the BUSY_LEVEL event
+ * btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);
+ */
+
+ p_inq->inq_counter++;
+ btm_clr_inq_result_flt();
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_StartInquiry
+**
+** Description This function is called to start an inquiry.
+**
+** Parameters: p_inqparms - pointer to the inquiry information
+** mode - GENERAL or LIMITED inquiry, BR/LE bit mask seperately
+** duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED)
+** max_resps - maximum amount of devices to search for before ending the inquiry
+** filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or
+** BTM_FILTER_COND_BD_ADDR
+** filter_cond - value for the filter (based on filter_cond_type)
+**
+** p_results_cb - Pointer to the callback routine which gets called
+** upon receipt of an inquiry result. If this field is
+** NULL, the application is not notified.
+**
+** p_cmpl_cb - Pointer to the callback routine which gets called
+** upon completion. If this field is NULL, the
+** application is not notified when completed.
+** Returns tBTM_STATUS
+** BTM_CMD_STARTED if successfully initiated
+** BTM_BUSY if already in progress
+** BTM_ILLEGAL_VALUE if parameter(s) are out of range
+** BTM_NO_RESOURCES if could not allocate resources to start the command
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, tBTM_INQ_RESULTS_CB *p_results_cb,
+ tBTM_CMPL_CB *p_cmpl_cb)
+{
+ tBTM_STATUS status = BTM_CMD_STARTED;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ BTM_TRACE_API ("BTM_StartInquiry: mode: %d, dur: %d, rsps: %d, flt: %d\n",
+ p_inqparms->mode, p_inqparms->duration, p_inqparms->max_resps,
+ p_inqparms->filter_cond_type);
+
+ /* Only one active inquiry is allowed in this implementation.
+ Also do not allow an inquiry if the inquiry filter is being updated */
+ if (p_inq->inq_active || p_inq->inqfilt_active) {
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+ /*check if LE observe is already running*/
+ if (p_inq->scan_type == INQ_LE_OBSERVE && p_inq->p_inq_ble_results_cb != NULL) {
+ BTM_TRACE_API("BTM_StartInquiry: LE observe in progress");
+ p_inq->scan_type = INQ_GENERAL;
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+ btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
+ btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+ } else
+#endif
+ {
+ return (BTM_BUSY);
+ BTM_TRACE_API("BTM_StartInquiry: return BUSY\n");
+ }
+ } else {
+ p_inq->scan_type = INQ_GENERAL;
+ }
+
+ /*** Make sure the device is ready ***/
+ if (!BTM_IsDeviceUp()) {
+ return (BTM_WRONG_MODE);
+ }
+
+ if ((p_inqparms->mode & BTM_BR_INQUIRY_MASK) != BTM_GENERAL_INQUIRY &&
+ (p_inqparms->mode & BTM_BR_INQUIRY_MASK) != BTM_LIMITED_INQUIRY
+#if (BLE_INCLUDED == TRUE)
+ && (p_inqparms->mode & BTM_BLE_INQUIRY_MASK) != BTM_BLE_GENERAL_INQUIRY
+ && (p_inqparms->mode & BTM_BLE_INQUIRY_MASK) != BTM_BLE_LIMITED_INQUIRY
+#endif
+ ) {
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ if (p_inq->next_state == BTM_FINISH) {
+ return BTM_ILLEGAL_VALUE;
+ }
+#endif
+
+
+ /* Save the inquiry parameters to be used upon the completion of setting/clearing the inquiry filter */
+ p_inq->inqparms = *p_inqparms;
+
+ /* Initialize the inquiry variables */
+ p_inq->state = BTM_INQ_ACTIVE_STATE;
+ p_inq->p_inq_cmpl_cb = p_cmpl_cb;
+ p_inq->p_inq_results_cb = p_results_cb;
+ p_inq->inq_cmpl_info.num_resp = 0; /* Clear the results counter */
+ p_inq->inq_active = p_inqparms->mode;
+
+ BTM_TRACE_DEBUG("BTM_StartInquiry: p_inq->inq_active = 0x%02x\n", p_inq->inq_active);
+
+ /* interleave scan minimal conditions */
+#if (BLE_INCLUDED==TRUE && (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE))
+
+ /* check if both modes are present */
+ if ((p_inqparms->mode & BTM_BLE_INQUIRY_MASK) && (p_inqparms->mode & BTM_BR_INQUIRY_MASK)) {
+ BTM_TRACE_API("BTM:Interleave Inquiry Mode Set\n");
+ p_inqparms->duration = p_inqparms->intl_duration[p_inq->next_state];
+ p_inq->inqparms.duration = p_inqparms->duration;
+ } else {
+ BTM_TRACE_API("BTM:Single Mode: No interleaving, Mode:0x%02x\n", p_inqparms->mode);
+ p_inq->next_state = BTM_NO_INTERLEAVING;
+ }
+#endif
+
+
+
+ /* start LE inquiry here if requested */
+#if BLE_INCLUDED == TRUE
+ if ((p_inqparms->mode & BTM_BLE_INQUIRY_MASK)
+#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ && (p_inq->next_state == BTM_BLE_ONE || p_inq->next_state == BTM_BLE_TWO ||
+ p_inq->next_state == BTM_NO_INTERLEAVING)
+#endif
+ )
+
+ {
+#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ p_inq->inq_active = (p_inqparms->mode & BTM_BLE_INQUIRY_MASK);
+ BTM_TRACE_API("BTM:Starting LE Scan with duration %d and activeMode:0x%02x\n",
+ p_inqparms->duration, (p_inqparms->mode & BTM_BLE_INQUIRY_MASK));
+#endif
+ if (!controller_get_interface()->supports_ble()) {
+ p_inq->inqparms.mode &= ~ BTM_BLE_INQUIRY_MASK;
+ status = BTM_ILLEGAL_VALUE;
+ }
+ /* BLE for now does not support filter condition for inquiry */
+ else if ((status = btm_ble_start_inquiry((UINT8)(p_inqparms->mode & BTM_BLE_INQUIRY_MASK),
+ p_inqparms->duration)) != BTM_CMD_STARTED) {
+ BTM_TRACE_ERROR("Err Starting LE Inquiry.\n");
+ p_inq->inqparms.mode &= ~ BTM_BLE_INQUIRY_MASK;
+ }
+#if (!defined(BTA_HOST_INTERLEAVE_SEARCH) || BTA_HOST_INTERLEAVE_SEARCH == FALSE)
+ p_inqparms->mode &= ~BTM_BLE_INQUIRY_MASK;
+#endif
+
+#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ if (p_inq->next_state == BTM_NO_INTERLEAVING) {
+ p_inq->next_state = BTM_FINISH;
+ } else {
+ BTM_TRACE_API("BTM:Interleaving: started LE scan, Advancing to next state: %d\n",
+ p_inq->next_state + 1);
+ p_inq->next_state += 1;
+ }
+ /* reset next_state if status <> BTM_Started */
+ if (status != BTM_CMD_STARTED) {
+ p_inq->next_state = BTM_BR_ONE;
+ }
+
+ /* if interleave scan..return here */
+ return status;
+#endif
+
+
+ BTM_TRACE_DEBUG("BTM_StartInquiry: mode = %02x\n", p_inqparms->mode);
+ }
+#endif /* end of BLE_INCLUDED */
+
+ /* we're done with this routine if BR/EDR inquiry is not desired. */
+ if ((p_inqparms->mode & BTM_BR_INQUIRY_MASK) == BTM_INQUIRY_NONE) {
+ return status;
+ }
+
+ /* BR/EDR inquiry portion */
+#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ if ((p_inq->next_state == BTM_BR_ONE || p_inq->next_state == BTM_BR_TWO ||
+ p_inq->next_state == BTM_NO_INTERLEAVING )) {
+ p_inq->inq_active = (p_inqparms->mode & BTM_BR_INQUIRY_MASK);
+#endif
+ /* If a filter is specified, then save it for later and clear the current filter.
+ The setting of the filter is done upon completion of clearing of the previous
+ filter.
+ */
+ switch (p_inqparms->filter_cond_type) {
+ case BTM_CLR_INQUIRY_FILTER:
+ p_inq->state = BTM_INQ_SET_FILT_STATE;
+ break;
+
+ case BTM_FILTER_COND_DEVICE_CLASS:
+ case BTM_FILTER_COND_BD_ADDR:
+ /* The filter is not being used so simply clear it;
+ the inquiry can start after this operation */
+ p_inq->state = BTM_INQ_CLR_FILT_STATE;
+ p_inqparms->filter_cond_type = BTM_CLR_INQUIRY_FILTER;
+ /* =============>>>> adding LE filtering here ????? */
+ break;
+
+ default:
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ /* Before beginning the inquiry the current filter must be cleared, so initiate the command */
+ if ((status = btm_set_inq_event_filter (p_inqparms->filter_cond_type,
+ &p_inqparms->filter_cond)) != BTM_CMD_STARTED) {
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+ }
+
+#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ if (p_inq->next_state == BTM_NO_INTERLEAVING) {
+ p_inq->next_state = BTM_FINISH;
+ } else {
+ BTM_TRACE_API("BTM:Interleaving: Started BTM inq, Advancing to next state: %d\n",
+ p_inq->next_state + 1);
+ p_inq->next_state += 1;
+ }
+ }
+ if (status != BTM_CMD_STARTED) {
+ /* Some error beginning the scan process.
+ Reset the next_state parameter.. Do we need to reset the inq_active also?
+ */
+ BTM_TRACE_API("BTM:Interleaving: Error in Starting inquiry, status: 0x%02x\n", status);
+ p_inq->next_state = BTM_BR_ONE;
+ }
+#endif
+
+
+ return (status);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadRemoteDeviceName
+**
+** Description This function initiates a remote device HCI command to the
+** controller and calls the callback when the process has completed.
+**
+** Input Params: remote_bda - device address of name to retrieve
+** p_cb - callback function called when BTM_CMD_STARTED
+** is returned.
+** A pointer to tBTM_REMOTE_DEV_NAME is passed to the
+** callback.
+**
+** Returns
+** BTM_CMD_STARTED is returned if the request was successfully sent
+** to HCI.
+** BTM_BUSY if already in progress
+** BTM_UNKNOWN_ADDR if device address is bad
+** BTM_NO_RESOURCES if could not allocate resources to start the command
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadRemoteDeviceName (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb
+ , tBT_TRANSPORT transport)
+{
+ tBTM_INQ_INFO *p_cur = NULL;
+ tINQ_DB_ENT *p_i;
+
+ BTM_TRACE_API ("BTM_ReadRemoteDeviceName: bd addr [%02x%02x%02x%02x%02x%02x]\n",
+ remote_bda[0], remote_bda[1], remote_bda[2],
+ remote_bda[3], remote_bda[4], remote_bda[5]);
+
+ /* Use the remote device's clock offset if it is in the local inquiry database */
+ if ((p_i = btm_inq_db_find (remote_bda)) != NULL) {
+ p_cur = &p_i->inq_info;
+ }
+ BTM_TRACE_API ("no device found in inquiry db\n");
+
+#if (BLE_INCLUDED == TRUE)
+ if (transport == BT_TRANSPORT_LE) {
+ return btm_ble_read_remote_name(remote_bda, p_cur, p_cb);
+ } else
+#endif
+ {
+ return (btm_initiate_rem_name (remote_bda, p_cur, BTM_RMT_NAME_EXT,
+ BTM_EXT_RMT_NAME_TIMEOUT, p_cb));
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_CancelRemoteDeviceName
+**
+** Description This function initiates the cancel request for the specified
+** remote device.
+**
+** Input Params: None
+**
+** Returns
+** BTM_CMD_STARTED is returned if the request was successfully sent
+** to HCI.
+** BTM_NO_RESOURCES if could not allocate resources to start the command
+** BTM_WRONG_MODE if there is not an active remote name request.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_CancelRemoteDeviceName (void)
+{
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ BTM_TRACE_API ("BTM_CancelRemoteDeviceName()\n");
+
+ /* Make sure there is not already one in progress */
+ if (p_inq->remname_active) {
+#if BLE_INCLUDED == TRUE
+ if (BTM_UseLeLink(p_inq->remname_bda)) {
+ if (btm_ble_cancel_remote_name(p_inq->remname_bda)) {
+ return (BTM_CMD_STARTED);
+ } else {
+ return (BTM_UNKNOWN_ADDR);
+ }
+ } else
+#endif
+ {
+ if (btsnd_hcic_rmt_name_req_cancel (p_inq->remname_bda)) {
+ return (BTM_CMD_STARTED);
+ } else {
+ return (BTM_NO_RESOURCES);
+ }
+ }
+ } else {
+ return (BTM_WRONG_MODE);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_InqDbRead
+**
+** Description This function looks through the inquiry database for a match
+** based on Bluetooth Device Address. This is the application's
+** interface to get the inquiry details of a specific BD address.
+**
+** Returns pointer to entry, or NULL if not found
+**
+*******************************************************************************/
+tBTM_INQ_INFO *BTM_InqDbRead (BD_ADDR p_bda)
+{
+ BTM_TRACE_API ("BTM_InqDbRead: bd addr [%02x%02x%02x%02x%02x%02x]\n",
+ p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
+
+ tINQ_DB_ENT *p_ent = btm_inq_db_find(p_bda);
+ if (!p_ent) {
+ return NULL;
+ }
+
+ return &p_ent->inq_info;
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_InqDbFirst
+**
+** Description This function looks through the inquiry database for the first
+** used entry, and returns that. This is used in conjunction with
+** BTM_InqDbNext by applications as a way to walk through the
+** inquiry database.
+**
+** Returns pointer to first in-use entry, or NULL if DB is empty
+**
+*******************************************************************************/
+tBTM_INQ_INFO *BTM_InqDbFirst (void)
+{
+ UINT16 xx;
+ tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db;
+
+ for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) {
+ if (p_ent->in_use) {
+ return (&p_ent->inq_info);
+ }
+ }
+
+ /* If here, no used entry found */
+ return ((tBTM_INQ_INFO *)NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_InqDbNext
+**
+** Description This function looks through the inquiry database for the next
+** used entry, and returns that. If the input parameter is NULL,
+** the first entry is returned.
+**
+** Returns pointer to next in-use entry, or NULL if no more found.
+**
+*******************************************************************************/
+tBTM_INQ_INFO *BTM_InqDbNext (tBTM_INQ_INFO *p_cur)
+{
+ tINQ_DB_ENT *p_ent;
+ UINT16 inx;
+
+ if (p_cur) {
+ p_ent = (tINQ_DB_ENT *) ((UINT8 *)p_cur - offsetof (tINQ_DB_ENT, inq_info));
+ inx = (UINT16)((p_ent - btm_cb.btm_inq_vars.inq_db) + 1);
+
+ for (p_ent = &btm_cb.btm_inq_vars.inq_db[inx]; inx < BTM_INQ_DB_SIZE; inx++, p_ent++) {
+ if (p_ent->in_use) {
+ return (&p_ent->inq_info);
+ }
+ }
+
+ /* If here, more entries found */
+ return ((tBTM_INQ_INFO *)NULL);
+ } else {
+ return (BTM_InqDbFirst());
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ClearInqDb
+**
+** Description This function is called to clear out a device or all devices
+** from the inquiry database.
+**
+** Parameter p_bda - (input) BD_ADDR -> Address of device to clear
+** (NULL clears all entries)
+**
+** Returns BTM_BUSY if an inquiry, get remote name, or event filter
+** is active, otherwise BTM_SUCCESS
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ClearInqDb (BD_ADDR p_bda)
+{
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ /* If an inquiry or remote name is in progress return busy */
+ if (p_inq->inq_active != BTM_INQUIRY_INACTIVE ||
+ p_inq->inqfilt_active) {
+ return (BTM_BUSY);
+ }
+
+ btm_clr_inq_db(p_bda);
+
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadInquiryRspTxPower
+**
+** Description This command will read the inquiry Transmit Power level used
+** to transmit the FHS and EIR data packets.
+** This can be used directly in the Tx Power Level EIR data type.
+**
+** Returns BTM_SUCCESS if successful
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadInquiryRspTxPower (tBTM_CMPL_CB *p_cb)
+{
+ if (btm_cb.devcb.p_txpwer_cmpl_cb) {
+ return (BTM_BUSY);
+ }
+
+ btu_start_timer (&btm_cb.devcb.txpwer_timer, BTU_TTYPE_BTM_ACL, BTM_INQ_REPLY_TIMEOUT );
+
+
+ btm_cb.devcb.p_txpwer_cmpl_cb = p_cb;
+
+ if (!btsnd_hcic_read_inq_tx_power ()) {
+ btm_cb.devcb.p_txpwer_cmpl_cb = NULL;
+ btu_stop_timer (&btm_cb.devcb.txpwer_timer);
+ return (BTM_NO_RESOURCES);
+ } else {
+ return (BTM_CMD_STARTED);
+ }
+}
+
+/*********************************************************************************
+**********************************************************************************
+** **
+** BTM Internal Inquiry Functions **
+** **
+**********************************************************************************
+*********************************************************************************/
+/*******************************************************************************
+**
+** Function btm_inq_db_reset
+**
+** Description This function is called at at reset to clear the inquiry
+** database & pending callback.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_inq_db_reset (void)
+{
+ tBTM_REMOTE_DEV_NAME rem_name;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ UINT8 num_responses;
+ UINT8 temp_inq_active;
+ tBTM_STATUS status;
+
+ btu_stop_timer (&p_inq->inq_timer_ent);
+
+ /* If an inquiry or periodic inquiry is active, reset the mode to inactive */
+ if (p_inq->inq_active != BTM_INQUIRY_INACTIVE) {
+ temp_inq_active = p_inq->inq_active; /* Save so state can change BEFORE
+ callback is called */
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+
+ /* If not a periodic inquiry, the complete callback must be called to notify caller */
+ if (temp_inq_active == BTM_LIMITED_INQUIRY_ACTIVE ||
+ temp_inq_active == BTM_GENERAL_INQUIRY_ACTIVE) {
+ if (p_inq->p_inq_cmpl_cb) {
+ num_responses = 0;
+ (*p_inq->p_inq_cmpl_cb)(&num_responses);
+ }
+ }
+ }
+
+ /* Cancel a remote name request if active, and notify the caller (if waiting) */
+ if (p_inq->remname_active ) {
+ btu_stop_timer (&p_inq->rmt_name_timer_ent);
+ p_inq->remname_active = FALSE;
+ memset(p_inq->remname_bda, 0, BD_ADDR_LEN);
+
+ if (p_inq->p_remname_cmpl_cb) {
+ rem_name.status = BTM_DEV_RESET;
+
+ (*p_inq->p_remname_cmpl_cb)(&rem_name);
+ p_inq->p_remname_cmpl_cb = NULL;
+ }
+ }
+
+ /* Cancel an inquiry filter request if active, and notify the caller (if waiting) */
+ if (p_inq->inqfilt_active) {
+ p_inq->inqfilt_active = FALSE;
+
+ if (p_inq->p_inqfilter_cmpl_cb) {
+ status = BTM_DEV_RESET;
+ (*p_inq->p_inqfilter_cmpl_cb)(&status);
+ }
+ }
+
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+ p_inq->pending_filt_complete_event = 0;
+ p_inq->p_inq_results_cb = NULL;
+ btm_clr_inq_db(NULL); /* Clear out all the entries in the database */
+ btm_clr_inq_result_flt();
+
+ p_inq->discoverable_mode = BTM_NON_DISCOVERABLE;
+ p_inq->connectable_mode = BTM_NON_CONNECTABLE;
+ p_inq->page_scan_type = BTM_SCAN_TYPE_STANDARD;
+ p_inq->inq_scan_type = BTM_SCAN_TYPE_STANDARD;
+
+#if BLE_INCLUDED == TRUE
+ p_inq->discoverable_mode |= BTM_BLE_NON_DISCOVERABLE;
+ p_inq->connectable_mode |= BTM_BLE_NON_CONNECTABLE;
+#endif
+ return;
+}
+
+
+/*********************************************************************************
+**
+** Function btm_inq_db_init
+**
+** Description This function is called at startup to initialize the inquiry
+** database.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_inq_db_init (void)
+{
+#if 0 /* cleared in btm_init; put back in if called from anywhere else! */
+ memset (&btm_cb.btm_inq_vars, 0, sizeof (tBTM_INQUIRY_VAR_ST));
+#endif
+
+ btu_free_timer(&btm_cb.btm_inq_vars.rmt_name_timer_ent);
+ memset(&btm_cb.btm_inq_vars.rmt_name_timer_ent, 0, sizeof(TIMER_LIST_ENT));
+ btu_free_timer(&btm_cb.btm_inq_vars.inq_timer_ent);
+ memset(&btm_cb.btm_inq_vars.inq_timer_ent, 0, sizeof(TIMER_LIST_ENT));
+
+ btm_cb.btm_inq_vars.no_inc_ssp = BTM_NO_SSP_ON_INQUIRY;
+}
+
+/*********************************************************************************
+**
+** Function btm_inq_stop_on_ssp
+**
+** Description This function is called on incoming SSP
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_inq_stop_on_ssp(void)
+{
+ UINT8 normal_active = (BTM_GENERAL_INQUIRY_ACTIVE | BTM_LIMITED_INQUIRY_ACTIVE);
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG ("btm_inq_stop_on_ssp: no_inc_ssp=%d inq_active:0x%x state:%d inqfilt_active:%d\n",
+ btm_cb.btm_inq_vars.no_inc_ssp, btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+ if (btm_cb.btm_inq_vars.no_inc_ssp) {
+ if (btm_cb.btm_inq_vars.state == BTM_INQ_ACTIVE_STATE) {
+ if (btm_cb.btm_inq_vars.inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) {
+ BTM_CancelPeriodicInquiry();
+ } else if (btm_cb.btm_inq_vars.inq_active & normal_active) {
+ /* can not call BTM_CancelInquiry() here. We need to report inquiry complete evt */
+ btsnd_hcic_inq_cancel();
+ }
+ }
+ /* do not allow inquiry to start */
+ btm_cb.btm_inq_vars.inq_active |= BTM_SSP_INQUIRY_ACTIVE;
+ }
+}
+
+/*********************************************************************************
+**
+** Function btm_inq_clear_ssp
+**
+** Description This function is called when pairing_state becomes idle
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_inq_clear_ssp(void)
+{
+ btm_cb.btm_inq_vars.inq_active &= ~BTM_SSP_INQUIRY_ACTIVE;
+}
+
+/*********************************************************************************
+**
+** Function btm_clr_inq_db
+**
+** Description This function is called to clear out a device or all devices
+** from the inquiry database.
+**
+** Parameter p_bda - (input) BD_ADDR -> Address of device to clear
+** (NULL clears all entries)
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_clr_inq_db (BD_ADDR p_bda)
+{
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ tINQ_DB_ENT *p_ent = p_inq->inq_db;
+ UINT16 xx;
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG ("btm_clr_inq_db: inq_active:0x%x state:%d\n",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state);
+#endif
+ for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) {
+ if (p_ent->in_use) {
+ /* If this is the specified BD_ADDR or clearing all devices */
+ if (p_bda == NULL ||
+ (!memcmp (p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN))) {
+ p_ent->in_use = FALSE;
+ }
+ }
+ }
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG ("inq_active:0x%x state:%d\n",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function btm_clr_inq_result_flt
+**
+** Description This function looks through the bdaddr database for a match
+** based on Bluetooth Device Address
+**
+** Returns TRUE if found, else FALSE (new entry)
+**
+*******************************************************************************/
+static void btm_clr_inq_result_flt (void)
+{
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ if (p_inq->p_bd_db) {
+ osi_free(p_inq->p_bd_db);
+ p_inq->p_bd_db = NULL;
+ }
+ p_inq->num_bd_entries = 0;
+ p_inq->max_bd_entries = 0;
+}
+
+/*******************************************************************************
+**
+** Function btm_inq_find_bdaddr
+**
+** Description This function looks through the bdaddr database for a match
+** based on Bluetooth Device Address
+**
+** Returns TRUE if found, else FALSE (new entry)
+**
+*******************************************************************************/
+BOOLEAN btm_inq_find_bdaddr (BD_ADDR p_bda)
+{
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ tINQ_BDADDR *p_db = &p_inq->p_bd_db[0];
+ UINT16 xx;
+
+ /* Don't bother searching, database doesn't exist or periodic mode */
+ if ((p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) || !p_db) {
+ return (FALSE);
+ }
+
+ for (xx = 0; xx < p_inq->num_bd_entries; xx++, p_db++) {
+ if (!memcmp(p_db->bd_addr, p_bda, BD_ADDR_LEN)
+ && p_db->inq_count == p_inq->inq_counter) {
+ return (TRUE);
+ }
+ }
+
+ if (xx < p_inq->max_bd_entries) {
+ p_db->inq_count = p_inq->inq_counter;
+ memcpy(p_db->bd_addr, p_bda, BD_ADDR_LEN);
+ p_inq->num_bd_entries++;
+ }
+
+ /* If here, New Entry */
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function btm_inq_db_find
+**
+** Description This function looks through the inquiry database for a match
+** based on Bluetooth Device Address
+**
+** Returns pointer to entry, or NULL if not found
+**
+*******************************************************************************/
+tINQ_DB_ENT *btm_inq_db_find (BD_ADDR p_bda)
+{
+ UINT16 xx;
+ tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db;
+
+ for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) {
+ if ((p_ent->in_use) && (!memcmp (p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN))) {
+ return (p_ent);
+ }
+ }
+
+ /* If here, not found */
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_inq_db_new
+**
+** Description This function looks through the inquiry database for an unused
+** entry. If no entry is free, it allocates the oldest entry.
+**
+** Returns pointer to entry
+**
+*******************************************************************************/
+tINQ_DB_ENT *btm_inq_db_new (BD_ADDR p_bda)
+{
+ UINT16 xx;
+ tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db;
+ tINQ_DB_ENT *p_old = btm_cb.btm_inq_vars.inq_db;
+ UINT32 ot = 0xFFFFFFFF;
+
+ for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) {
+ if (!p_ent->in_use) {
+ memset (p_ent, 0, sizeof (tINQ_DB_ENT));
+ memcpy (p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN);
+ p_ent->in_use = TRUE;
+
+ return (p_ent);
+ }
+
+ if (p_ent->time_of_resp < ot) {
+ p_old = p_ent;
+ ot = p_ent->time_of_resp;
+ }
+ }
+
+ /* If here, no free entry found. Return the oldest. */
+
+ memset (p_old, 0, sizeof (tINQ_DB_ENT));
+ memcpy (p_old->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN);
+ p_old->in_use = TRUE;
+
+ return (p_old);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_set_inq_event_filter
+**
+** Description This function is called to set the inquiry event filter.
+** It is called by either internally, or by the external API function
+** (BTM_SetInqEventFilter). It is used internally as part of the
+** inquiry processing.
+**
+** Input Params:
+** filter_cond_type - this is the type of inquiry filter to apply:
+** BTM_FILTER_COND_DEVICE_CLASS,
+** BTM_FILTER_COND_BD_ADDR, or
+** BTM_CLR_INQUIRY_FILTER
+**
+** p_filt_cond - this is either a BD_ADDR or DEV_CLASS depending on the
+** filter_cond_type (See section 4.7.3 of Core Spec 1.0b).
+**
+** Returns BTM_CMD_STARTED if successfully initiated
+** BTM_NO_RESOURCES if couldn't get a memory pool buffer
+** BTM_ILLEGAL_VALUE if a bad parameter was detected
+**
+*******************************************************************************/
+static tBTM_STATUS btm_set_inq_event_filter (UINT8 filter_cond_type,
+ tBTM_INQ_FILT_COND *p_filt_cond)
+{
+ UINT8 condition_length = DEV_CLASS_LEN * 2;
+ UINT8 condition_buf[DEV_CLASS_LEN * 2];
+ UINT8 *p_cond = condition_buf; /* points to the condition to pass to HCI */
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG ("btm_set_inq_event_filter: filter type %d [Clear-0, COD-1, BDADDR-2]\n",
+ filter_cond_type);
+ BTM_TRACE_DEBUG (" condition [%02x%02x%02x %02x%02x%02x]\n",
+ p_filt_cond->bdaddr_cond[0], p_filt_cond->bdaddr_cond[1], p_filt_cond->bdaddr_cond[2],
+ p_filt_cond->bdaddr_cond[3], p_filt_cond->bdaddr_cond[4], p_filt_cond->bdaddr_cond[5]);
+#endif
+
+ /* Load the correct filter condition to pass to the lower layer */
+ switch (filter_cond_type) {
+ case BTM_FILTER_COND_DEVICE_CLASS:
+ /* copy the device class and device class fields into contiguous memory to send to HCI */
+ memcpy (condition_buf, p_filt_cond->cod_cond.dev_class, DEV_CLASS_LEN);
+ memcpy (&condition_buf[DEV_CLASS_LEN],
+ p_filt_cond->cod_cond.dev_class_mask, DEV_CLASS_LEN);
+
+ /* condition length should already be set as the default */
+ break;
+
+ case BTM_FILTER_COND_BD_ADDR:
+ p_cond = p_filt_cond->bdaddr_cond;
+
+ /* condition length should already be set as the default */
+ break;
+
+ case BTM_CLR_INQUIRY_FILTER:
+ condition_length = 0;
+ break;
+
+ default:
+ return (BTM_ILLEGAL_VALUE); /* Bad parameter was passed in */
+ }
+
+ btm_cb.btm_inq_vars.inqfilt_active = TRUE;
+
+ /* Filter the inquiry results for the specified condition type and value */
+ if (btsnd_hcic_set_event_filter(HCI_FILTER_INQUIRY_RESULT, filter_cond_type,
+ p_cond, condition_length))
+
+ {
+ return (BTM_CMD_STARTED);
+ } else {
+ return (BTM_NO_RESOURCES);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_event_filter_complete
+**
+** Description This function is called when a set event filter has completed.
+** Note: This routine currently only handles inquiry filters.
+** Connection filters are ignored for now.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_event_filter_complete (UINT8 *p)
+{
+ UINT8 hci_status;
+ tBTM_STATUS status;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ tBTM_CMPL_CB *p_cb = p_inq->p_inqfilter_cmpl_cb;
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG ("btm_event_filter_complete: inq_active:0x%x state:%d inqfilt_active:%d\n",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+ /* If the filter complete event is from an old or cancelled request, ignore it */
+ if (p_inq->pending_filt_complete_event) {
+ p_inq->pending_filt_complete_event--;
+ return;
+ }
+
+ /* Only process the inquiry filter; Ignore the connection filter until it
+ is used by the upper layers */
+ if (p_inq->inqfilt_active == TRUE ) {
+ /* Extract the returned status from the buffer */
+ STREAM_TO_UINT8 (hci_status, p);
+ if (hci_status != HCI_SUCCESS) {
+ /* If standalone operation, return the error status; if embedded in the inquiry, continue the inquiry */
+ BTM_TRACE_WARNING ("BTM Warning: Set Event Filter Failed (HCI returned 0x%x)\n", hci_status);
+ status = BTM_ERR_PROCESSING;
+ } else {
+ status = BTM_SUCCESS;
+ }
+
+ /* If the set filter was initiated externally (via BTM_SetInqEventFilter), call the
+ callback function to notify the initiator that it has completed */
+ if (p_inq->state == BTM_INQ_INACTIVE_STATE) {
+ p_inq->inqfilt_active = FALSE;
+ if (p_cb) {
+ (*p_cb) (&status);
+ }
+ } else /* An inquiry is active (the set filter command was internally generated),
+ process the next state of the process (Set a new filter or start the inquiry). */
+ {
+ if (status != BTM_SUCCESS) {
+ /* Process the inquiry complete (Error Status) */
+ btm_process_inq_complete (BTM_ERR_PROCESSING, (UINT8)(p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK));
+
+ /* btm_process_inq_complete() does not restore the following settings on periodic inquiry */
+ p_inq->inqfilt_active = FALSE;
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+
+ return;
+ }
+
+ /* Check to see if a new filter needs to be set up */
+ if (p_inq->state == BTM_INQ_CLR_FILT_STATE) {
+ if ((status = btm_set_inq_event_filter (p_inq->inqparms.filter_cond_type, &p_inq->inqparms.filter_cond)) == BTM_CMD_STARTED) {
+ p_inq->state = BTM_INQ_SET_FILT_STATE;
+ } else { /* Error setting the filter: Call the initiator's callback function to indicate a failure */
+ p_inq->inqfilt_active = FALSE;
+
+ /* Process the inquiry complete (Error Status) */
+ btm_process_inq_complete (BTM_ERR_PROCESSING, (UINT8)(p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK));
+ }
+ } else { /* Initiate the Inquiry or Periodic Inquiry */
+ p_inq->state = BTM_INQ_ACTIVE_STATE;
+ p_inq->inqfilt_active = FALSE;
+ btm_initiate_inquiry (p_inq);
+ }
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_initiate_inquiry
+**
+** Description This function is called to start an inquiry or periodic inquiry
+** upon completion of the setting and/or clearing of the inquiry filter.
+**
+** Inputs: p_inq (btm_cb.btm_inq_vars) - pointer to saved inquiry information
+** mode - GENERAL or LIMITED inquiry
+** duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED)
+** max_resps - maximum amount of devices to search for before ending the inquiry
+** filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or
+** BTM_FILTER_COND_BD_ADDR
+** filter_cond - value for the filter (based on filter_cond_type)
+**
+** Returns If an error occurs the initiator's callback is called with the error status.
+**
+*******************************************************************************/
+static void btm_initiate_inquiry (tBTM_INQUIRY_VAR_ST *p_inq)
+{
+ const LAP *lap;
+ tBTM_INQ_PARMS *p_inqparms = &p_inq->inqparms;
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG ("btm_initiate_inquiry: inq_active:0x%x state:%d inqfilt_active:%d\n",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+ btm_acl_update_busy_level (BTM_BLI_INQ_EVT);
+
+ if (p_inq->inq_active & BTM_SSP_INQUIRY_ACTIVE) {
+ btm_process_inq_complete (BTM_NO_RESOURCES, (UINT8)(p_inqparms->mode & BTM_BR_INQUIRY_MASK));
+ return;
+ }
+
+ /* Make sure the number of responses doesn't overflow the database configuration */
+ p_inqparms->max_resps = (UINT8)((p_inqparms->max_resps <= BTM_INQ_DB_SIZE) ? p_inqparms->max_resps : BTM_INQ_DB_SIZE);
+
+ lap = (p_inq->inq_active & BTM_LIMITED_INQUIRY_ACTIVE) ? &limited_inq_lap : &general_inq_lap;
+
+ if (p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) {
+ if (!btsnd_hcic_per_inq_mode (p_inq->per_max_delay,
+ p_inq->per_min_delay,
+ *lap, p_inqparms->duration,
+ p_inqparms->max_resps)) {
+ btm_process_inq_complete (BTM_NO_RESOURCES, (UINT8)(p_inqparms->mode & BTM_BR_INQUIRY_MASK));
+ }
+ } else {
+ btm_clr_inq_result_flt();
+
+ /* Allocate memory to hold bd_addrs responding */
+ if ((p_inq->p_bd_db = (tINQ_BDADDR *)osi_calloc(BT_DEFAULT_BUFFER_SIZE)) != NULL) {
+ p_inq->max_bd_entries = (UINT16)(BT_DEFAULT_BUFFER_SIZE / sizeof(tINQ_BDADDR));
+ /* BTM_TRACE_DEBUG("btm_initiate_inquiry: memory allocated for %d bdaddrs",
+ p_inq->max_bd_entries); */
+ }
+
+ if (!btsnd_hcic_inquiry(*lap, p_inqparms->duration, 0)) {
+ btm_process_inq_complete (BTM_NO_RESOURCES, (UINT8)(p_inqparms->mode & BTM_BR_INQUIRY_MASK));
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_process_inq_results
+**
+** Description This function is called when inquiry results are received from
+** the device. It updates the inquiry database. If the inquiry
+** database is full, the oldest entry is discarded.
+**
+** Parameters inq_res_mode - BTM_INQ_RESULT_STANDARD
+** BTM_INQ_RESULT_WITH_RSSI
+** BTM_INQ_RESULT_EXTENDED
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_process_inq_results (UINT8 *p, UINT8 inq_res_mode)
+{
+ UINT8 num_resp, xx;
+ BD_ADDR bda;
+ tINQ_DB_ENT *p_i;
+ tBTM_INQ_RESULTS *p_cur = NULL;
+ BOOLEAN is_new = TRUE;
+ BOOLEAN update = FALSE;
+ INT8 i_rssi;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ tBTM_INQ_RESULTS_CB *p_inq_results_cb = p_inq->p_inq_results_cb;
+ UINT8 page_scan_rep_mode = 0;
+ UINT8 page_scan_per_mode = 0;
+ UINT8 page_scan_mode = 0;
+ UINT8 rssi = 0;
+ DEV_CLASS dc;
+ UINT16 clock_offset;
+ UINT8 *p_eir_data = NULL;
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG ("btm_process_inq_results inq_active:0x%x state:%d inqfilt_active:%d inq_res_mode=%d\n",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active, inq_res_mode);
+#endif
+ /* Only process the results if the BR inquiry is still active */
+ if (!(p_inq->inq_active & BTM_BR_INQ_ACTIVE_MASK)) {
+ return;
+ }
+
+ STREAM_TO_UINT8 (num_resp, p);
+
+ for (xx = 0; xx < num_resp; xx++) {
+ update = FALSE;
+ /* Extract inquiry results */
+ STREAM_TO_BDADDR (bda, p);
+ STREAM_TO_UINT8 (page_scan_rep_mode, p);
+ STREAM_TO_UINT8 (page_scan_per_mode, p);
+
+ if (inq_res_mode == BTM_INQ_RESULT_STANDARD) {
+ STREAM_TO_UINT8(page_scan_mode, p);
+ }
+
+ STREAM_TO_DEVCLASS (dc, p);
+ STREAM_TO_UINT16 (clock_offset, p);
+ if (inq_res_mode != BTM_INQ_RESULT_STANDARD) {
+ STREAM_TO_UINT8(rssi, p);
+ }
+
+ p_i = btm_inq_db_find (bda);
+
+ /* Only process the num_resp is smaller than max_resps.
+ If results are queued to BTU task while canceling inquiry,
+ or when more than one result is in this response, > max_resp
+ responses could be processed which can confuse some apps
+ */
+ if (p_inq->inqparms.max_resps &&
+ p_inq->inq_cmpl_info.num_resp >= p_inq->inqparms.max_resps
+#if BLE_INCLUDED == TRUE
+ /* new device response */
+ && ( p_i == NULL ||
+ /* exisiting device with BR/EDR info */
+ (p_i && (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0)
+ )
+#endif
+
+ ) {
+ BTM_TRACE_WARNING("INQ RES: Extra Response Received...ignoring\n");
+ return;
+ }
+
+ /* Check if this address has already been processed for this inquiry */
+ if (btm_inq_find_bdaddr(bda)) {
+ BTM_TRACE_DEBUG("BDA seen before [%02x%02x %02x%02x %02x%02x]\n",
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+ /* By default suppose no update needed */
+ i_rssi = (INT8)rssi;
+
+ /* If this new RSSI is higher than the last one */
+ if (p_inq->inqparms.report_dup && (rssi != 0) &&
+ p_i && (i_rssi > p_i->inq_info.results.rssi || p_i->inq_info.results.rssi == 0
+#if BLE_INCLUDED == TRUE
+ /* BR/EDR inquiry information update */
+ || (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0
+#endif
+ )) {
+ p_cur = &p_i->inq_info.results;
+ BTM_TRACE_DEBUG("update RSSI new:%d, old:%d\n", i_rssi, p_cur->rssi);
+ p_cur->rssi = i_rssi;
+ update = TRUE;
+ }
+ /* If we received a second Extended Inq Event for an already */
+ /* discovered device, this is because for the first one EIR was not received */
+ else if ((inq_res_mode == BTM_INQ_RESULT_EXTENDED) && (p_i)) {
+ p_cur = &p_i->inq_info.results;
+ update = TRUE;
+ }
+ /* If no update needed continue with next response (if any) */
+ else {
+ continue;
+ }
+ }
+
+ /* If existing entry, use that, else get a new one (possibly reusing the oldest) */
+ if (p_i == NULL) {
+ p_i = btm_inq_db_new (bda);
+ is_new = TRUE;
+ }
+
+ /* If an entry for the device already exists, overwrite it ONLY if it is from
+ a previous inquiry. (Ignore it if it is a duplicate response from the same
+ inquiry.
+ */
+ else if (p_i->inq_count == p_inq->inq_counter
+#if (BLE_INCLUDED == TRUE )
+ && (p_i->inq_info.results.device_type == BT_DEVICE_TYPE_BREDR)
+#endif
+ ) {
+ is_new = FALSE;
+ }
+
+ /* keep updating RSSI to have latest value */
+ if ( inq_res_mode != BTM_INQ_RESULT_STANDARD ) {
+ p_i->inq_info.results.rssi = (INT8)rssi;
+ } else {
+ p_i->inq_info.results.rssi = BTM_INQ_RES_IGNORE_RSSI;
+ }
+
+ if (is_new == TRUE) {
+ /* Save the info */
+ p_cur = &p_i->inq_info.results;
+ p_cur->page_scan_rep_mode = page_scan_rep_mode;
+ p_cur->page_scan_per_mode = page_scan_per_mode;
+ p_cur->page_scan_mode = page_scan_mode;
+ p_cur->dev_class[0] = dc[0];
+ p_cur->dev_class[1] = dc[1];
+ p_cur->dev_class[2] = dc[2];
+ p_cur->clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID;
+
+ p_i->time_of_resp = osi_time_get_os_boottime_ms();
+
+ if (p_i->inq_count != p_inq->inq_counter) {
+ p_inq->inq_cmpl_info.num_resp++; /* A new response was found */
+ }
+
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+ p_cur->inq_result_type = BTM_INQ_RESULT_BR;
+ if (p_i->inq_count != p_inq->inq_counter) {
+ p_cur->device_type = BT_DEVICE_TYPE_BREDR;
+ p_i->scan_rsp = FALSE;
+ } else {
+ p_cur->device_type |= BT_DEVICE_TYPE_BREDR;
+ }
+#endif
+ p_i->inq_count = p_inq->inq_counter; /* Mark entry for current inquiry */
+
+ /* If the number of responses found and not unlimited, issue a cancel inquiry */
+ if (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) &&
+ p_inq->inqparms.max_resps &&
+ p_inq->inq_cmpl_info.num_resp == p_inq->inqparms.max_resps
+#if BLE_INCLUDED == TRUE
+ /* BLE scanning is active and received adv */
+ && ((((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0) &&
+ p_cur->device_type == BT_DEVICE_TYPE_DUMO && p_i->scan_rsp) ||
+ (p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) == 0)
+#endif
+ ) {
+ /* BTM_TRACE_DEBUG("BTMINQ: Found devices, cancelling inquiry..."); */
+ btsnd_hcic_inq_cancel();
+
+#if BLE_INCLUDED == TRUE
+ if ((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0) {
+ btm_ble_stop_inquiry();
+ }
+#endif
+ btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);
+ }
+ /* Initialize flag to FALSE. This flag is set/used by application */
+ p_i->inq_info.appl_knows_rem_name = FALSE;
+ }
+
+ if (is_new || update) {
+ if ( inq_res_mode == BTM_INQ_RESULT_EXTENDED ) {
+ memset( p_cur->eir_uuid, 0,
+ BTM_EIR_SERVICE_ARRAY_SIZE * (BTM_EIR_ARRAY_BITS / 8));
+ /* set bit map of UUID list from received EIR */
+ btm_set_eir_uuid( p, p_cur );
+ p_eir_data = p;
+ } else {
+ p_eir_data = NULL;
+ }
+
+ /* If a callback is registered, call it with the results */
+ if (p_inq_results_cb) {
+ (p_inq_results_cb)((tBTM_INQ_RESULTS *) p_cur, p_eir_data);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sort_inq_result
+**
+** Description This function is called when inquiry complete is received
+** from the device to sort inquiry results based on rssi.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sort_inq_result(void)
+{
+ UINT8 xx, yy, num_resp;
+ tINQ_DB_ENT *p_tmp = NULL;
+ tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db;
+ tINQ_DB_ENT *p_next = btm_cb.btm_inq_vars.inq_db + 1;
+ int size;
+
+ num_resp = (btm_cb.btm_inq_vars.inq_cmpl_info.num_resp < BTM_INQ_DB_SIZE) ?
+ btm_cb.btm_inq_vars.inq_cmpl_info.num_resp : BTM_INQ_DB_SIZE;
+
+ if ((p_tmp = (tINQ_DB_ENT *)osi_malloc(sizeof(tINQ_DB_ENT))) != NULL) {
+ size = sizeof(tINQ_DB_ENT);
+ for (xx = 0; xx < num_resp - 1; xx++, p_ent++) {
+ for (yy = xx + 1, p_next = p_ent + 1; yy < num_resp; yy++, p_next++) {
+ if (p_ent->inq_info.results.rssi < p_next->inq_info.results.rssi) {
+ memcpy (p_tmp, p_next, size);
+ memcpy (p_next, p_ent, size);
+ memcpy (p_ent, p_tmp, size);
+ }
+ }
+ }
+
+ osi_free(p_tmp);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_process_inq_complete
+**
+** Description This function is called when inquiry complete is received
+** from the device. Call the callback if not in periodic inquiry
+** mode AND it is not NULL (The caller wants the event).
+**
+** The callback pass back the status and the number of responses
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_process_inq_complete (UINT8 status, UINT8 mode)
+{
+ tBTM_CMPL_CB *p_inq_cb = btm_cb.btm_inq_vars.p_inq_cmpl_cb;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ /* inquiry inactive case happens when inquiry is cancelled.
+ Make mode 0 for no further inquiries from the current inquiry process
+ */
+ if (status != HCI_SUCCESS || p_inq->next_state == BTM_FINISH || !p_inq->inq_active) {
+ /* re-initialize for next inquiry request */
+ p_inq->next_state = BTM_BR_ONE;
+ /* make the mode 0 here */
+ p_inq->inqparms.mode &= ~(p_inq->inqparms.mode);
+
+ }
+#endif
+
+#if (!defined(BTA_HOST_INTERLEAVE_SEARCH) || BTA_HOST_INTERLEAVE_SEARCH == FALSE)
+ p_inq->inqparms.mode &= ~(mode);
+#endif
+
+ if (p_inq->scan_type == INQ_LE_OBSERVE && !p_inq->inq_active) {
+ /*end of LE observe*/
+ p_inq->p_inq_ble_results_cb = (tBTM_INQ_RESULTS_CB *) NULL;
+ p_inq->p_inq_ble_cmpl_cb = (tBTM_CMPL_CB *) NULL;
+ p_inq->scan_type = INQ_NONE;
+ }
+
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG ("btm_process_inq_complete inq_active:0x%x state:%d inqfilt_active:%d\n",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+ btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);
+ /* Ignore any stray or late complete messages if the inquiry is not active */
+ if (p_inq->inq_active) {
+ p_inq->inq_cmpl_info.status = (tBTM_STATUS)((status == HCI_SUCCESS) ? BTM_SUCCESS : BTM_ERR_PROCESSING);
+
+ /* Notify caller that the inquiry has completed; (periodic inquiries do not send completion events */
+ if (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) && p_inq->inqparms.mode == 0) {
+#if BLE_INCLUDED == TRUE
+ btm_clear_all_pending_le_entry();
+#endif
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+
+ /* Increment so the start of a next inquiry has a new count */
+ p_inq->inq_counter++;
+
+ btm_clr_inq_result_flt();
+
+ if ((p_inq->inq_cmpl_info.status == BTM_SUCCESS) &&
+ controller_get_interface()->supports_rssi_with_inquiry_results()) {
+ btm_sort_inq_result();
+ }
+
+ /* Clear the results callback if set */
+ p_inq->p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL;
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+ p_inq->p_inq_cmpl_cb = (tBTM_CMPL_CB *) NULL;
+
+ /* If we have a callback registered for inquiry complete, call it */
+ BTM_TRACE_DEBUG ("BTM Inq Compl Callback: status 0x%02x, num results %d\n",
+ p_inq->inq_cmpl_info.status, p_inq->inq_cmpl_info.num_resp);
+
+ if (p_inq_cb) {
+ (p_inq_cb)((tBTM_INQUIRY_CMPL *) &p_inq->inq_cmpl_info);
+ }
+ }
+#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ if (p_inq->inqparms.mode != 0 && !(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE)) {
+ /* make inquiry inactive for next iteration */
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+ /* call the inquiry again */
+ BTM_StartInquiry(&p_inq->inqparms, p_inq->p_inq_results_cb, p_inq->p_inq_cmpl_cb);
+ }
+#endif
+ }
+ if (p_inq->inqparms.mode == 0 && p_inq->scan_type == INQ_GENERAL) { //this inquiry is complete
+ p_inq->scan_type = INQ_NONE;
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+ /* check if the LE observe is pending */
+ if (p_inq->p_inq_ble_results_cb != NULL) {
+ BTM_TRACE_DEBUG("BTM Inq Compl: resuming a pending LE scan");
+ BTM_BleObserve(1, 0, p_inq->p_inq_ble_results_cb, p_inq->p_inq_ble_cmpl_cb);
+ }
+#endif
+ }
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG ("inq_active:0x%x state:%d inqfilt_active:%d\n",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_process_cancel_complete
+**
+** Description This function is called when inquiry cancel complete is received
+** from the device.This function will also call the btm_process_inq_complete
+** This function is needed to differentiate a cancel_cmpl_evt from the
+** inq_cmpl_evt
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_process_cancel_complete(UINT8 status, UINT8 mode)
+{
+ btm_acl_update_busy_level (BTM_BLI_INQ_CANCEL_EVT);
+ btm_process_inq_complete(status, mode);
+}
+/*******************************************************************************
+**
+** Function btm_initiate_rem_name
+**
+** Description This function looks initiates a remote name request. It is called
+** either by GAP or by the API call BTM_ReadRemoteDeviceName.
+**
+** Input Params: p_cur - pointer to an inquiry result structure (NULL if nonexistent)
+** p_cb - callback function called when BTM_CMD_STARTED
+** is returned.
+** A pointer to tBTM_REMOTE_DEV_NAME is passed to the
+** callback.
+**
+** Returns
+** BTM_CMD_STARTED is returned if the request was sent to HCI.
+** BTM_BUSY if already in progress
+** BTM_NO_RESOURCES if could not allocate resources to start the command
+** BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS btm_initiate_rem_name (BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur,
+ UINT8 origin, UINT32 timeout, tBTM_CMPL_CB *p_cb)
+{
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ BOOLEAN cmd_ok;
+
+ /*** Make sure the device is ready ***/
+ if (!BTM_IsDeviceUp()) {
+ return (BTM_WRONG_MODE);
+ }
+
+ if (origin == BTM_RMT_NAME_SEC) {
+ cmd_ok = btsnd_hcic_rmt_name_req (remote_bda, HCI_PAGE_SCAN_REP_MODE_R1,
+ HCI_MANDATARY_PAGE_SCAN_MODE, 0);
+ if (cmd_ok) {
+ return BTM_CMD_STARTED;
+ } else {
+ return BTM_NO_RESOURCES;
+ }
+ }
+ /* Make sure there are no two remote name requests from external API in progress */
+ else if (origin == BTM_RMT_NAME_EXT) {
+ if (p_inq->remname_active) {
+ return (BTM_BUSY);
+ } else {
+ /* If there is no remote name request running,call the callback function and start timer */
+ p_inq->p_remname_cmpl_cb = p_cb;
+ memcpy(p_inq->remname_bda, remote_bda, BD_ADDR_LEN);
+ btu_start_timer (&p_inq->rmt_name_timer_ent,
+ BTU_TTYPE_BTM_RMT_NAME,
+ timeout);
+
+ /* If the database entry exists for the device, use its clock offset */
+ if (p_cur) {
+ cmd_ok = btsnd_hcic_rmt_name_req (remote_bda,
+ p_cur->results.page_scan_rep_mode,
+ p_cur->results.page_scan_mode,
+ (UINT16)(p_cur->results.clock_offset |
+ BTM_CLOCK_OFFSET_VALID));
+ } else { /* Otherwise use defaults and mark the clock offset as invalid */
+ cmd_ok = btsnd_hcic_rmt_name_req (remote_bda, HCI_PAGE_SCAN_REP_MODE_R1,
+ HCI_MANDATARY_PAGE_SCAN_MODE, 0);
+ }
+ if (cmd_ok) {
+ p_inq->remname_active = TRUE;
+ return BTM_CMD_STARTED;
+ } else {
+ return BTM_NO_RESOURCES;
+ }
+ }
+ } else {
+ return BTM_ILLEGAL_VALUE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_process_remote_name
+**
+** Description This function is called when a remote name is received from
+** the device. If remote names are cached, it updates the inquiry
+** database.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_process_remote_name (BD_ADDR bda, BD_NAME bdn, UINT16 evt_len, UINT8 hci_status)
+{
+ tBTM_REMOTE_DEV_NAME rem_name;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+ tBTM_CMPL_CB *p_cb = p_inq->p_remname_cmpl_cb;
+ UINT8 *p_n1;
+
+ UINT16 temp_evt_len;
+
+ if (bda != NULL) {
+ BTM_TRACE_EVENT("BDA %02x:%02x:%02x:%02x:%02x:%02x\n", bda[0], bda[1],
+ bda[2], bda[3],
+ bda[4], bda[5]);
+ }
+
+ BTM_TRACE_EVENT("Inquire BDA %02x:%02x:%02x:%02x:%02x:%02x\n", p_inq->remname_bda[0], p_inq->remname_bda[1],
+ p_inq->remname_bda[2], p_inq->remname_bda[3],
+ p_inq->remname_bda[4], p_inq->remname_bda[5]);
+
+
+
+ /* If the inquire BDA and remote DBA are the same, then stop the timer and set the active to false */
+ if ((p_inq->remname_active == TRUE) &&
+ (((bda != NULL) &&
+ (memcmp(bda, p_inq->remname_bda, BD_ADDR_LEN) == 0)) || bda == NULL))
+
+ {
+#if BLE_INCLUDED == TRUE
+ if (BTM_UseLeLink(p_inq->remname_bda)) {
+ if (hci_status == HCI_ERR_UNSPECIFIED) {
+ btm_ble_cancel_remote_name(p_inq->remname_bda);
+ }
+ }
+#endif
+ btu_stop_timer (&p_inq->rmt_name_timer_ent);
+ p_inq->remname_active = FALSE;
+ /* Clean up and return the status if the command was not successful */
+ /* Note: If part of the inquiry, the name is not stored, and the */
+ /* inquiry complete callback is called. */
+
+ if (hci_status == HCI_SUCCESS) {
+ /* Copy the name from the data stream into the return structure */
+ /* Note that even if it is not being returned, it is used as a */
+ /* temporary buffer. */
+ p_n1 = (UINT8 *)rem_name.remote_bd_name;
+ rem_name.length = (evt_len < BD_NAME_LEN) ? evt_len : BD_NAME_LEN;
+ rem_name.remote_bd_name[rem_name.length] = 0;
+ rem_name.status = BTM_SUCCESS;
+ temp_evt_len = rem_name.length;
+
+ while (temp_evt_len > 0) {
+ *p_n1++ = *bdn++;
+ temp_evt_len--;
+ }
+ rem_name.remote_bd_name[rem_name.length] = 0;
+ }
+ /* If processing a stand alone remote name then report the error in the callback */
+ else {
+ rem_name.status = BTM_BAD_VALUE_RET;
+ rem_name.length = 0;
+ rem_name.remote_bd_name[0] = '\0';
+ }
+ memcpy(rem_name.bd_addr, p_inq->remname_bda, BD_ADDR_LEN);
+ /* Reset the remote BAD to zero and call callback if possible */
+ memset(p_inq->remname_bda, 0, BD_ADDR_LEN);
+
+ p_inq->p_remname_cmpl_cb = NULL;
+ if (p_cb) {
+ (p_cb)((tBTM_REMOTE_DEV_NAME *)&rem_name);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_inq_rmt_name_failed
+**
+** Description This function is if timeout expires while getting remote
+** name. This is done for devices that incorrectly do not
+** report operation failure
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_inq_rmt_name_failed (void)
+{
+ BTM_TRACE_ERROR ("btm_inq_rmt_name_failed() remname_active=%d\n", btm_cb.btm_inq_vars.remname_active);
+
+ if (btm_cb.btm_inq_vars.remname_active) {
+ btm_process_remote_name (btm_cb.btm_inq_vars.remname_bda, NULL, 0, HCI_ERR_UNSPECIFIED);
+ } else {
+ btm_process_remote_name (NULL, NULL, 0, HCI_ERR_UNSPECIFIED);
+ }
+#if (SMP_INCLUDED == TRUE)
+ btm_sec_rmt_name_request_complete (NULL, NULL, HCI_ERR_UNSPECIFIED);
+#endif ///SMP_INCLUDED == TRUE
+}
+/*******************************************************************************
+**
+** Function btm_read_linq_tx_power_complete
+**
+** Description read inquiry tx power level complete callback function.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_linq_tx_power_complete(UINT8 *p)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_txpwer_cmpl_cb;
+ tBTM_INQ_TXPWR_RESULTS results;
+
+ btu_stop_timer (&btm_cb.devcb.txpwer_timer);
+ /* If there was a callback registered for read inq tx power, call it */
+ btm_cb.devcb.p_txpwer_cmpl_cb = NULL;
+
+ if (p_cb) {
+ STREAM_TO_UINT8 (results.hci_status, p);
+
+ if (results.hci_status == HCI_SUCCESS) {
+ results.status = BTM_SUCCESS;
+
+ STREAM_TO_UINT8 (results.tx_power, p);
+ BTM_TRACE_EVENT ("BTM INQ TX POWER Complete: tx_power %d, hci status 0x%02x\n",
+ results.tx_power, results.hci_status);
+ } else {
+ results.status = BTM_ERR_PROCESSING;
+ }
+
+ (*p_cb)(&results);
+ }
+
+}
+/*******************************************************************************
+**
+** Function BTM_WriteEIR
+**
+** Description This function is called to write EIR data to controller.
+**
+** Parameters p_buff - allocated HCI command buffer including extended
+** inquriry response
+** fec_required - FEC is required or not
+**
+** Returns BTM_SUCCESS - if successful
+** BTM_MODE_UNSUPPORTED - if local device cannot support it
+**
+*******************************************************************************/
+tBTM_STATUS BTM_WriteEIR( BT_HDR *p_buff, BOOLEAN fec_required)
+{
+ if (controller_get_interface()->supports_extended_inquiry_response()) {
+ BTM_TRACE_API("Write Extended Inquiry Response to controller\n");
+ btsnd_hcic_write_ext_inquiry_response (p_buff, fec_required);
+ osi_free(p_buff);
+ return BTM_SUCCESS;
+ } else {
+ osi_free(p_buff);
+ return BTM_MODE_UNSUPPORTED;
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_CheckEirData
+**
+** Description This function is called to get EIR data from significant part.
+**
+** Parameters p_eir - pointer of EIR significant part
+** type - finding EIR data type
+** p_length - return the length of EIR data not including type
+**
+** Returns pointer of EIR data
+**
+*******************************************************************************/
+UINT8 *BTM_CheckEirData( UINT8 *p_eir, UINT8 type, UINT8 *p_length )
+{
+ UINT8 *p = p_eir;
+ UINT8 length;
+ UINT8 eir_type;
+ BTM_TRACE_API("BTM_CheckEirData type=0x%02X\n", type);
+
+ STREAM_TO_UINT8(length, p);
+ while ( length && (p - p_eir <= HCI_EXT_INQ_RESPONSE_LEN)) {
+ STREAM_TO_UINT8(eir_type, p);
+ if ( eir_type == type ) {
+ /* length doesn't include itself */
+ *p_length = length - 1; /* minus the length of type */
+ return p;
+ }
+ p += length - 1; /* skip the length of data */
+ STREAM_TO_UINT8(length, p);
+ }
+
+ *p_length = 0;
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function btm_convert_uuid_to_eir_service
+**
+** Description This function is called to get the bit position of UUID.
+**
+** Parameters uuid16 - UUID 16-bit
+**
+** Returns BTM EIR service ID if found
+** BTM_EIR_MAX_SERVICES - if not found
+**
+*******************************************************************************/
+static UINT8 btm_convert_uuid_to_eir_service( UINT16 uuid16 )
+{
+ UINT8 xx;
+
+ for ( xx = 0; xx < BTM_EIR_MAX_SERVICES; xx++ ) {
+ if ( uuid16 == BTM_EIR_UUID_LKUP_TBL[xx]) {
+ return xx;
+ }
+ }
+ return BTM_EIR_MAX_SERVICES;
+}
+
+/*******************************************************************************
+**
+** Function BTM_HasEirService
+**
+** Description This function is called to know if UUID in bit map of UUID.
+**
+** Parameters p_eir_uuid - bit map of UUID list
+** uuid16 - UUID 16-bit
+**
+** Returns TRUE - if found
+** FALSE - if not found
+**
+*******************************************************************************/
+BOOLEAN BTM_HasEirService( UINT32 *p_eir_uuid, UINT16 uuid16 )
+{
+ UINT8 service_id;
+
+ service_id = btm_convert_uuid_to_eir_service(uuid16);
+ if ( service_id < BTM_EIR_MAX_SERVICES ) {
+ return ( BTM_EIR_HAS_SERVICE( p_eir_uuid, service_id ));
+ } else {
+ return ( FALSE );
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_HasInquiryEirService
+**
+** Description This function is called to know if UUID in bit map of UUID list.
+**
+** Parameters p_results - inquiry results
+** uuid16 - UUID 16-bit
+**
+** Returns BTM_EIR_FOUND - if found
+** BTM_EIR_NOT_FOUND - if not found and it is complete list
+** BTM_EIR_UNKNOWN - if not found and it is not complete list
+**
+*******************************************************************************/
+tBTM_EIR_SEARCH_RESULT BTM_HasInquiryEirService( tBTM_INQ_RESULTS *p_results, UINT16 uuid16 )
+{
+ if ( BTM_HasEirService( p_results->eir_uuid, uuid16 )) {
+ return BTM_EIR_FOUND;
+ } else if ( p_results->eir_complete_list ) {
+ return BTM_EIR_NOT_FOUND;
+ } else {
+ return BTM_EIR_UNKNOWN;
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_AddEirService
+**
+** Description This function is called to add a service in bit map of UUID list.
+**
+** Parameters p_eir_uuid - bit mask of UUID list for EIR
+** uuid16 - UUID 16-bit
+**
+** Returns None
+**
+*******************************************************************************/
+void BTM_AddEirService( UINT32 *p_eir_uuid, UINT16 uuid16 )
+{
+ UINT8 service_id;
+
+ service_id = btm_convert_uuid_to_eir_service(uuid16);
+ if ( service_id < BTM_EIR_MAX_SERVICES ) {
+ BTM_EIR_SET_SERVICE( p_eir_uuid, service_id );
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_compare_uuid
+**
+** Description Helper function for custom service managing routines.
+**
+** Parameters uuid1 - pointer to the first tBT_UUID struct
+** uuid2 - pointer to the second tBT_UUID struct
+**
+** Returns true if UUID structs are identical
+**
+*******************************************************************************/
+static bool btm_compare_uuid(tBT_UUID *uuid1, tBT_UUID *uuid2)
+{
+ if (uuid1->len != uuid2->len) {
+ return FALSE;
+ }
+
+ return (memcmp(&uuid1->uu, &uuid2->uu, uuid1->len) == 0);
+}
+
+/*******************************************************************************
+**
+** Function btm_find_empty_custom_uuid_slot
+**
+** Description Helper function for custom service managing routines.
+**
+** Parameters custom_uuid - pointer to custom_uuid array in tBTA_DM_CB
+** uuid - UUID struct
+**
+** Returns Slot number if there is empty slot,
+** otherwise - BTA_EIR_SERVER_NUM_CUSTOM_UUID
+**
+*******************************************************************************/
+static UINT8 btm_find_empty_custom_uuid_slot(tBT_UUID *custom_uuid, tBT_UUID uuid)
+{
+ for (UINT8 xx = 0; xx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; xx++) {
+ if (custom_uuid[xx].len == 0) {
+ return xx;
+ }
+ }
+ return BTA_EIR_SERVER_NUM_CUSTOM_UUID;
+}
+
+/*******************************************************************************
+**
+** Function btm_find_match_custom_uuid_slot
+**
+** Description Helper function for custom service managing routines.
+**
+** Parameters custom_uuid - pointer to custom_uuid array in tBTA_DM_CB
+** uuid - UUID struct
+**
+** Returns Slot number if given UUID is already in slots array,
+** otherwise - BTA_EIR_SERVER_NUM_CUSTOM_UUID
+**
+*******************************************************************************/
+static UINT8 btm_find_match_custom_uuid_slot(tBT_UUID *custom_uuid, tBT_UUID uuid)
+{
+ for (UINT8 xx = 0; xx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; xx++) {
+ if (btm_compare_uuid(&custom_uuid[xx], &uuid)) {
+ return xx;
+ }
+ }
+ return BTA_EIR_SERVER_NUM_CUSTOM_UUID;
+}
+
+/*******************************************************************************
+**
+** Function BTM_HasCustomEirService
+**
+** Description This function is called to know if UUID is already in custom
+** UUID list.
+**
+** Parameters custom_uuid - pointer to custom_uuid array in tBTA_DM_CB
+** uuid - UUID struct
+**
+** Returns TRUE - if found
+** FALSE - if not found
+**
+*******************************************************************************/
+BOOLEAN BTM_HasCustomEirService(tBT_UUID *custom_uuid, tBT_UUID uuid)
+{
+ UINT8 match_slot = btm_find_match_custom_uuid_slot(custom_uuid, uuid);
+
+ if (match_slot == BTA_EIR_SERVER_NUM_CUSTOM_UUID) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function BTM_AddCustomEirService
+**
+** Description This function is called to add a custom UUID.
+**
+** Parameters custom_uuid - pointer to custom_uuid array in tBTA_DM_CB
+** uuid - UUID struct
+**
+** Returns None
+**
+*******************************************************************************/
+void BTM_AddCustomEirService(tBT_UUID *custom_uuid, tBT_UUID uuid)
+{
+ UINT8 empty_slot = btm_find_empty_custom_uuid_slot(custom_uuid, uuid);
+
+ if (empty_slot == BTA_EIR_SERVER_NUM_CUSTOM_UUID) {
+ BTM_TRACE_WARNING("No space to add UUID for EIR");
+ } else {
+ memcpy(&(custom_uuid[empty_slot]), &(uuid), sizeof(tBT_UUID));
+ BTM_TRACE_EVENT("UUID saved in %d slot", empty_slot);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_RemoveCustomEirService
+**
+** Description This function is called to remove a service in bit map of UUID list.
+**
+** Parameters p_eir_uuid - bit mask of UUID list for EIR
+** uuid16 - UUID 16-bit
+**
+** Returns None
+**
+*******************************************************************************/
+void BTM_RemoveEirService( UINT32 *p_eir_uuid, UINT16 uuid16 )
+{
+ UINT8 service_id;
+
+ service_id = btm_convert_uuid_to_eir_service(uuid16);
+ if ( service_id < BTM_EIR_MAX_SERVICES ) {
+ BTM_EIR_CLR_SERVICE( p_eir_uuid, service_id );
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_RemoveCustomEirService
+**
+** Description This function is called to remove a a custom UUID.
+**
+** Parameters custom_uuid - pointer to custom_uuid array in tBTA_DM_CB
+** uuid - UUID struct
+**
+** Returns None
+**
+*******************************************************************************/
+void BTM_RemoveCustomEirService(tBT_UUID *custom_uuid, tBT_UUID uuid)
+{
+ UINT8 match_slot = btm_find_match_custom_uuid_slot(custom_uuid, uuid);
+
+ if (match_slot == BTA_EIR_SERVER_NUM_CUSTOM_UUID) {
+ BTM_TRACE_WARNING("UUID is not found for EIR");
+ return;
+ } else {
+ memset(&(custom_uuid[match_slot]), 0, sizeof(tBT_UUID));
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetEirSupportedServices
+**
+** Description This function is called to get UUID list from bit map of UUID list.
+**
+** Parameters p_eir_uuid - bit mask of UUID list for EIR
+** p - reference of current pointer of EIR
+** max_num_uuid16 - max number of UUID can be written in EIR
+** num_uuid16 - number of UUID have been written in EIR
+**
+** Returns BTM_EIR_MORE_16BITS_UUID_TYPE, if it has more than max
+** BTM_EIR_COMPLETE_16BITS_UUID_TYPE, otherwise
+**
+*******************************************************************************/
+UINT8 BTM_GetEirSupportedServices( UINT32 *p_eir_uuid, UINT8 **p,
+ UINT8 max_num_uuid16, UINT8 *p_num_uuid16)
+{
+ UINT8 service_index;
+
+ *p_num_uuid16 = 0;
+
+ for (service_index = 0; service_index < BTM_EIR_MAX_SERVICES; service_index++) {
+ if ( BTM_EIR_HAS_SERVICE( p_eir_uuid, service_index )) {
+ if ( *p_num_uuid16 < max_num_uuid16 ) {
+ UINT16_TO_STREAM(*p, BTM_EIR_UUID_LKUP_TBL[service_index]);
+ (*p_num_uuid16)++;
+ }
+ /* if max number of UUIDs are stored and found one more */
+ else {
+ return BTM_EIR_MORE_16BITS_UUID_TYPE;
+ }
+ }
+ }
+ return BTM_EIR_COMPLETE_16BITS_UUID_TYPE;
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetEirUuidList
+**
+** Description This function parses EIR and returns UUID list.
+**
+** Parameters p_eir - EIR
+** uuid_size - LEN_UUID_16, LEN_UUID_32, LEN_UUID_128
+** p_num_uuid - return number of UUID in found list
+** p_uuid_list - return UUID list
+** max_num_uuid - maximum number of UUID to be returned
+**
+** Returns 0 - if not found
+** BTM_EIR_COMPLETE_16BITS_UUID_TYPE
+** BTM_EIR_MORE_16BITS_UUID_TYPE
+** BTM_EIR_COMPLETE_32BITS_UUID_TYPE
+** BTM_EIR_MORE_32BITS_UUID_TYPE
+** BTM_EIR_COMPLETE_128BITS_UUID_TYPE
+** BTM_EIR_MORE_128BITS_UUID_TYPE
+**
+*******************************************************************************/
+UINT8 BTM_GetEirUuidList( UINT8 *p_eir, UINT8 uuid_size, UINT8 *p_num_uuid,
+ UINT8 *p_uuid_list, UINT8 max_num_uuid)
+{
+ UINT8 *p_uuid_data;
+ UINT8 type;
+ UINT8 yy, xx;
+ UINT16 *p_uuid16 = (UINT16 *)p_uuid_list;
+ UINT32 *p_uuid32 = (UINT32 *)p_uuid_list;
+ char buff[LEN_UUID_128 * 2 + 1];
+
+ p_uuid_data = btm_eir_get_uuid_list( p_eir, uuid_size, p_num_uuid, &type );
+ if ( p_uuid_data == NULL ) {
+ return 0x00;
+ }
+
+ if ( *p_num_uuid > max_num_uuid ) {
+ BTM_TRACE_WARNING("BTM_GetEirUuidList number of uuid in EIR = %d, size of uuid list = %d\n",
+ *p_num_uuid, max_num_uuid );
+ *p_num_uuid = max_num_uuid;
+ }
+
+ BTM_TRACE_DEBUG("BTM_GetEirUuidList type = %02X, number of uuid = %d\n", type, *p_num_uuid );
+
+ if ( uuid_size == LEN_UUID_16 ) {
+ for ( yy = 0; yy < *p_num_uuid; yy++ ) {
+ STREAM_TO_UINT16(*(p_uuid16 + yy), p_uuid_data);
+ BTM_TRACE_DEBUG(" 0x%04X\n", *(p_uuid16 + yy));
+ }
+ } else if ( uuid_size == LEN_UUID_32 ) {
+ for ( yy = 0; yy < *p_num_uuid; yy++ ) {
+ STREAM_TO_UINT32(*(p_uuid32 + yy), p_uuid_data);
+ BTM_TRACE_DEBUG(" 0x%08X\n", *(p_uuid32 + yy));
+ }
+ } else if ( uuid_size == LEN_UUID_128 ) {
+ for ( yy = 0; yy < *p_num_uuid; yy++ ) {
+ STREAM_TO_ARRAY16(p_uuid_list + yy * LEN_UUID_128, p_uuid_data);
+ for ( xx = 0; xx < LEN_UUID_128; xx++ ) {
+ sprintf(buff + xx * 2, "%02X", *(p_uuid_list + yy * LEN_UUID_128 + xx));
+ }
+ BTM_TRACE_DEBUG(" 0x%s\n", buff);
+ }
+ }
+
+ return type;
+}
+
+
+/*******************************************************************************
+**
+** Function btm_eir_get_uuid_list
+**
+** Description This function searches UUID list in EIR.
+**
+** Parameters p_eir - address of EIR
+** uuid_size - size of UUID to find
+** p_num_uuid - number of UUIDs found
+** p_uuid_list_type - EIR data type
+**
+** Returns NULL - if UUID list with uuid_size is not found
+** beginning of UUID list in EIR - otherwise
+**
+*******************************************************************************/
+static UINT8 *btm_eir_get_uuid_list( UINT8 *p_eir, UINT8 uuid_size,
+ UINT8 *p_num_uuid, UINT8 *p_uuid_list_type )
+{
+ UINT8 *p_uuid_data;
+ UINT8 complete_type, more_type;
+ UINT8 uuid_len;
+
+ switch ( uuid_size ) {
+ case LEN_UUID_16:
+ complete_type = BTM_EIR_COMPLETE_16BITS_UUID_TYPE;
+ more_type = BTM_EIR_MORE_16BITS_UUID_TYPE;
+ break;
+ case LEN_UUID_32:
+ complete_type = BTM_EIR_COMPLETE_32BITS_UUID_TYPE;
+ more_type = BTM_EIR_MORE_32BITS_UUID_TYPE;
+ break;
+ case LEN_UUID_128:
+ complete_type = BTM_EIR_COMPLETE_128BITS_UUID_TYPE;
+ more_type = BTM_EIR_MORE_128BITS_UUID_TYPE;
+ break;
+ default:
+ *p_num_uuid = 0;
+ return NULL;
+ break;
+ }
+
+ p_uuid_data = BTM_CheckEirData( p_eir, complete_type, &uuid_len );
+ if (p_uuid_data == NULL) {
+ p_uuid_data = BTM_CheckEirData( p_eir, more_type, &uuid_len );
+ *p_uuid_list_type = more_type;
+ } else {
+ *p_uuid_list_type = complete_type;
+ }
+
+ *p_num_uuid = uuid_len / uuid_size;
+ return p_uuid_data;
+}
+
+/*******************************************************************************
+**
+** Function btm_convert_uuid_to_uuid16
+**
+** Description This function converts UUID to UUID 16-bit.
+**
+** Parameters p_uuid - address of UUID
+** uuid_size - size of UUID
+**
+** Returns 0 - if UUID cannot be converted to UUID 16-bit
+** UUID 16-bit - otherwise
+**
+*******************************************************************************/
+static UINT16 btm_convert_uuid_to_uuid16( UINT8 *p_uuid, UINT8 uuid_size )
+{
+ static const UINT8 base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ UINT16 uuid16 = 0;
+ UINT32 uuid32;
+ BOOLEAN is_base_uuid;
+ UINT8 xx;
+
+ switch (uuid_size) {
+ case LEN_UUID_16:
+ STREAM_TO_UINT16 (uuid16, p_uuid);
+ break;
+ case LEN_UUID_32:
+ STREAM_TO_UINT32 (uuid32, p_uuid);
+ if (uuid32 < 0x10000) {
+ uuid16 = (UINT16) uuid32;
+ }
+ break;
+ case LEN_UUID_128:
+ /* See if we can compress his UUID down to 16 or 32bit UUIDs */
+ is_base_uuid = TRUE;
+ for (xx = 0; xx < LEN_UUID_128 - 4; xx++) {
+ if (p_uuid[xx] != base_uuid[xx]) {
+ is_base_uuid = FALSE;
+ break;
+ }
+ }
+ if (is_base_uuid) {
+ if ((p_uuid[LEN_UUID_128 - 1] == 0) && (p_uuid[LEN_UUID_128 - 2] == 0)) {
+ p_uuid += (LEN_UUID_128 - 4);
+ STREAM_TO_UINT16(uuid16, p_uuid);
+ }
+ }
+ break;
+ default:
+ BTM_TRACE_WARNING("btm_convert_uuid_to_uuid16 invalid uuid size\n");
+ break;
+ }
+
+ return ( uuid16);
+}
+
+/*******************************************************************************
+**
+** Function btm_set_eir_uuid
+**
+** Description This function is called to store received UUID into inquiry result.
+**
+** Parameters p_eir - pointer of EIR significant part
+** p_results - pointer of inquiry result
+**
+** Returns None
+**
+*******************************************************************************/
+void btm_set_eir_uuid( UINT8 *p_eir, tBTM_INQ_RESULTS *p_results )
+{
+ UINT8 *p_uuid_data;
+ UINT8 num_uuid;
+ UINT16 uuid16;
+ UINT8 yy;
+ UINT8 type = BTM_EIR_MORE_16BITS_UUID_TYPE;
+
+ p_uuid_data = btm_eir_get_uuid_list( p_eir, LEN_UUID_16, &num_uuid, &type );
+
+ if (type == BTM_EIR_COMPLETE_16BITS_UUID_TYPE) {
+ p_results->eir_complete_list = TRUE;
+ } else {
+ p_results->eir_complete_list = FALSE;
+ }
+
+ BTM_TRACE_API("btm_set_eir_uuid eir_complete_list=0x%02X\n", p_results->eir_complete_list);
+
+ if ( p_uuid_data ) {
+ for ( yy = 0; yy < num_uuid; yy++ ) {
+ STREAM_TO_UINT16(uuid16, p_uuid_data);
+ BTM_AddEirService( p_results->eir_uuid, uuid16 );
+ }
+ }
+
+ p_uuid_data = btm_eir_get_uuid_list( p_eir, LEN_UUID_32, &num_uuid, &type );
+ if ( p_uuid_data ) {
+ for ( yy = 0; yy < num_uuid; yy++ ) {
+ uuid16 = btm_convert_uuid_to_uuid16( p_uuid_data, LEN_UUID_32 );
+ p_uuid_data += LEN_UUID_32;
+ if ( uuid16 ) {
+ BTM_AddEirService( p_results->eir_uuid, uuid16 );
+ }
+ }
+ }
+
+ p_uuid_data = btm_eir_get_uuid_list( p_eir, LEN_UUID_128, &num_uuid, &type );
+ if ( p_uuid_data ) {
+ for ( yy = 0; yy < num_uuid; yy++ ) {
+ uuid16 = btm_convert_uuid_to_uuid16( p_uuid_data, LEN_UUID_128 );
+ p_uuid_data += LEN_UUID_128;
+ if ( uuid16 ) {
+ BTM_AddEirService( p_results->eir_uuid, uuid16 );
+ }
+ }
+ }
+}
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_main.c b/lib/bt/host/bluedroid/stack/btm/btm_main.c
new file mode 100644
index 00000000..05ef1837
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_main.c
@@ -0,0 +1,152 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-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 the definition of the btm control block when
+ * BTM_DYNAMIC_MEMORY is used.
+ *
+ ******************************************************************************/
+
+#include "stack/bt_types.h"
+#include "common/bt_target.h"
+#include <string.h>
+#include "btm_int.h"
+#include "osi/allocator.h"
+
+/* Global BTM control block structure
+*/
+#if BTM_DYNAMIC_MEMORY == FALSE
+tBTM_CB btm_cb;
+#else
+tBTM_CB *btm_cb_ptr;
+#endif
+
+#if (BLE_50_FEATURE_SUPPORT == TRUE)
+extern void btm_ble_extendadvcb_init(void);
+extern void btm_ble_advrecod_init(void);
+#endif
+
+
+/*******************************************************************************
+**
+** Function btm_init
+**
+** Description This function is called at BTM startup to allocate the
+** control block (if using dynamic memory), and initializes the
+** tracing level. It then initializes the various components of
+** btm.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_init (void)
+{
+#if BTM_DYNAMIC_MEMORY
+ btm_cb_ptr = (tBTM_CB *)osi_malloc(sizeof(tBTM_CB));
+#endif /* #if BTM_DYNAMIC_MEMORY */
+ /* All fields are cleared; nonzero fields are reinitialized in appropriate function */
+ memset(&btm_cb, 0, sizeof(tBTM_CB));
+ btm_cb.page_queue = fixed_queue_new(QUEUE_SIZE_MAX);
+ btm_cb.sec_pending_q = fixed_queue_new(QUEUE_SIZE_MAX);
+
+#if defined(BTM_INITIAL_TRACE_LEVEL)
+ btm_cb.trace_level = BTM_INITIAL_TRACE_LEVEL;
+#else
+ btm_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+ /* Initialize BTM component structures */
+ btm_inq_db_init(); /* Inquiry Database and Structures */
+ btm_acl_init(); /* ACL Database and Structures */
+#if (SMP_INCLUDED == TRUE)
+ btm_sec_init(BTM_SEC_MODE_SP); /* Security Manager Database and Structures */
+#endif ///SMP_INCLUDED == TRUE
+#if BTM_SCO_INCLUDED == TRUE
+ btm_sco_init(); /* SCO Database and Structures (If included) */
+#endif
+
+ btm_dev_init(); /* Device Manager Structures & HCI_Reset */
+#if BLE_INCLUDED == TRUE
+ btm_ble_lock_init();
+ btm_ble_sem_init();
+#endif
+ btm_sec_dev_init();
+#if (BLE_50_FEATURE_SUPPORT == TRUE)
+ btm_ble_extendadvcb_init();
+ btm_ble_advrecod_init();
+#endif
+
+}
+
+
+/*******************************************************************************
+**
+** Function btm_free
+**
+** Description This function is called at btu core free the fixed queue
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_free(void)
+{
+ fixed_queue_free(btm_cb.page_queue, osi_free_func);
+ fixed_queue_free(btm_cb.sec_pending_q, osi_free_func);
+ btm_acl_free();
+ btm_sec_dev_free();
+#if BTM_DYNAMIC_MEMORY
+ FREE_AND_RESET(btm_cb_ptr);
+#endif
+#if BLE_INCLUDED == TRUE
+ btm_ble_lock_free();
+ btm_ble_sem_free();
+#endif
+}
+
+uint8_t btm_acl_active_count(void)
+{
+ list_node_t *p_node = NULL;
+ tACL_CONN *p_acl_conn = NULL;
+ uint8_t count = 0;
+
+ for (p_node = list_begin(btm_cb.p_acl_db_list); p_node; p_node = list_next(p_node)) {
+ p_acl_conn = list_node(p_node);
+ if (p_acl_conn && p_acl_conn->in_use) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+uint8_t btdm_sec_dev_active_count(void)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+ list_node_t *p_node = NULL;
+ uint8_t count = 0;
+
+ /* First look for the non-paired devices for the oldest entry */
+ for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
+ p_dev_rec = list_node(p_node);
+ if (p_dev_rec && (p_dev_rec->sec_flags & BTM_SEC_IN_USE)) {
+ count++;
+ }
+ }
+
+ return count;
+}
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_pm.c b/lib/bt/host/bluedroid/stack/btm/btm_pm.c
new file mode 100644
index 00000000..4c52348e
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_pm.c
@@ -0,0 +1,965 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2000-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 functions that manages ACL link modes.
+ * This includes operations such as active, hold,
+ * park and sniff modes.
+ *
+ * This module contains both internal and external (API)
+ * functions. External (API) functions are distinguishable
+ * by their names beginning with uppercase BTM.
+ *
+ *****************************************************************************/
+
+//#define LOG_TAG "bt_btm_pm"
+
+#include <stdlib.h>
+#include <string.h>
+//#include <stdio.h>
+#include <stddef.h>
+
+#include "stack/bt_types.h"
+#include "stack/hcimsgs.h"
+#include "stack/btu.h"
+#include "stack/btm_api.h"
+#include "btm_int.h"
+#include "l2c_int.h"
+#include "stack/hcidefs.h"
+//#include "bt_utils.h"
+//#include "osi/include/log.h"
+#include "osi/allocator.h"
+/*****************************************************************************/
+/* to handle different modes */
+/*****************************************************************************/
+#define BTM_PM_STORED_MASK 0x80 /* set this mask if the command is stored */
+#define BTM_PM_NUM_SET_MODES 3 /* only hold, sniff & park */
+
+/* Usage: (ptr_features[ offset ] & mask )?TRUE:FALSE */
+/* offset to supported feature */
+const UINT8 btm_pm_mode_off[BTM_PM_NUM_SET_MODES] = {0, 0, 1};
+/* mask to supported feature */
+const UINT8 btm_pm_mode_msk[BTM_PM_NUM_SET_MODES] = {0x40, 0x80, 0x01};
+
+#define BTM_PM_GET_MD1 1
+#define BTM_PM_GET_MD2 2
+#define BTM_PM_GET_COMP 3
+
+const UINT8 btm_pm_md_comp_matrix[BTM_PM_NUM_SET_MODES * BTM_PM_NUM_SET_MODES] = {
+ BTM_PM_GET_COMP,
+ BTM_PM_GET_MD2,
+ BTM_PM_GET_MD2,
+
+ BTM_PM_GET_MD1,
+ BTM_PM_GET_COMP,
+ BTM_PM_GET_MD1,
+
+ BTM_PM_GET_MD1,
+ BTM_PM_GET_MD2,
+ BTM_PM_GET_COMP
+};
+
+/* function prototype */
+static tBTM_STATUS btm_pm_snd_md_req( UINT8 pm_id, UINT16 link_hdl, tBTM_PM_PWR_MD *p_mode );
+#if (!CONFIG_BT_STACK_NO_LOG)
+static const char *mode_to_string(tBTM_PM_MODE mode);
+#endif
+
+/*
+#ifdef BTM_PM_DEBUG
+#undef BTM_PM_DEBUG
+#define BTM_PM_DEBUG TRUE
+#endif
+*/
+
+#if BTM_PM_DEBUG == TRUE
+const char *btm_pm_state_str[] = {
+ "pm_active_state",
+ "pm_hold_state",
+ "pm_sniff_state",
+ "pm_park_state",
+ "pm_pend_state"
+};
+
+const char *btm_pm_event_str[] = {
+ "pm_set_mode_event",
+ "pm_hci_sts_event",
+ "pm_mod_chg_event",
+ "pm_update_event"
+};
+
+const char *btm_pm_action_str[] = {
+ "pm_set_mode_action",
+ "pm_update_db_action",
+ "pm_mod_chg_action",
+ "pm_hci_sts_action",
+ "pm_update_action"
+};
+#endif // BTM_PM_DEBUG
+
+/*****************************************************************************/
+/* P U B L I C F U N C T I O N S */
+/*****************************************************************************/
+/*******************************************************************************
+**
+** Function BTM_PmRegister
+**
+** Description register or deregister with power manager
+**
+** Returns BTM_SUCCESS if successful,
+** BTM_NO_RESOURCES if no room to hold registration
+** BTM_ILLEGAL_VALUE
+**
+*******************************************************************************/
+tBTM_STATUS BTM_PmRegister (UINT8 mask, UINT8 *p_pm_id, tBTM_PM_STATUS_CBACK *p_cb)
+{
+ int xx;
+
+ /* de-register */
+ if (mask & BTM_PM_DEREG) {
+ if (*p_pm_id >= BTM_MAX_PM_RECORDS) {
+ return BTM_ILLEGAL_VALUE;
+ }
+ btm_cb.pm_reg_db[*p_pm_id].mask = BTM_PM_REC_NOT_USED;
+ return BTM_SUCCESS;
+ }
+
+ for (xx = 0; xx < BTM_MAX_PM_RECORDS; xx++) {
+ /* find an unused entry */
+ if (btm_cb.pm_reg_db[xx].mask == BTM_PM_REC_NOT_USED) {
+ /* if register for notification, should provide callback routine */
+ if (mask & BTM_PM_REG_NOTIF) {
+ if (p_cb == NULL) {
+ return BTM_ILLEGAL_VALUE;
+ }
+ btm_cb.pm_reg_db[xx].cback = p_cb;
+ }
+ btm_cb.pm_reg_db[xx].mask = mask;
+ *p_pm_id = xx;
+ return BTM_SUCCESS;
+ }
+ }
+
+ return BTM_NO_RESOURCES;
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetPowerMode
+**
+** Description store the mode in control block or
+** alter ACL connection behavior.
+**
+** Returns BTM_SUCCESS if successful,
+** BTM_UNKNOWN_ADDR if bd addr is not active or bad
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetPowerMode (UINT8 pm_id, BD_ADDR remote_bda, tBTM_PM_PWR_MD *p_mode)
+{
+ UINT8 *p_features;
+ int ind;
+ tBTM_PM_MCB *p_cb = NULL; /* per ACL link */
+ tBTM_PM_MODE mode;
+ int temp_pm_id;
+ tACL_CONN *p_acl_cb;
+
+ if (pm_id >= BTM_MAX_PM_RECORDS) {
+ pm_id = BTM_PM_SET_ONLY_ID;
+ }
+
+ if (p_mode == NULL) {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ BTM_TRACE_API( "BTM_SetPowerMode: pm_id %d BDA: %08x mode:0x%x", pm_id,
+ (remote_bda[2] << 24) + (remote_bda[3] << 16) + (remote_bda[4] << 8) + remote_bda[5], p_mode->mode);
+
+ /* take out the force bit */
+ mode = p_mode->mode & ~BTM_PM_MD_FORCE;
+
+ p_acl_cb = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+ if (p_acl_cb == NULL){
+ return BTM_UNKNOWN_ADDR;
+ }
+
+ p_cb = p_acl_cb->p_pm_mode_db;
+ if (mode != BTM_PM_MD_ACTIVE) {
+ /* check if the requested mode is supported */
+ ind = mode - BTM_PM_MD_HOLD; /* make it base 0 */
+ p_features = BTM_ReadLocalFeatures();
+ if ( !(p_features[ btm_pm_mode_off[ind] ] & btm_pm_mode_msk[ind] ) ) {
+ return BTM_MODE_UNSUPPORTED;
+ }
+ }
+
+ if (mode == p_cb->state) { /* the requested mode is current mode */
+ /* already in the requested mode and the current interval has less latency than the max */
+ if ( (mode == BTM_PM_MD_ACTIVE) ||
+ ((p_mode->mode & BTM_PM_MD_FORCE) && (p_mode->max >= p_cb->interval) && (p_mode->min <= p_cb->interval)) ||
+ ((p_mode->mode & BTM_PM_MD_FORCE) == 0 && (p_mode->max >= p_cb->interval)) ) {
+ BTM_TRACE_DEBUG( "BTM_SetPowerMode: mode:0x%x interval %d max:%d, min:%d", p_mode->mode, p_cb->interval, p_mode->max, p_mode->min);
+ return BTM_SUCCESS;
+ }
+ }
+
+ temp_pm_id = pm_id;
+ if (pm_id == BTM_PM_SET_ONLY_ID) {
+ temp_pm_id = BTM_MAX_PM_RECORDS;
+ }
+
+ /* update mode database */
+ if ( ((pm_id != BTM_PM_SET_ONLY_ID) &&
+ (btm_cb.pm_reg_db[pm_id].mask & BTM_PM_REG_SET))
+ || ((pm_id == BTM_PM_SET_ONLY_ID)
+ && (btm_cb.pm_pend_link_hdl != BTM_INVALID_HANDLE)) ) {
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG( "BTM_SetPowerMode: Saving cmd acl handle %d temp_pm_id %d", p_acl_cb->hci_handle, temp_pm_id);
+#endif // BTM_PM_DEBUG
+ /* Make sure mask is set to BTM_PM_REG_SET */
+ btm_cb.pm_reg_db[temp_pm_id].mask |= BTM_PM_REG_SET;
+ *(&p_cb->req_mode[temp_pm_id]) = *((tBTM_PM_PWR_MD *)p_mode);
+ p_cb->chg_ind = TRUE;
+ }
+
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG( "btm_pm state:0x%x, pm_pend_link_hdl: %d", p_cb->state, btm_cb.pm_pend_link_hdl);
+#endif // BTM_PM_DEBUG
+ /* if mode == hold or pending, return */
+ if ( (p_cb->state == BTM_PM_STS_HOLD) ||
+ (p_cb->state == BTM_PM_STS_PENDING) ||
+ (btm_cb.pm_pend_link_hdl != BTM_INVALID_HANDLE) ||
+ (p_cb->state & BTM_PM_STORED_MASK) ) { /* command pending */
+ if (p_acl_cb->hci_handle != btm_cb.pm_pend_link_hdl) {
+ /* set the stored mask */
+ p_cb->state |= BTM_PM_STORED_MASK;
+ BTM_TRACE_DEBUG( "btm_pm state stored:%d", p_acl_cb->hci_handle);
+ }
+ return BTM_CMD_STORED;
+ }
+
+
+
+ return btm_pm_snd_md_req(pm_id, p_acl_cb->hci_handle, p_mode);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadPowerMode
+**
+** Description This returns the current mode for a specific
+** ACL connection.
+**
+** Input Param remote_bda - device address of desired ACL connection
+**
+** Output Param p_mode - address where the current mode is copied into.
+** BTM_ACL_MODE_NORMAL
+** BTM_ACL_MODE_HOLD
+** BTM_ACL_MODE_SNIFF
+** BTM_ACL_MODE_PARK
+** (valid only if return code is BTM_SUCCESS)
+**
+** Returns BTM_SUCCESS if successful,
+** BTM_UNKNOWN_ADDR if bd addr is not active or bad
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadPowerMode (BD_ADDR remote_bda, tBTM_PM_MODE *p_mode)
+{
+ tACL_CONN *p_acl_cb = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+ if (!p_acl_cb) {
+ return (BTM_UNKNOWN_ADDR);
+ }
+
+ *p_mode = p_acl_cb->p_pm_mode_db->state;
+ return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetSsrParams
+**
+** Description This sends the given SSR parameters for the given ACL
+** connection if it is in ACTIVE mode.
+**
+** Input Param remote_bda - device address of desired ACL connection
+** max_lat - maximum latency (in 0.625ms)(0-0xFFFE)
+** min_rmt_to - minimum remote timeout
+** min_loc_to - minimum local timeout
+**
+**
+** Returns BTM_SUCCESS if the HCI command is issued successful,
+** BTM_UNKNOWN_ADDR if bd addr is not active or bad
+** BTM_CMD_STORED if the command is stored
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetSsrParams (BD_ADDR remote_bda, UINT16 max_lat,
+ UINT16 min_rmt_to, UINT16 min_loc_to)
+{
+#if (BTM_SSR_INCLUDED == TRUE)
+ tBTM_PM_MCB *p_cb;
+ tACL_CONN *p_acl_cb = NULL;
+
+ p_acl_cb = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+ if (!p_acl_cb) {
+ return (BTM_UNKNOWN_ADDR);
+ }
+ p_cb = p_acl_cb->p_pm_mode_db;
+
+ if (BTM_PM_STS_ACTIVE == p_cb->state ||
+ BTM_PM_STS_SNIFF == p_cb->state) {
+ if (btsnd_hcic_sniff_sub_rate(p_acl_cb->hci_handle, max_lat,
+ min_rmt_to, min_loc_to)) {
+ return BTM_SUCCESS;
+ } else {
+ return BTM_NO_RESOURCES;
+ }
+ }
+ p_cb->max_lat = max_lat;
+ p_cb->min_rmt_to = min_rmt_to;
+ p_cb->min_loc_to = min_loc_to;
+ return BTM_CMD_STORED;
+#else
+ return BTM_ILLEGAL_ACTION;
+#endif // BTM_SSR_INCLUDED
+}
+
+/*******************************************************************************
+**
+** Function btm_pm_reset
+**
+** Description as a part of the BTM reset process.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_pm_reset(void)
+{
+ int xx;
+ tBTM_PM_STATUS_CBACK *cb = NULL;
+
+ /* clear the pending request for application */
+ if ( (btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) &&
+ (btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF) ) {
+ cb = btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback;
+ }
+
+
+ /* clear the register record */
+ for (xx = 0; xx < BTM_MAX_PM_RECORDS; xx++) {
+ btm_cb.pm_reg_db[xx].mask = BTM_PM_REC_NOT_USED;
+ }
+
+ if (cb != NULL && btm_cb.pm_pend_link_hdl != BTM_INVALID_HANDLE) {
+ (*cb)((btm_handle_to_acl(btm_cb.pm_pend_link_hdl))->remote_addr, BTM_PM_STS_ERROR, BTM_DEV_RESET, 0);
+ }
+
+ /* no command pending */
+ btm_cb.pm_pend_link_hdl = BTM_INVALID_HANDLE;
+}
+
+/*******************************************************************************
+**
+** Function btm_pm_sm_alloc
+**
+** Description This function initializes the control block of an ACL link.
+** It is called when an ACL connection is created.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_PM_MCB *btm_pm_sm_alloc(void)
+{
+ tBTM_PM_MCB *p_db = (tBTM_PM_MCB *) osi_malloc(sizeof(tBTM_PM_MCB)); /* per ACL link */
+ if (p_db) {
+ memset (p_db, 0, sizeof(tBTM_PM_MCB));
+ p_db->state = BTM_PM_ST_ACTIVE;
+ if (list_length(btm_cb.p_pm_mode_db_list) >= MAX_L2CAP_LINKS) {
+ osi_free(p_db);
+ p_db = NULL;
+ }
+ if (!list_append(btm_cb.p_pm_mode_db_list, p_db)) {
+ osi_free(p_db);
+ p_db = NULL;
+ }
+ }
+ return p_db;
+}
+/*******************************************************************************
+**
+** Function btm_pm_find_acl_ind
+**
+** Description This function initializes the control block of an ACL link.
+** It is called when an ACL connection is created.
+**
+** Returns void
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Function btm_pm_compare_modes
+** Description get the "more active" mode of the 2
+** Returns void
+**
+*******************************************************************************/
+static tBTM_PM_PWR_MD *btm_pm_compare_modes(tBTM_PM_PWR_MD *p_md1, tBTM_PM_PWR_MD *p_md2, tBTM_PM_PWR_MD *p_res)
+{
+ UINT8 res;
+
+ if (p_md1 == NULL) {
+ *p_res = *p_md2;
+ p_res->mode &= ~BTM_PM_MD_FORCE;
+
+ return p_md2;
+ }
+
+ if (p_md2->mode == BTM_PM_MD_ACTIVE || p_md1->mode == BTM_PM_MD_ACTIVE) {
+ return NULL;
+ }
+
+ /* check if force bit is involved */
+ if (p_md1->mode & BTM_PM_MD_FORCE) {
+ *p_res = *p_md1;
+ p_res->mode &= ~BTM_PM_MD_FORCE;
+ return p_res;
+ }
+
+ if (p_md2->mode & BTM_PM_MD_FORCE) {
+ *p_res = *p_md2;
+ p_res->mode &= ~BTM_PM_MD_FORCE;
+ return p_res;
+ }
+
+ res = (p_md1->mode - 1) * BTM_PM_NUM_SET_MODES + (p_md2->mode - 1);
+ res = btm_pm_md_comp_matrix[res];
+ switch (res) {
+ case BTM_PM_GET_MD1:
+ *p_res = *p_md1;
+ return p_md1;
+
+ case BTM_PM_GET_MD2:
+ *p_res = *p_md2;
+ return p_md2;
+
+ case BTM_PM_GET_COMP:
+ p_res->mode = p_md1->mode;
+ /* min of the two */
+ p_res->max = (p_md1->max < p_md2->max) ? (p_md1->max) : (p_md2->max);
+ /* max of the two */
+ p_res->min = (p_md1->min > p_md2->min) ? (p_md1->min) : (p_md2->min);
+
+ /* the intersection is NULL */
+ if ( p_res->max < p_res->min) {
+ return NULL;
+ }
+
+ if (p_res->mode == BTM_PM_MD_SNIFF) {
+ /* max of the two */
+ p_res->attempt = (p_md1->attempt > p_md2->attempt) ? (p_md1->attempt) : (p_md2->attempt);
+ p_res->timeout = (p_md1->timeout > p_md2->timeout) ? (p_md1->timeout) : (p_md2->timeout);
+ }
+ return p_res;
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function btm_pm_get_set_mode
+** Description get the resulting mode from the registered parties, then compare it
+** with the requested mode, if the command is from an unregistered party.
+** Returns void
+**
+*******************************************************************************/
+static tBTM_PM_MODE btm_pm_get_set_mode(UINT8 pm_id, tBTM_PM_MCB *p_cb, tBTM_PM_PWR_MD *p_mode, tBTM_PM_PWR_MD *p_res)
+{
+ int xx, loop_max;
+ tBTM_PM_PWR_MD *p_md = NULL;
+
+ if (p_mode != NULL && p_mode->mode & BTM_PM_MD_FORCE) {
+ *p_res = *p_mode;
+ p_res->mode &= ~BTM_PM_MD_FORCE;
+ return p_res->mode;
+ }
+
+ if (!p_mode) {
+ loop_max = BTM_MAX_PM_RECORDS + 1;
+ } else {
+ loop_max = BTM_MAX_PM_RECORDS;
+ }
+
+ for ( xx = 0; xx < loop_max; xx++) {
+ /* g through all the registered "set" parties */
+ if (btm_cb.pm_reg_db[xx].mask & BTM_PM_REG_SET) {
+ if (p_cb->req_mode[xx].mode == BTM_PM_MD_ACTIVE) {
+ /* if at least one registered (SET) party says ACTIVE, stay active */
+ return BTM_PM_MD_ACTIVE;
+ } else {
+ /* if registered parties give conflicting information, stay active */
+ if ( (btm_pm_compare_modes(p_md, &p_cb->req_mode[xx], p_res)) == NULL) {
+ return BTM_PM_MD_ACTIVE;
+ }
+ p_md = p_res;
+ }
+ }
+ }
+
+ /* if the resulting mode is NULL(nobody registers SET), use the requested mode */
+ if (p_md == NULL) {
+ if (p_mode) {
+ *p_res = *((tBTM_PM_PWR_MD *)p_mode);
+ } else { /* p_mode is NULL when btm_pm_snd_md_req is called from btm_pm_proc_mode_change */
+ return BTM_PM_MD_ACTIVE;
+ }
+ } else {
+ /* if the command is from unregistered party,
+ compare the resulting mode from registered party*/
+ if ( (pm_id == BTM_PM_SET_ONLY_ID) &&
+ ((btm_pm_compare_modes(p_mode, p_md, p_res)) == NULL) ) {
+ return BTM_PM_MD_ACTIVE;
+ }
+ }
+
+ return p_res->mode;
+}
+
+/*******************************************************************************
+**
+** Function btm_pm_snd_md_req
+** Description get the resulting mode and send the resuest to host controller
+** Returns tBTM_STATUS
+**, BOOLEAN *p_chg_ind
+*******************************************************************************/
+static tBTM_STATUS btm_pm_snd_md_req(UINT8 pm_id, UINT16 link_hdl, tBTM_PM_PWR_MD *p_mode)
+{
+ tBTM_PM_PWR_MD md_res;
+ tBTM_PM_MODE mode;
+ tACL_CONN *p_acl_cb = btm_handle_to_acl(link_hdl);
+ tBTM_PM_MCB *p_cb = p_acl_cb->p_pm_mode_db;
+ BOOLEAN chg_ind = FALSE;
+
+ mode = btm_pm_get_set_mode(pm_id, p_cb, p_mode, &md_res);
+ md_res.mode = mode;
+
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG( "btm_pm_snd_md_req link_hdl:%d, mode: %d",
+ link_hdl, mode);
+#endif // BTM_PM_DEBUG
+
+ if ( p_cb->state == mode) {
+ /* already in the resulting mode */
+ if ( (mode == BTM_PM_MD_ACTIVE) ||
+ ((md_res.max >= p_cb->interval) && (md_res.min <= p_cb->interval)) ) {
+ return BTM_CMD_STORED;
+ }
+ /* Otherwise, needs to wake, then sleep */
+ chg_ind = TRUE;
+ }
+ p_cb->chg_ind = chg_ind;
+
+ /* cannot go directly from current mode to resulting mode. */
+ if ( mode != BTM_PM_MD_ACTIVE && p_cb->state != BTM_PM_MD_ACTIVE) {
+ p_cb->chg_ind = TRUE; /* needs to wake, then sleep */
+ }
+
+ if (p_cb->chg_ind == TRUE) { /* needs to wake first */
+ md_res.mode = BTM_PM_MD_ACTIVE;
+ }
+#if (BTM_SSR_INCLUDED == TRUE)
+ else if (BTM_PM_MD_SNIFF == md_res.mode && p_cb->max_lat) {
+ btsnd_hcic_sniff_sub_rate(link_hdl, p_cb->max_lat,
+ p_cb->min_rmt_to, p_cb->min_loc_to);
+ p_cb->max_lat = 0;
+ }
+#endif // BTM_SSR_INCLUDED
+ /* Default is failure */
+ btm_cb.pm_pend_link_hdl = BTM_INVALID_HANDLE;
+
+ /* send the appropriate HCI command */
+ btm_cb.pm_pend_id = pm_id;
+
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG("btm_pm_snd_md_req state:0x%x, link_hdl: %d", p_cb->state, link_hdl);
+#endif // BTM_PM_DEBUG
+
+ BTM_TRACE_DEBUG("%s switching from %s to %s.", __func__, mode_to_string(p_cb->state), mode_to_string(md_res.mode));
+ switch (md_res.mode) {
+ case BTM_PM_MD_ACTIVE:
+ switch (p_cb->state) {
+ case BTM_PM_MD_SNIFF:
+ if (btsnd_hcic_exit_sniff_mode(link_hdl)) {
+ btm_cb.pm_pend_link_hdl = link_hdl;
+ }
+ break;
+ case BTM_PM_MD_PARK:
+ if (btsnd_hcic_exit_park_mode(link_hdl)) {
+ btm_cb.pm_pend_link_hdl = link_hdl;
+ }
+ break;
+ default:
+ /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
+ break;
+ }
+ break;
+
+ case BTM_PM_MD_HOLD:
+ if (btsnd_hcic_hold_mode (link_hdl,
+ md_res.max, md_res.min)) {
+ btm_cb.pm_pend_link_hdl = link_hdl;
+ }
+ break;
+
+ case BTM_PM_MD_SNIFF:
+ if (btsnd_hcic_sniff_mode (link_hdl,
+ md_res.max, md_res.min, md_res.attempt,
+ md_res.timeout)) {
+ btm_cb.pm_pend_link_hdl = link_hdl;
+ }
+ break;
+
+ case BTM_PM_MD_PARK:
+ if (btsnd_hcic_park_mode (link_hdl,
+ md_res.max, md_res.min)) {
+ btm_cb.pm_pend_link_hdl = link_hdl;
+ }
+ break;
+ default:
+ /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
+ break;
+ }
+
+ if (btm_cb.pm_pend_link_hdl == BTM_INVALID_HANDLE) {
+ /* the command was not sent */
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG( "pm_pend_link_hdl: %d", btm_cb.pm_pend_link_hdl);
+#endif // BTM_PM_DEBUG
+ return (BTM_NO_RESOURCES);
+ }
+
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function btm_pm_check_stored
+**
+** Description This function is called when an HCI command status event occurs
+** to check if there's any PM command issued while waiting for
+** HCI command status.
+**
+** Returns none.
+**
+*******************************************************************************/
+static void btm_pm_check_stored(void)
+{
+ tACL_CONN *p_acl_cb = NULL;
+ list_node_t *p_node = NULL;
+ for (p_node = list_begin(btm_cb.p_acl_db_list); p_node; p_node = list_next(p_node)) {
+ p_acl_cb = list_node(p_node);
+ if (p_acl_cb->p_pm_mode_db->state & BTM_PM_STORED_MASK) {
+ p_acl_cb->p_pm_mode_db->state &= ~BTM_PM_STORED_MASK;
+ BTM_TRACE_DEBUG( "btm_pm_check_stored :%d", p_acl_cb->hci_handle);
+ btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, p_acl_cb->hci_handle, NULL);
+ break;
+ }
+ }
+
+}
+
+
+/*******************************************************************************
+**
+** Function btm_pm_proc_cmd_status
+**
+** Description This function is called when an HCI command status event occurs
+** for power manager related commands.
+**
+** Input Parms status - status of the event (HCI_SUCCESS if no errors)
+**
+** Returns none.
+**
+*******************************************************************************/
+void btm_pm_proc_cmd_status(UINT8 status)
+{
+ tBTM_PM_MCB *p_cb;
+ tBTM_PM_STATUS pm_status;
+ tACL_CONN *p_acl_cb;
+
+ if (btm_cb.pm_pend_link_hdl == BTM_INVALID_HANDLE) {
+ return;
+ }
+
+
+ p_acl_cb = btm_handle_to_acl(btm_cb.pm_pend_link_hdl);
+ if (p_acl_cb == NULL) {
+ return;
+ }
+ p_cb = p_acl_cb->p_pm_mode_db;
+
+ if (status == HCI_SUCCESS) {
+ p_cb->state = BTM_PM_ST_PENDING;
+ pm_status = BTM_PM_STS_PENDING;
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG( "btm_pm_proc_cmd_status new state:0x%x", p_cb->state);
+#endif // BTM_PM_DEBUG
+ } else { /* the command was not successfull. Stay in the same state */
+ pm_status = BTM_PM_STS_ERROR;
+ }
+
+ /* notify the caller is appropriate */
+ if ( (btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) &&
+ (btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF) ) {
+ (*btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback)(p_acl_cb->remote_addr, pm_status, 0, status);
+ }
+
+ /* no pending cmd now */
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG( "btm_pm_proc_cmd_status state:0x%x, pm_pend_link: %d(new: %d)",
+ p_cb->state, btm_cb.pm_pend_link_hdl, MAX_L2CAP_LINKS);
+#endif // BTM_PM_DEBUG
+ btm_cb.pm_pend_link_hdl = BTM_INVALID_HANDLE;
+
+ btm_pm_check_stored();
+}
+
+/*******************************************************************************
+**
+** Function btm_process_mode_change
+**
+** Description This function is called when an HCI mode change event occurs.
+**
+** Input Parms hci_status - status of the event (HCI_SUCCESS if no errors)
+** hci_handle - connection handle associated with the change
+** mode - HCI_MODE_ACTIVE, HCI_MODE_HOLD, HCI_MODE_SNIFF, or HCI_MODE_PARK
+** interval - number of baseband slots (meaning depends on mode)
+**
+** Returns none.
+**
+*******************************************************************************/
+void btm_pm_proc_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode, UINT16 interval)
+{
+ tACL_CONN *p;
+ tBTM_PM_MCB *p_cb = NULL;
+ int yy;
+ tBTM_PM_STATE old_state;
+ tL2C_LCB *p_lcb;
+
+ /* get the index to acl_db */
+ p = btm_handle_to_acl(hci_handle);
+ if (!p) {
+ return;
+ }
+
+ /* update control block */
+ p_cb = p->p_pm_mode_db;
+ old_state = p_cb->state;
+ p_cb->state = mode;
+ p_cb->interval = interval;
+
+ BTM_TRACE_DEBUG("%s switched from %s to %s.", __func__, mode_to_string(old_state), mode_to_string(p_cb->state));
+
+ if ((p_lcb = l2cu_find_lcb_by_bd_addr(p->remote_addr, BT_TRANSPORT_BR_EDR)) != NULL) {
+ if ((p_cb->state == BTM_PM_ST_ACTIVE) || (p_cb->state == BTM_PM_ST_SNIFF)) {
+ /* There might be any pending packets due to SNIFF or PENDING state */
+ /* Trigger L2C to start transmission of the pending packets. */
+ BTM_TRACE_DEBUG("btm mode change to active; check l2c_link for outgoing packets");
+ l2c_link_check_send_pkts(p_lcb, NULL, NULL);
+ }
+ }
+
+ /* notify registered parties */
+ for (yy = 0; yy <= BTM_MAX_PM_RECORDS; yy++) {
+ /* set req_mode HOLD mode->ACTIVE */
+ if ( (mode == BTM_PM_MD_ACTIVE) && (p_cb->req_mode[yy].mode == BTM_PM_MD_HOLD) ) {
+ p_cb->req_mode[yy].mode = BTM_PM_MD_ACTIVE;
+ }
+ }
+
+ /* new request has been made. - post a message to BTU task */
+ if (old_state & BTM_PM_STORED_MASK) {
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG( "btm_pm_proc_mode_change: Sending stored req:%d", xx);
+#endif // BTM_PM_DEBUG
+ btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, hci_handle, NULL);
+ } else {
+ list_node_t *p_node = NULL;
+
+ for (p_node =(list_begin(btm_cb.p_pm_mode_db_list)); p_node; p_node = (list_next(p_node))) {
+ p_cb = (tBTM_PM_MCB *)list_node(p_node);
+ if (p_cb->chg_ind == TRUE) {
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG( "btm_pm_proc_mode_change: Sending PM req :%d", zz);
+#endif // BTM_PM_DEBUG
+ btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, hci_handle, NULL);
+ break;
+ }
+ }
+ }
+
+
+ /* notify registered parties */
+ for (yy = 0; yy < BTM_MAX_PM_RECORDS; yy++) {
+ if (btm_cb.pm_reg_db[yy].mask & BTM_PM_REG_NOTIF) {
+ (*btm_cb.pm_reg_db[yy].cback)( p->remote_addr, mode, interval, hci_status);
+ }
+ }
+
+ /* If mode change was because of an active role switch or change link key */
+ btm_cont_rswitch(p, btm_find_dev(p->remote_addr), hci_status);
+}
+
+/*******************************************************************************
+**
+** Function btm_pm_proc_ssr_evt
+**
+** Description This function is called when an HCI sniff subrating event occurs.
+**
+** Returns none.
+**
+*******************************************************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+void btm_pm_proc_ssr_evt (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT16 handle;
+ UINT16 max_rx_lat;
+ int xx;
+ tBTM_PM_MCB *p_cb;
+ tACL_CONN *p_acl = NULL;
+ UINT16 use_ssr = TRUE;
+ UNUSED(evt_len);
+
+ STREAM_TO_UINT8 (status, p);
+
+ STREAM_TO_UINT16 (handle, p);
+ /* get the index to acl_db */
+
+ p += 2;
+ STREAM_TO_UINT16 (max_rx_lat, p);
+ p_acl = btm_handle_to_acl(handle);
+ if (!p_acl) {
+ return;
+ }
+ p_cb = p_acl->p_pm_mode_db;
+ if (p_cb->interval == max_rx_lat) {
+ /* using legacy sniff */
+ use_ssr = FALSE;
+ }
+
+ /* notify registered parties */
+ for (xx = 0; xx < BTM_MAX_PM_RECORDS; xx++) {
+ if (btm_cb.pm_reg_db[xx].mask & BTM_PM_REG_NOTIF) {
+ if ( p_acl) {
+ (*btm_cb.pm_reg_db[xx].cback)( p_acl->remote_addr, BTM_PM_STS_SSR, use_ssr, status);
+ }
+ }
+ }
+}
+#endif // BTM_SSR_INCLUDED
+
+/*******************************************************************************
+**
+** Function btm_pm_device_in_active_or_sniff_mode
+**
+** Description This function is called to check if in active or sniff mode
+**
+** Returns TRUE, if in active or sniff mode
+**
+*******************************************************************************/
+BOOLEAN btm_pm_device_in_active_or_sniff_mode(void)
+{
+ /* The active state is the highest state-includes connected device and sniff mode*/
+
+ /* Covers active and sniff modes */
+ if (BTM_GetNumAclLinks() > 0) {
+ BTM_TRACE_DEBUG("%s - ACL links: %d", __func__, BTM_GetNumAclLinks());
+ return TRUE;
+ }
+
+#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
+ /* Check BLE states */
+ if (btm_ble_get_conn_st() != BLE_CONN_IDLE) {
+ BTM_TRACE_DEBUG("%s - BLE state: %x", __func__, btm_ble_get_conn_st());
+ return TRUE;
+ }
+#endif
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btm_pm_device_in_scan_state
+**
+** Description This function is called to check if in paging, inquiry or connecting mode
+**
+** Returns TRUE, if in paging, inquiry or connecting mode
+**
+*******************************************************************************/
+BOOLEAN btm_pm_device_in_scan_state(void)
+{
+ /* Scan state-paging, inquiry, and trying to connect */
+
+ /* Check for paging */
+ if (btm_cb.is_paging || (!fixed_queue_is_empty(btm_cb.page_queue)) ||
+ BTM_BL_PAGING_STARTED == btm_cb.busy_level) {
+ BTM_TRACE_DEBUG("btm_pm_device_in_scan_state- paging");
+ return TRUE;
+ }
+
+ /* Check for inquiry */
+ if ((btm_cb.btm_inq_vars.inq_active & (BTM_BR_INQ_ACTIVE_MASK | BTM_BLE_INQ_ACTIVE_MASK)) != 0) {
+ BTM_TRACE_DEBUG("btm_pm_device_in_scan_state- Inq active");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function BTM_PM_ReadControllerState
+**
+** Description This function is called to obtain the controller state
+**
+** Returns Controller State-BTM_CONTRL_ACTIVE, BTM_CONTRL_SCAN, and BTM_CONTRL_IDLE
+**
+*******************************************************************************/
+tBTM_CONTRL_STATE BTM_PM_ReadControllerState(void)
+{
+ if (TRUE == btm_pm_device_in_active_or_sniff_mode()) {
+ return BTM_CONTRL_ACTIVE;
+ } else if (TRUE == btm_pm_device_in_scan_state()) {
+ return BTM_CONTRL_SCAN;
+ } else {
+ return BTM_CONTRL_IDLE;
+ }
+}
+
+#if (!CONFIG_BT_STACK_NO_LOG)
+static const char *mode_to_string(tBTM_PM_MODE mode)
+{
+ switch (mode) {
+ case BTM_PM_MD_ACTIVE: return "ACTIVE";
+ case BTM_PM_MD_SNIFF: return "SNIFF";
+ case BTM_PM_MD_PARK: return "PARK";
+ case BTM_PM_MD_HOLD: return "HOLD";
+ default: return "UNKNOWN";
+ }
+}
+#endif
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_sco.c b/lib/bt/host/bluedroid/stack/btm/btm_sco.c
new file mode 100644
index 00000000..53a9768a
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_sco.c
@@ -0,0 +1,1907 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2000-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 functions that handle SCO connections. This includes
+ * operations such as connect, disconnect, change supported packet types.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "stack/bt_types.h"
+#include "common/bt_target.h"
+#include "stack/bt_types.h"
+#include "stack/hcimsgs.h"
+#include "stack/btu.h"
+#include "stack/btm_api.h"
+#include "osi/allocator.h"
+#include "btm_int.h"
+#include "stack/hcidefs.h"
+//#include "bt_utils.h"
+
+#if BTM_SCO_INCLUDED == TRUE
+
+/********************************************************************************/
+/* L O C A L D A T A D E F I N I T I O N S */
+/********************************************************************************/
+
+#define SCO_ST_UNUSED 0
+#define SCO_ST_LISTENING 1
+#define SCO_ST_W4_CONN_RSP 2
+#define SCO_ST_CONNECTING 3
+#define SCO_ST_CONNECTED 4
+#define SCO_ST_DISCONNECTING 5
+#define SCO_ST_PEND_UNPARK 6
+#define SCO_ST_PEND_ROLECHANGE 7
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+
+static const tBTM_ESCO_PARAMS btm_esco_defaults = {
+ BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec) */
+ BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec) */
+ 0x000a, /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3) */
+ 0x0060, /* Inp Linear, Air CVSD, 2s Comp, 16bit */
+ (BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types */
+ BTM_SCO_PKT_TYPES_MASK_HV2 +
+ BTM_SCO_PKT_TYPES_MASK_HV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV4 +
+ BTM_SCO_PKT_TYPES_MASK_EV5),
+ BTM_ESCO_RETRANS_POWER /* Retransmission Effort (Power) */
+};
+
+/*******************************************************************************
+**
+** Function btm_sco_flush_sco_data
+**
+** Description This function is called to flush the SCO data for this channel.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_flush_sco_data(UINT16 sco_inx)
+{
+#if BTM_SCO_HCI_INCLUDED == TRUE
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p ;
+ BT_HDR *p_buf;
+
+ if (sco_inx < BTM_MAX_SCO_LINKS) {
+ p = &btm_cb.sco_cb.sco_db[sco_inx];
+ while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p->xmit_data_q, 0)) != NULL) {
+ osi_free(p_buf);
+ }
+ }
+#else
+ UNUSED(sco_inx);
+#endif
+#else
+ UNUSED(sco_inx);
+#endif
+}
+/*******************************************************************************
+**
+** Function btm_sco_init
+**
+** Description This function is called at BTM startup to initialize
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_init (void)
+{
+#if 0 /* cleared in btm_init; put back in if called from anywhere else! */
+ memset (&btm_cb.sco_cb, 0, sizeof(tSCO_CB));
+#endif
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ for (int i = 0; i < BTM_MAX_SCO_LINKS; i++) {
+ btm_cb.sco_cb.sco_db[i].xmit_data_q = fixed_queue_new(QUEUE_SIZE_MAX);
+ }
+#endif
+ /* Initialize nonzero defaults */
+ btm_cb.sco_cb.sco_disc_reason = BTM_INVALID_SCO_DISC_REASON;
+
+ btm_cb.sco_cb.def_esco_parms = btm_esco_defaults; /* Initialize with defaults */
+ btm_cb.sco_cb.desired_sco_mode = BTM_DEFAULT_SCO_MODE;
+}
+
+/*******************************************************************************
+**
+** Function btm_esco_conn_rsp
+**
+** Description This function is called upon receipt of an (e)SCO connection
+** request event (BTM_ESCO_CONN_REQ_EVT) to accept or reject
+** the request. Parameters used to negotiate eSCO links.
+** If p_parms is NULL, then default values are used.
+** If the link type of the incoming request is SCO, then only
+** the tx_bw, max_latency, content format, and packet_types are
+** valid. The hci_status parameter should be
+** ([0x0] to accept, [0x0d..0x0f] to reject)
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_esco_conn_rsp (UINT16 sco_inx, UINT8 hci_status, BD_ADDR bda,
+ tBTM_ESCO_PARAMS *p_parms)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p_sco = NULL;
+ tBTM_ESCO_PARAMS *p_setup;
+ UINT16 temp_pkt_types;
+
+ if (sco_inx < BTM_MAX_SCO_LINKS) {
+ p_sco = &btm_cb.sco_cb.sco_db[sco_inx];
+ }
+
+ /* Reject the connect request if refused by caller or wrong state */
+ if (hci_status != HCI_SUCCESS || p_sco == NULL) {
+ if (p_sco) {
+ p_sco->state = (p_sco->state == SCO_ST_W4_CONN_RSP) ? SCO_ST_LISTENING
+ : SCO_ST_UNUSED;
+ }
+
+ if (!btm_cb.sco_cb.esco_supported) {
+ if (!btsnd_hcic_reject_conn (bda, hci_status)) {
+ BTM_TRACE_ERROR("Could not reject (e)SCO conn: No Buffer!!!");
+ }
+ } else {
+ if (!btsnd_hcic_reject_esco_conn (bda, hci_status)) {
+ BTM_TRACE_ERROR("Could not reject (e)SCO conn: No Buffer!!!");
+ }
+ }
+ } else { /* Connection is being accepted */
+ p_sco->state = SCO_ST_CONNECTING;
+ p_setup = &p_sco->esco.setup;
+ /* If parameters not specified use the default */
+ if (p_parms) {
+ *p_setup = *p_parms;
+ } else { /* Use the last setup passed thru BTM_SetEscoMode (or defaults) */
+ *p_setup = btm_cb.sco_cb.def_esco_parms;
+ }
+
+ temp_pkt_types = (p_setup->packet_types &
+ BTM_SCO_SUPPORTED_PKTS_MASK &
+ btm_cb.btm_sco_pkt_types_supported);
+
+ /* Make sure at least one eSCO packet type is sent, else might confuse peer */
+ /* Taking this out to confirm with BQB tests
+ ** Real application would like to include this though, as many devices
+ ** do not retry with SCO only if an eSCO connection fails.
+ if (!(temp_pkt_types & BTM_ESCO_LINK_ONLY_MASK))
+ {
+ temp_pkt_types |= BTM_SCO_PKT_TYPES_MASK_EV3;
+ }
+ */
+ /* If SCO request, remove eSCO packet types (conformance) */
+ if (p_sco->esco.data.link_type == BTM_LINK_TYPE_SCO) {
+ temp_pkt_types &= BTM_SCO_LINK_ONLY_MASK;
+ temp_pkt_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
+ } else {
+ /* OR in any exception packet types */
+ temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
+ (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
+ }
+
+ if (btsnd_hcic_accept_esco_conn (bda, p_setup->tx_bw, p_setup->rx_bw,
+ p_setup->max_latency, p_setup->voice_contfmt,
+ p_setup->retrans_effort, temp_pkt_types)) {
+ p_setup->packet_types = temp_pkt_types;
+ } else {
+ BTM_TRACE_ERROR("Could not accept SCO conn: No Buffer!!!");
+ }
+ }
+#endif
+}
+
+
+#if BTM_SCO_HCI_INCLUDED == TRUE
+void btm_sco_process_num_bufs (UINT16 num_lm_sco_bufs)
+{
+ BTM_TRACE_DEBUG("%s, %d", __FUNCTION__, num_lm_sco_bufs);
+ btm_cb.sco_cb.num_lm_sco_bufs = btm_cb.sco_cb.xmit_window_size = num_lm_sco_bufs;
+}
+
+/*******************************************************************************
+**
+** Function BTM_ConfigScoPath
+**
+** Description This function enable/disable SCO over HCI and registers SCO
+** data callback if SCO over HCI is enabled.
+**
+** Parameter path: SCO or HCI
+** p_sco_data_cb: callback function or SCO data if path is set
+** to transport.
+** p_pcm_param: pointer to the PCM interface parameter. If a NULL
+** pointer is used, PCM parameter maintained in
+** the control block will be used; otherwise update
+** control block value.
+** err_data_rpt: Lisbon feature to enable the erronous data report
+** or not.
+**
+** Returns BTM_SUCCESS if the successful.
+** BTM_NO_RESOURCES: no rsource to start the command.
+** BTM_ILLEGAL_VALUE: invalid callback function pointer.
+** BTM_CMD_STARTED :Command sent. Waiting for command cmpl event.
+**
+**
+*******************************************************************************/
+//extern
+tBTM_STATUS BTM_ConfigScoPath (tBTM_SCO_ROUTE_TYPE path,
+ tBTM_SCO_DATA_CB *p_sco_data_cb,
+ tBTM_SCO_PCM_PARAM *p_pcm_param,
+ BOOLEAN err_data_rpt)
+{
+ UNUSED(err_data_rpt);
+ UNUSED(p_pcm_param);
+ btm_cb.sco_cb.sco_path = path;
+ if (path == BTM_SCO_ROUTE_PCM) {
+ return BTM_SUCCESS;
+ } else if (path == BTM_SCO_ROUTE_HCI) {
+ if (p_sco_data_cb) {
+ btm_cb.sco_cb.p_data_cb = p_sco_data_cb;
+ }
+ }
+
+ return BTM_SUCCESS;
+}
+
+static void hci_sco_data_to_lower(BT_HDR *p_buf)
+{
+ p_buf->event = BT_EVT_TO_LM_HCI_SCO;
+ if (p_buf->offset == 0) {
+ BTM_TRACE_ERROR("offset cannot be 0");
+ osi_free(p_buf);
+ }
+
+ bte_main_hci_send(p_buf, (UINT16)(BT_EVT_TO_LM_HCI_SCO | LOCAL_BLE_CONTROLLER_ID));
+}
+/*******************************************************************************
+**
+** Function btm_sco_check_send_pkts
+**
+** Description This function is called to check if it can send packets
+** to the Host Controller.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_check_send_pkts (UINT16 sco_inx)
+{
+ tSCO_CB *p_cb = &btm_cb.sco_cb;
+ tSCO_CONN *p_ccb = &p_cb->sco_db[sco_inx];
+
+ /* If there is data to send, send it now */
+ BT_HDR *p_buf;
+ while (p_cb->xmit_window_size != 0)
+ {
+ if ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_ccb->xmit_data_q, 0)) == NULL) {
+ break;
+ }
+#if BTM_SCO_HCI_DEBUG
+ BTM_TRACE_DEBUG("btm: [%d] buf in xmit_data_q",
+ fixed_queue_length(p_ccb->xmit_data_q) + 1);
+#endif
+ /* Don't go negative */
+ p_cb->xmit_window_size -= 1;
+ p_ccb->sent_not_acked += 1;
+
+ // HCI_SCO_DATA_TO_LOWER(p_buf);
+ hci_sco_data_to_lower(p_buf);
+ }
+}
+
+void btm_sco_process_num_completed_pkts (UINT8 *p)
+{
+ UINT8 num_handles, xx;
+ UINT16 handle;
+ UINT16 num_sent;
+ UINT16 sco_inx;
+ tSCO_CB *p_cb = &btm_cb.sco_cb;
+ tSCO_CONN * p_ccb;
+ STREAM_TO_UINT8 (num_handles, p);
+ for (xx = 0; xx < num_handles; xx++) {
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT16 (num_sent, p);
+ if ((sco_inx = btm_find_scb_by_handle(handle)) == BTM_MAX_SCO_LINKS) {
+ continue;
+ }
+ BTM_TRACE_DEBUG("%s, %d, %u", __FUNCTION__, handle, p_cb->xmit_window_size); //debug
+ p_ccb = &p_cb->sco_db[sco_inx];
+ p_ccb->sent_not_acked -= num_sent;
+ // don't go negative
+ if (p_ccb->sent_not_acked < 0) {
+ BTM_TRACE_WARNING("SCO: un-acked underf: %u", p_ccb->sent_not_acked);
+ p_ccb->sent_not_acked = 0;
+ }
+ p_cb->xmit_window_size += num_sent;
+ if (p_cb->xmit_window_size > p_cb->num_lm_sco_bufs) {
+ BTM_TRACE_WARNING("SCO xwind: %d, max %d", p_cb->xmit_window_size, p_cb->num_lm_sco_bufs);
+ p_cb->xmit_window_size = p_cb->num_lm_sco_bufs;
+ }
+ btm_sco_check_send_pkts (sco_inx);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function btm_pkt_stat_nums_update
+**
+** Description Update the number of received SCO data packet status.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_pkt_stat_nums_update(uint16_t sco_inx, uint8_t pkt_status)
+{
+ tSCO_CONN *p_ccb = &btm_cb.sco_cb.sco_db[sco_inx];
+ p_ccb->pkt_stat_nums.rx_total++;
+ if (pkt_status == BTM_SCO_DATA_CORRECT) {
+ p_ccb->pkt_stat_nums.rx_correct++;
+ } else if (pkt_status == BTM_SCO_DATA_PAR_ERR) {
+ p_ccb->pkt_stat_nums.rx_err++;
+ } else if (pkt_status == BTM_SCO_DATA_NONE) {
+ p_ccb->pkt_stat_nums.rx_none++;
+ } else {
+ p_ccb->pkt_stat_nums.rx_lost++;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_pkt_stat_send_nums_update
+**
+** Description Update the number of send packet status.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_pkt_stat_send_nums_update(uint16_t sco_inx, uint8_t pkt_status)
+{
+ tSCO_CONN *p_ccb = &btm_cb.sco_cb.sco_db[sco_inx];
+ p_ccb->pkt_stat_nums.tx_total++;
+ if (pkt_status != BTM_SUCCESS && pkt_status != BTM_NO_RESOURCES && pkt_status != BTM_SCO_BAD_LENGTH) {
+ p_ccb->pkt_stat_nums.tx_discarded++;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_pkt_stat_nums_reset
+**
+** Description This function is called to reset the number of packet status struct
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_pkt_stat_nums_reset(uint16_t sco_inx)
+{
+ memset(&btm_cb.sco_cb.sco_db[sco_inx].pkt_stat_nums, 0, sizeof(tBTM_SCO_PKT_STAT_NUMS));
+}
+
+/*******************************************************************************
+**
+** Function BTM_PktStatNumsGet
+**
+** Description This function is called to get the number of packet status struct
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_PktStatNumsGet(uint16_t sync_conn_handle, tBTM_SCO_PKT_STAT_NUMS *p_pkt_nums)
+{
+ uint16_t sco_inx = btm_find_scb_by_handle(sync_conn_handle);
+ if (sco_inx < BTM_MAX_SCO_LINKS) {
+ memcpy(p_pkt_nums, &btm_cb.sco_cb.sco_db[sco_inx].pkt_stat_nums, sizeof(tBTM_SCO_PKT_STAT_NUMS));
+ } else {
+ memset(p_pkt_nums, 0, sizeof(tBTM_SCO_PKT_STAT_NUMS));
+ }
+}
+
+#endif /* BTM_SCO_HCI_INCLUDED == TRUE */
+
+/*******************************************************************************
+**
+** Function btm_route_sco_data
+**
+** Description Route received SCO data.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_route_sco_data(BT_HDR *p_msg)
+{
+#if BTM_SCO_HCI_INCLUDED == TRUE
+ UINT16 sco_inx, handle;
+ UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
+ UINT8 pkt_size = 0;
+ UINT8 pkt_status = 0;
+
+ /* Extract Packet_Status_Flag and handle */
+ STREAM_TO_UINT16 (handle, p);
+ pkt_status = HCID_GET_EVENT(handle);
+ handle = HCID_GET_HANDLE (handle);
+
+ STREAM_TO_UINT8 (pkt_size, p);
+ UNUSED(pkt_size);
+ if ((sco_inx = btm_find_scb_by_handle(handle)) != BTM_MAX_SCO_LINKS ) {
+ /* send data callback */
+ if (!btm_cb.sco_cb.p_data_cb )
+ /* if no data callback registered, just free the buffer */
+ {
+ osi_free (p_msg);
+ } else {
+ btm_pkt_stat_nums_update(sco_inx, pkt_status);
+ (*btm_cb.sco_cb.p_data_cb)(sco_inx, p_msg, (tBTM_SCO_DATA_FLAG) pkt_status);
+ }
+ } else { /* no mapping handle SCO connection is active, free the buffer */
+ osi_free (p_msg);
+ }
+ BTM_TRACE_DEBUG ("SCO: hdl %x, len %d, pkt_sz %d\n", handle, p_msg->len, pkt_size);
+#else
+ osi_free(p_msg);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_WriteScoData
+**
+** Description This function write SCO data to a specified instance. The data
+** to be written p_buf needs to carry an offset of
+** HCI_SCO_PREAMBLE_SIZE bytes, and the data length can not
+** exceed BTM_SCO_DATA_SIZE_MAX bytes, whose default value is set
+** to 60 and is configurable. Data longer than the maximum bytes
+** will be truncated.
+**
+** Returns BTM_SUCCESS: data write is successful
+** BTM_ILLEGAL_VALUE: SCO data contains illegal offset value.
+** BTM_SCO_BAD_LENGTH: SCO data length exceeds the max SCO packet
+** size.
+** BTM_NO_RESOURCES: no resources.
+** BTM_UNKNOWN_ADDR: unknown SCO connection handle, or SCO is not
+** routed via HCI.
+** BTM_ERR_PROCESSING: transmit queue overflow
+**
+**
+*******************************************************************************/
+tBTM_STATUS BTM_WriteScoData (UINT16 sco_inx, BT_HDR *p_buf)
+{
+ APPL_TRACE_DEBUG("%s", __FUNCTION__);
+#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p_ccb = &btm_cb.sco_cb.sco_db[sco_inx];
+ UINT8 *p;
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ if (sco_inx < BTM_MAX_SCO_LINKS && btm_cb.sco_cb.p_data_cb &&
+ p_ccb->state == SCO_ST_CONNECTED) {
+ /* Ensure we have enough space in the buffer for the SCO and HCI headers */
+ if (p_buf->offset < HCI_SCO_PREAMBLE_SIZE) {
+ BTM_TRACE_ERROR ("BTM SCO - cannot send buffer, offset: %d", p_buf->offset);
+ status = BTM_ILLEGAL_VALUE;
+ } else { /* write HCI header */
+ /* Step back 3 bytes to add the headers */
+ p_buf->offset -= HCI_SCO_PREAMBLE_SIZE;
+ /* Set the pointer to the beginning of the data */
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ /* add HCI handle */
+ UINT16_TO_STREAM (p, p_ccb->hci_handle);
+ /* only sent the first BTM_SCO_DATA_SIZE_MAX bytes data if more than max,
+ and set warning status */
+ if (p_buf->len > BTM_SCO_DATA_SIZE_MAX) {
+ BTM_TRACE_WARNING ("BTM SCO hdl %x, bad len %u", p_ccb->hci_handle, p_buf->len);
+ p_buf->len = BTM_SCO_DATA_SIZE_MAX;
+ status = BTM_SCO_BAD_LENGTH;
+ }
+
+ UINT8_TO_STREAM (p, (UINT8)p_buf->len);
+
+ p_buf->len += HCI_SCO_PREAMBLE_SIZE;
+
+ if (fixed_queue_length(p_ccb->xmit_data_q) < BTM_SCO_XMIT_QUEUE_THRS) {
+ if (fixed_queue_length(p_ccb->xmit_data_q) >= BTM_SCO_XMIT_QUEUE_HIGH_WM) {
+ status = BTM_NO_RESOURCES;
+ }
+ fixed_queue_enqueue(p_ccb->xmit_data_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
+ btm_sco_check_send_pkts (sco_inx);
+ } else {
+ BTM_TRACE_WARNING ("SCO xmit Q overflow, pkt dropped");
+ status = BTM_ERR_PROCESSING;
+ }
+ }
+ } else {
+ BTM_TRACE_WARNING ("BTM_WriteScoData, invalid sco index: %d at state [%d]",
+ sco_inx, btm_cb.sco_cb.sco_db[sco_inx].state);
+ status = BTM_UNKNOWN_ADDR;
+ }
+
+ if (status != BTM_SUCCESS && status!= BTM_NO_RESOURCES && status != BTM_SCO_BAD_LENGTH) {
+ BTM_TRACE_WARNING ("stat %d", status);
+ osi_free(p_buf);
+ }
+ btm_pkt_stat_send_nums_update(sco_inx, status);
+ return (status);
+
+#else
+ UNUSED(sco_inx);
+ UNUSED(p_buf);
+ return (BTM_NO_RESOURCES);
+#endif
+}
+
+#if (BTM_MAX_SCO_LINKS>0)
+/*******************************************************************************
+**
+** Function btm_send_connect_request
+**
+** Description This function is called to respond to SCO connect indications
+**
+** Returns void
+**
+*******************************************************************************/
+static tBTM_STATUS btm_send_connect_request(UINT16 acl_handle,
+ tBTM_ESCO_PARAMS *p_setup)
+{
+ UINT16 temp_pkt_types;
+ tACL_CONN *p_acl;
+
+ /* Send connect request depending on version of spec */
+ if (!btm_cb.sco_cb.esco_supported) {
+ if (!btsnd_hcic_add_SCO_conn (acl_handle, BTM_ESCO_2_SCO(p_setup->packet_types))) {
+ return (BTM_NO_RESOURCES);
+ }
+ } else {
+ temp_pkt_types = (p_setup->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK &
+ btm_cb.btm_sco_pkt_types_supported);
+
+ /* OR in any exception packet types */
+ temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
+ (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
+
+ /* Finally, remove EDR eSCO if the remote device doesn't support it */
+ /* UPF25: Only SCO was brought up in this case */
+ p_acl = btm_handle_to_acl(acl_handle);
+ if (p_acl) {
+ if (!HCI_EDR_ESCO_2MPS_SUPPORTED(p_acl->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) {
+
+ BTM_TRACE_WARNING("BTM Remote does not support 2-EDR eSCO");
+ temp_pkt_types |= (HCI_ESCO_PKT_TYPES_MASK_NO_2_EV3 |
+ HCI_ESCO_PKT_TYPES_MASK_NO_2_EV5);
+ }
+ if (!HCI_EDR_ESCO_3MPS_SUPPORTED(p_acl->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) {
+
+ BTM_TRACE_WARNING("BTM Remote does not support 3-EDR eSCO");
+ temp_pkt_types |= (HCI_ESCO_PKT_TYPES_MASK_NO_3_EV3 |
+ HCI_ESCO_PKT_TYPES_MASK_NO_3_EV5);
+ }
+
+ /* Check to see if BR/EDR Secure Connections is being used
+ ** If so, we cannot use SCO-only packet types (HFP 1.7)
+ */
+ if (BTM_BothEndsSupportSecureConnections(p_acl->remote_addr)) {
+ temp_pkt_types &= ~(BTM_SCO_PKT_TYPE_MASK);
+ BTM_TRACE_DEBUG("%s: SCO Conn: pkt_types after removing SCO (0x%04x)", __FUNCTION__,
+ temp_pkt_types);
+
+ /* Return error if no packet types left */
+ if (temp_pkt_types == 0) {
+ BTM_TRACE_ERROR("%s: SCO Conn (BR/EDR SC): No packet types available",__FUNCTION__);
+ return (BTM_WRONG_MODE);
+ }
+ } else {
+ BTM_TRACE_DEBUG("%s: SCO Conn(BR/EDR SC):local or peer does not support BR/EDR SC",__FUNCTION__);
+ }
+ }
+
+
+ BTM_TRACE_API("txbw 0x%x, rxbw 0x%x, lat 0x%x, voice 0x%x, retrans 0x%02x, pkt 0x%04x",
+ p_setup->tx_bw, p_setup->rx_bw,
+ p_setup->max_latency, p_setup->voice_contfmt,
+ p_setup->retrans_effort, temp_pkt_types);
+
+ if (!btsnd_hcic_setup_esco_conn(acl_handle,
+ p_setup->tx_bw,
+ p_setup->rx_bw,
+ p_setup->max_latency,
+ p_setup->voice_contfmt,
+ p_setup->retrans_effort,
+ temp_pkt_types)) {
+ return (BTM_NO_RESOURCES);
+ } else {
+ p_setup->packet_types = temp_pkt_types;
+ }
+ }
+
+ return (BTM_CMD_STARTED);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function btm_set_sco_ind_cback
+**
+** Description This function is called to register for TCS SCO connect
+** indications.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_set_sco_ind_cback( tBTM_SCO_IND_CBACK *sco_ind_cb )
+{
+ btm_cb.sco_cb.app_sco_ind_cb = sco_ind_cb;
+}
+
+/*******************************************************************************
+**
+** Function btm_accept_sco_link
+**
+** Description This function is called to respond to TCS SCO connect
+** indications
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_accept_sco_link(UINT16 sco_inx, tBTM_ESCO_PARAMS *p_setup,
+ tBTM_SCO_CB *p_conn_cb, tBTM_SCO_CB *p_disc_cb)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p_sco;
+
+ if (sco_inx >= BTM_MAX_SCO_LINKS) {
+ BTM_TRACE_ERROR("btm_accept_sco_link: Invalid sco_inx(%d)", sco_inx);
+ return;
+ }
+
+ /* Link role is ignored in for this message */
+ p_sco = &btm_cb.sco_cb.sco_db[sco_inx];
+ p_sco->p_conn_cb = p_conn_cb;
+ p_sco->p_disc_cb = p_disc_cb;
+ p_sco->esco.data.link_type = BTM_LINK_TYPE_ESCO; /* Accept with all supported types */
+
+ BTM_TRACE_DEBUG("TCS accept SCO: Packet Types 0x%04x", p_setup->packet_types);
+
+ btm_esco_conn_rsp(sco_inx, HCI_SUCCESS, p_sco->esco.data.bd_addr, p_setup);
+#else
+ btm_reject_sco_link(sco_inx);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_reject_sco_link
+**
+** Description This function is called to respond to SCO connect indications
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_reject_sco_link( UINT16 sco_inx )
+{
+ btm_esco_conn_rsp(sco_inx, HCI_ERR_HOST_REJECT_RESOURCES,
+ btm_cb.sco_cb.sco_db[sco_inx].esco.data.bd_addr, NULL);
+}
+
+/*******************************************************************************
+**
+** Function BTM_CreateSco
+**
+** Description This function is called to create an SCO connection. If the
+** "is_orig" flag is TRUE, the connection will be originated,
+** otherwise BTM will wait for the other side to connect.
+**
+** NOTE: If BTM_IGNORE_SCO_PKT_TYPE is passed in the pkt_types
+** parameter the default packet types is used.
+**
+** Returns BTM_UNKNOWN_ADDR if the ACL connection is not up
+** BTM_BUSY if another SCO being set up to
+** the same BD address
+** BTM_NO_RESOURCES if the max SCO limit has been reached
+** BTM_CMD_STARTED if the connection establishment is started.
+** In this case, "*p_sco_inx" is filled in
+** with the sco index used for the connection.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_CreateSco (BD_ADDR remote_bda, BOOLEAN is_orig, UINT16 pkt_types,
+ UINT16 *p_sco_inx, tBTM_SCO_CB *p_conn_cb,
+ tBTM_SCO_CB *p_disc_cb)
+{
+#if (BTM_MAX_SCO_LINKS > 0)
+ tBTM_ESCO_PARAMS *p_setup;
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+ UINT16 xx;
+ UINT16 acl_handle = 0;
+ UINT16 temp_pkt_types;
+ tACL_CONN *p_acl;
+
+#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+ tBTM_PM_MODE md;
+ tBTM_PM_PWR_MD pm;
+#else // BTM_SCO_WAKE_PARKED_LINK
+ UINT8 mode;
+#endif // BTM_SCO_WAKE_PARKED_LINK
+
+ *p_sco_inx = BTM_INVALID_SCO_INDEX;
+
+ /* If originating, ensure that there is an ACL connection to the BD Address */
+ if (is_orig) {
+ if ((!remote_bda) || ((acl_handle = BTM_GetHCIConnHandle (remote_bda, BT_TRANSPORT_BR_EDR)) == 0xFFFF)) {
+ return (BTM_UNKNOWN_ADDR);
+ }
+ }
+
+ if (remote_bda) {
+ /* If any SCO is being established to the remote BD address, refuse this */
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if (((p->state == SCO_ST_CONNECTING) || (p->state == SCO_ST_LISTENING)
+ || (p->state == SCO_ST_PEND_UNPARK))
+ && (!memcmp (p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN))) {
+ return (BTM_BUSY);
+ }
+ }
+ } else {
+ /* Support only 1 wildcard BD address at a time */
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if ((p->state == SCO_ST_LISTENING) && (!p->rem_bd_known)) {
+ return (BTM_BUSY);
+ }
+ }
+ }
+
+ /* Now, try to find an unused control block, and kick off the SCO establishment */
+ for (xx = 0, p = &btm_cb.sco_cb.sco_db[0]; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if (p->state == SCO_ST_UNUSED) {
+ if (remote_bda) {
+ if (is_orig) {
+ /* can not create SCO link if in park mode */
+#if BTM_SCO_WAKE_PARKED_LINK == TRUE
+ if (BTM_ReadPowerMode(remote_bda, &md) == BTM_SUCCESS) {
+ if (md == BTM_PM_MD_PARK || md == BTM_PM_MD_SNIFF) {
+ memset( (void *)&pm, 0, sizeof(pm));
+ pm.mode = BTM_PM_MD_ACTIVE;
+ BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, remote_bda, &pm);
+ p->state = SCO_ST_PEND_UNPARK;
+ }
+ }
+#else // BTM_SCO_WAKE_PARKED_LINK
+ if ( (BTM_ReadPowerMode(remote_bda, &mode) == BTM_SUCCESS) && (mode == BTM_PM_MD_PARK) ) {
+ return (BTM_WRONG_MODE);
+ }
+#endif // BTM_SCO_WAKE_PARKED_LINK
+ }
+ memcpy (p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN);
+ p->rem_bd_known = TRUE;
+ } else {
+ p->rem_bd_known = FALSE;
+ }
+
+ /* Link role is ignored in for this message */
+ if (pkt_types == BTM_IGNORE_SCO_PKT_TYPE) {
+ pkt_types = btm_cb.sco_cb.def_esco_parms.packet_types;
+ }
+
+ p_setup = &p->esco.setup;
+ *p_setup = btm_cb.sco_cb.def_esco_parms;
+ p_setup->packet_types = (btm_cb.sco_cb.desired_sco_mode == BTM_LINK_TYPE_SCO)
+ ? (pkt_types & BTM_SCO_LINK_ONLY_MASK) : pkt_types;
+
+ temp_pkt_types = (p_setup->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK &
+ btm_cb.btm_sco_pkt_types_supported);
+
+ /* OR in any exception packet types */
+ if (btm_cb.sco_cb.desired_sco_mode == HCI_LINK_TYPE_ESCO) {
+ temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
+ (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
+ } else { /* Only using SCO packet types; turn off EDR also */
+ temp_pkt_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
+ }
+
+ p_setup->packet_types = temp_pkt_types;
+ p->p_conn_cb = p_conn_cb;
+ p->p_disc_cb = p_disc_cb;
+ p->hci_handle = BTM_INVALID_HCI_HANDLE;
+ p->is_orig = is_orig;
+
+ if ( p->state != SCO_ST_PEND_UNPARK ) {
+ if (is_orig) {
+ /* If role change is in progress, do not proceed with SCO setup
+ * Wait till role change is complete */
+ p_acl = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+ if (p_acl && p_acl->switch_role_state != BTM_ACL_SWKEY_STATE_IDLE) {
+ BTM_TRACE_API("Role Change is in progress for ACL handle 0x%04x", acl_handle);
+ p->state = SCO_ST_PEND_ROLECHANGE;
+
+ }
+ }
+ }
+
+ if ( p->state != SCO_ST_PEND_UNPARK && p->state != SCO_ST_PEND_ROLECHANGE ) {
+ if (is_orig) {
+ BTM_TRACE_API("BTM_CreateSco -> (e)SCO Link for ACL handle 0x%04x, Desired Type %d",
+ acl_handle, btm_cb.sco_cb.desired_sco_mode);
+
+ if ((btm_send_connect_request(acl_handle, p_setup)) != BTM_CMD_STARTED) {
+ return (BTM_NO_RESOURCES);
+ }
+
+ p->state = SCO_ST_CONNECTING;
+ } else {
+ p->state = SCO_ST_LISTENING;
+ }
+ }
+
+ *p_sco_inx = xx;
+
+ return (BTM_CMD_STARTED);
+ }
+ }
+
+#endif
+ /* If here, all SCO blocks in use */
+ return (BTM_NO_RESOURCES);
+}
+
+#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+/*******************************************************************************
+**
+** Function btm_sco_chk_pend_unpark
+**
+** Description This function is called by BTIF when there is a mode change
+** event to see if there are SCO commands waiting for the unpark.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_chk_pend_unpark (UINT8 hci_status, UINT16 hci_handle)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ UINT16 xx;
+ UINT16 acl_handle;
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if ((p->state == SCO_ST_PEND_UNPARK) &&
+ ((acl_handle = BTM_GetHCIConnHandle (p->esco.data.bd_addr, BT_TRANSPORT_BR_EDR)) == hci_handle))
+
+ {
+ BTM_TRACE_API("btm_sco_chk_pend_unpark -> (e)SCO Link for ACL handle 0x%04x, Desired Type %d, hci_status 0x%02x",
+ acl_handle, btm_cb.sco_cb.desired_sco_mode, hci_status);
+
+ if ((btm_send_connect_request(acl_handle, &p->esco.setup)) == BTM_CMD_STARTED) {
+ p->state = SCO_ST_CONNECTING;
+ }
+ }
+ }
+#endif // BTM_MAX_SCO_LINKS
+}
+#endif // BTM_SCO_WAKE_PARKED_LINK
+
+/*******************************************************************************
+**
+** Function btm_sco_chk_pend_rolechange
+**
+** Description This function is called by BTIF when there is a role change
+** event to see if there are SCO commands waiting for the role change.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_chk_pend_rolechange (UINT16 hci_handle)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ UINT16 xx;
+ UINT16 acl_handle;
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if ((p->state == SCO_ST_PEND_ROLECHANGE) &&
+ ((acl_handle = BTM_GetHCIConnHandle (p->esco.data.bd_addr, BT_TRANSPORT_BR_EDR)) == hci_handle))
+
+ {
+ BTM_TRACE_API("btm_sco_chk_pend_rolechange -> (e)SCO Link for ACL handle 0x%04x", acl_handle);
+
+ if ((btm_send_connect_request(acl_handle, &p->esco.setup)) == BTM_CMD_STARTED) {
+ p->state = SCO_ST_CONNECTING;
+ }
+ }
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_sco_conn_req
+**
+** Description This function is called by BTIF when an SCO connection
+** request is received from a remote.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_conn_req (BD_ADDR bda, DEV_CLASS dev_class, UINT8 link_type)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CB *p_sco = &btm_cb.sco_cb;
+ tSCO_CONN *p = &p_sco->sco_db[0];
+ UINT16 xx;
+ tBTM_ESCO_CONN_REQ_EVT_DATA evt_data;
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ /*
+ * If the sco state is in the SCO_ST_CONNECTING state, we still need
+ * to return accept sco to avoid race conditon for sco creation
+ */
+ int rem_bd_matches = p->rem_bd_known &&
+ !memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN);
+ if (((p->state == SCO_ST_CONNECTING) && rem_bd_matches) ||
+ ((p->state == SCO_ST_LISTENING) && (rem_bd_matches || !p->rem_bd_known))) {
+ /* If this guy was a wildcard, he is not one any more */
+ p->rem_bd_known = TRUE;
+ p->esco.data.link_type = link_type;
+ p->state = SCO_ST_W4_CONN_RSP;
+ memcpy (p->esco.data.bd_addr, bda, BD_ADDR_LEN);
+
+ /* If no callback, auto-accept the connection if packet types match */
+ if (!p->esco.p_esco_cback) {
+ /* If requesting eSCO reject if default parameters are SCO only */
+ if ((link_type == BTM_LINK_TYPE_ESCO
+ && !(p_sco->def_esco_parms.packet_types & BTM_ESCO_LINK_ONLY_MASK)
+ && ((p_sco->def_esco_parms.packet_types & BTM_SCO_EXCEPTION_PKTS_MASK)
+ == BTM_SCO_EXCEPTION_PKTS_MASK))
+
+ /* Reject request if SCO is desired but no SCO packets delected */
+ || (link_type == BTM_LINK_TYPE_SCO
+ && !(p_sco->def_esco_parms.packet_types & BTM_SCO_LINK_ONLY_MASK))) {
+ btm_esco_conn_rsp(xx, HCI_ERR_HOST_REJECT_RESOURCES, bda, NULL);
+ } else { /* Accept the request */
+ btm_esco_conn_rsp(xx, HCI_SUCCESS, bda, NULL);
+ }
+ } else { /* Notify upper layer of connect indication */
+ memcpy(evt_data.bd_addr, bda, BD_ADDR_LEN);
+ memcpy(evt_data.dev_class, dev_class, DEV_CLASS_LEN);
+ evt_data.link_type = link_type;
+ evt_data.sco_inx = xx;
+ p->esco.p_esco_cback(BTM_ESCO_CONN_REQ_EVT, (tBTM_ESCO_EVT_DATA *)&evt_data);
+ }
+
+ return;
+ }
+ }
+
+ /* TCS usage */
+ if (btm_cb.sco_cb.app_sco_ind_cb) {
+ /* Now, try to find an unused control block */
+ for (xx = 0, p = &btm_cb.sco_cb.sco_db[0]; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if (p->state == SCO_ST_UNUSED) {
+ p->is_orig = FALSE;
+ p->state = SCO_ST_LISTENING;
+
+ p->esco.data.link_type = link_type;
+ memcpy (p->esco.data.bd_addr, bda, BD_ADDR_LEN);
+ p->rem_bd_known = TRUE;
+ break;
+ }
+ }
+ if ( xx < BTM_MAX_SCO_LINKS) {
+ btm_cb.sco_cb.app_sco_ind_cb(xx);
+ return;
+ }
+ }
+
+#endif
+ /* If here, no one wants the SCO connection. Reject it */
+ BTM_TRACE_WARNING("btm_sco_conn_req: No one wants this SCO connection; rejecting it");
+ btm_esco_conn_rsp(BTM_MAX_SCO_LINKS, HCI_ERR_HOST_REJECT_RESOURCES, bda, NULL);
+}
+
+/*******************************************************************************
+**
+** Function btm_sco_connected
+**
+** Description This function is called by BTIF when an (e)SCO connection
+** is connected.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_connected (UINT8 hci_status, BD_ADDR bda, UINT16 hci_handle,
+ tBTM_ESCO_DATA *p_esco_data)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+ UINT16 xx;
+ BOOLEAN spt = FALSE;
+ tBTM_CHG_ESCO_PARAMS parms;
+#endif
+
+ btm_cb.sco_cb.sco_disc_reason = hci_status;
+ BTM_TRACE_API("%s, handle %x", __FUNCTION__, hci_handle);
+#if (BTM_MAX_SCO_LINKS>0)
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if (((p->state == SCO_ST_CONNECTING) ||
+ (p->state == SCO_ST_LISTENING) ||
+ (p->state == SCO_ST_W4_CONN_RSP))
+ && (p->rem_bd_known)
+ && (!bda || !memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN))) {
+ if (hci_status != HCI_SUCCESS) {
+ /* Report the error if originator, otherwise remain in Listen mode */
+ if (p->is_orig) {
+ /* If role switch is pending, we need try again after role switch is complete */
+ if (hci_status == HCI_ERR_ROLE_SWITCH_PENDING) {
+ BTM_TRACE_API("Role Change pending for HCI handle 0x%04x", hci_handle);
+ p->state = SCO_ST_PEND_ROLECHANGE;
+ }
+ /* avoid calling disconnect callback because of sco creation race */
+ else if (hci_status != HCI_ERR_LMP_ERR_TRANS_COLLISION) {
+ p->state = SCO_ST_UNUSED;
+ (*p->p_disc_cb)(xx);
+ }
+ } else {
+ /* Notify the upper layer that incoming sco connection has failed. */
+ if (p->state == SCO_ST_CONNECTING) {
+ p->state = SCO_ST_UNUSED;
+ (*p->p_disc_cb)(xx);
+ } else {
+ p->state = SCO_ST_LISTENING;
+ }
+ }
+
+ return;
+ }
+
+ if (p->state == SCO_ST_LISTENING) {
+ spt = TRUE;
+ }
+#if BTM_SCO_HCI_INCLUDED == TRUE
+ p->sent_not_acked = 0;
+ btm_pkt_stat_nums_reset(xx);
+#endif
+ p->state = SCO_ST_CONNECTED;
+ p->hci_handle = hci_handle;
+
+ if (!btm_cb.sco_cb.esco_supported) {
+ p->esco.data.link_type = BTM_LINK_TYPE_SCO;
+ if (spt) {
+ parms.packet_types = p->esco.setup.packet_types;
+ /* Keep the other parameters the same for SCO */
+ parms.max_latency = p->esco.setup.max_latency;
+ parms.retrans_effort = p->esco.setup.retrans_effort;
+
+ BTM_ChangeEScoLinkParms(xx, &parms);
+ }
+ } else {
+ if (p_esco_data) {
+ p->esco.data = *p_esco_data;
+ }
+ }
+
+ (*p->p_conn_cb)(xx);
+
+ return;
+ }
+ }
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function btm_find_scb_by_handle
+**
+** Description Look through all active SCO connection for a match based on the
+** HCI handle.
+**
+** Returns index to matched SCO connection CB, or BTM_MAX_SCO_LINKS if
+** no match.
+**
+*******************************************************************************/
+UINT16 btm_find_scb_by_handle (UINT16 handle)
+{
+ int xx;
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if ((p->state == SCO_ST_CONNECTED) && (p->hci_handle == handle)) {
+ return (xx);
+ }
+ }
+
+ /* If here, no match found */
+ return (xx);
+}
+
+/*******************************************************************************
+**
+** Function BTM_RemoveSco
+**
+** Description This function is called to remove a specific SCO connection.
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_RemoveSco (UINT16 sco_inx)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[sco_inx];
+ UINT16 tempstate;
+
+ /* Validity check */
+ if ((sco_inx >= BTM_MAX_SCO_LINKS) || (p->state == SCO_ST_UNUSED)) {
+ return (BTM_UNKNOWN_ADDR);
+ }
+
+ /* If no HCI handle, simply drop the connection and return */
+ if (p->hci_handle == BTM_INVALID_HCI_HANDLE || p->state == SCO_ST_PEND_UNPARK) {
+ p->hci_handle = BTM_INVALID_HCI_HANDLE;
+ p->state = SCO_ST_UNUSED;
+ p->esco.p_esco_cback = NULL; /* Deregister the eSCO event callback */
+ return (BTM_SUCCESS);
+ }
+
+ tempstate = p->state;
+ p->state = SCO_ST_DISCONNECTING;
+
+ if (!btsnd_hcic_disconnect (p->hci_handle, HCI_ERR_PEER_USER)) {
+ p->state = tempstate;
+ return (BTM_NO_RESOURCES);
+ }
+
+ return (BTM_CMD_STARTED);
+#else
+ return (BTM_NO_RESOURCES);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_remove_sco_links
+**
+** Description This function is called to remove all sco links for an ACL link.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_remove_sco_links (BD_ADDR bda)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+ UINT16 xx;
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if (p->rem_bd_known && (!memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN))) {
+ BTM_RemoveSco(xx);
+ }
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_sco_removed
+**
+** Description This function is called by BTIF when an SCO connection
+** is removed.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_removed (UINT16 hci_handle, UINT8 reason)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+ UINT16 xx;
+#endif
+
+ btm_cb.sco_cb.sco_disc_reason = reason;
+
+#if (BTM_MAX_SCO_LINKS>0)
+ p = &btm_cb.sco_cb.sco_db[0];
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if ((p->state != SCO_ST_UNUSED) && (p->state != SCO_ST_LISTENING) && (p->hci_handle == hci_handle)) {
+ btm_sco_flush_sco_data(xx);
+
+ p->state = SCO_ST_UNUSED;
+#if BTM_SCO_HCI_INCLUDED == TRUE
+ btm_cb.sco_cb.xmit_window_size += p->sent_not_acked;
+ /* avoid overflow */
+ if (btm_cb.sco_cb.xmit_window_size > btm_cb.sco_cb.num_lm_sco_bufs) {
+ btm_cb.sco_cb.xmit_window_size = btm_cb.sco_cb.num_lm_sco_bufs;
+ }
+ p->sent_not_acked = 0;
+#endif
+ p->hci_handle = BTM_INVALID_HCI_HANDLE;
+ p->rem_bd_known = FALSE;
+ p->esco.p_esco_cback = NULL; /* Deregister eSCO callback */
+ (*p->p_disc_cb)(xx);
+
+ return;
+ }
+ }
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function btm_sco_acl_removed
+**
+** Description This function is called when an ACL connection is
+** removed. If the BD address is NULL, it is assumed that
+** the local device is down, and all SCO links are removed.
+** If a specific BD address is passed, only SCO connections
+** to that BD address are removed.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sco_acl_removed (BD_ADDR bda)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+ UINT16 xx;
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if (p->state != SCO_ST_UNUSED) {
+ if ((!bda) || (!memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN) && p->rem_bd_known)) {
+ btm_sco_flush_sco_data(xx);
+
+ p->state = SCO_ST_UNUSED;
+ p->esco.p_esco_cback = NULL; /* Deregister eSCO callback */
+ (*p->p_disc_cb)(xx);
+ }
+ }
+ }
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetScoPacketTypes
+**
+** Description This function is called to set the packet types used for
+** a specific SCO connection,
+**
+** Parameters pkt_types - One or more of the following
+** BTM_SCO_PKT_TYPES_MASK_HV1
+** BTM_SCO_PKT_TYPES_MASK_HV2
+** BTM_SCO_PKT_TYPES_MASK_HV3
+** BTM_SCO_PKT_TYPES_MASK_EV3
+** BTM_SCO_PKT_TYPES_MASK_EV4
+** BTM_SCO_PKT_TYPES_MASK_EV5
+** BTM_SCO_PKT_TYPES_MASK_NO_2_EV3
+** BTM_SCO_PKT_TYPES_MASK_NO_3_EV3
+** BTM_SCO_PKT_TYPES_MASK_NO_2_EV5
+** BTM_SCO_PKT_TYPES_MASK_NO_3_EV5
+**
+** BTM_SCO_LINK_ALL_MASK - enables all supported types
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetScoPacketTypes (UINT16 sco_inx, UINT16 pkt_types)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tBTM_CHG_ESCO_PARAMS parms;
+ tSCO_CONN *p;
+
+ /* Validity check */
+ if (sco_inx >= BTM_MAX_SCO_LINKS) {
+ return (BTM_UNKNOWN_ADDR);
+ }
+
+ p = &btm_cb.sco_cb.sco_db[sco_inx];
+ parms.packet_types = pkt_types;
+
+ /* Keep the other parameters the same for SCO */
+ parms.max_latency = p->esco.setup.max_latency;
+ parms.retrans_effort = p->esco.setup.retrans_effort;
+
+ return (BTM_ChangeEScoLinkParms(sco_inx, &parms));
+#else
+ return (BTM_UNKNOWN_ADDR);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadScoPacketTypes
+**
+** Description This function is read the packet types used for a specific
+** SCO connection.
+**
+** Returns Packet types supported for the connection
+** One or more of the following (bitmask):
+** BTM_SCO_PKT_TYPES_MASK_HV1
+** BTM_SCO_PKT_TYPES_MASK_HV2
+** BTM_SCO_PKT_TYPES_MASK_HV3
+** BTM_SCO_PKT_TYPES_MASK_EV3
+** BTM_SCO_PKT_TYPES_MASK_EV4
+** BTM_SCO_PKT_TYPES_MASK_EV5
+** BTM_SCO_PKT_TYPES_MASK_NO_2_EV3
+** BTM_SCO_PKT_TYPES_MASK_NO_3_EV3
+** BTM_SCO_PKT_TYPES_MASK_NO_2_EV5
+** BTM_SCO_PKT_TYPES_MASK_NO_3_EV5
+**
+*******************************************************************************/
+UINT16 BTM_ReadScoPacketTypes (UINT16 sco_inx)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[sco_inx];
+
+ /* Validity check */
+ if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->state == SCO_ST_CONNECTED)) {
+ return (p->esco.setup.packet_types);
+ } else {
+ return (0);
+ }
+#else
+ return (0);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadScoDiscReason
+**
+** Description This function is returns the reason why an (e)SCO connection
+** has been removed. It contains the value until read, or until
+** another (e)SCO connection has disconnected.
+**
+** Returns HCI reason or BTM_INVALID_SCO_DISC_REASON if not set.
+**
+*******************************************************************************/
+UINT16 BTM_ReadScoDiscReason (void)
+{
+ UINT16 res = btm_cb.sco_cb.sco_disc_reason;
+ btm_cb.sco_cb.sco_disc_reason = BTM_INVALID_SCO_DISC_REASON;
+ return (res);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadDeviceScoPacketTypes
+**
+** Description This function is read the SCO packet types that
+** the device supports.
+**
+** Returns Packet types supported by the device.
+** One or more of the following (bitmask):
+** BTM_SCO_PKT_TYPES_MASK_HV1
+** BTM_SCO_PKT_TYPES_MASK_HV2
+** BTM_SCO_PKT_TYPES_MASK_HV3
+** BTM_SCO_PKT_TYPES_MASK_EV3
+** BTM_SCO_PKT_TYPES_MASK_EV4
+** BTM_SCO_PKT_TYPES_MASK_EV5
+** BTM_SCO_PKT_TYPES_MASK_NO_2_EV3
+** BTM_SCO_PKT_TYPES_MASK_NO_3_EV3
+** BTM_SCO_PKT_TYPES_MASK_NO_2_EV5
+** BTM_SCO_PKT_TYPES_MASK_NO_3_EV5
+**
+*******************************************************************************/
+UINT16 BTM_ReadDeviceScoPacketTypes (void)
+{
+ return (btm_cb.btm_sco_pkt_types_supported);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadScoHandle
+**
+** Description This function is used to read the HCI handle used for a specific
+** SCO connection,
+**
+** Returns handle for the connection, or 0xFFFF if invalid SCO index.
+**
+*******************************************************************************/
+UINT16 BTM_ReadScoHandle (UINT16 sco_inx)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[sco_inx];
+
+ /* Validity check */
+ if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->state == SCO_ST_CONNECTED)) {
+ return (p->hci_handle);
+ } else {
+ return (BTM_INVALID_HCI_HANDLE);
+ }
+#else
+ return (BTM_INVALID_HCI_HANDLE);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadScoBdAddr
+**
+** Description This function is read the remote BD Address for a specific
+** SCO connection,
+**
+** Returns pointer to BD address or NULL if not known
+**
+*******************************************************************************/
+UINT8 *BTM_ReadScoBdAddr (UINT16 sco_inx)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[sco_inx];
+
+ /* Validity check */
+ if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->rem_bd_known)) {
+ return (p->esco.data.bd_addr);
+ } else {
+ return (NULL);
+ }
+#else
+ return (NULL);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetEScoMode
+**
+** Description This function sets up the negotiated parameters for SCO or
+** eSCO, and sets as the default mode used for outgoing calls to
+** BTM_CreateSco. It does not change any currently active (e)SCO links.
+** Note: Incoming (e)SCO connections will always use packet types
+** supported by the controller. If eSCO is not desired the
+** feature should be disabled in the controller's feature mask.
+**
+** Returns BTM_SUCCESS if the successful.
+** BTM_BUSY if there are one or more active (e)SCO links.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetEScoMode (tBTM_SCO_TYPE sco_mode, tBTM_ESCO_PARAMS *p_parms)
+{
+ tSCO_CB *p_esco = &btm_cb.sco_cb;
+ tBTM_ESCO_PARAMS *p_def = &p_esco->def_esco_parms;
+
+ if (p_esco->esco_supported) {
+ if (p_parms) {
+ if (sco_mode == BTM_LINK_TYPE_ESCO) {
+ *p_def = *p_parms; /* Save as the default parameters */
+ } else { /* Load only the SCO packet types */
+ p_def->packet_types = p_parms->packet_types;
+ p_def->tx_bw = BTM_64KBITS_RATE;
+ p_def->rx_bw = BTM_64KBITS_RATE;
+ p_def->max_latency = 0x000a;
+ p_def->voice_contfmt = 0x0060;
+ p_def->retrans_effort = 0;
+
+ /* OR in any exception packet types */
+ p_def->packet_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
+ }
+ }
+ p_esco->desired_sco_mode = sco_mode;
+ BTM_TRACE_API("BTM_SetEScoMode -> mode %d", sco_mode);
+ } else {
+ p_esco->desired_sco_mode = BTM_LINK_TYPE_SCO;
+ p_def->packet_types &= BTM_SCO_LINK_ONLY_MASK;
+ p_def->retrans_effort = 0;
+ BTM_TRACE_API("BTM_SetEScoMode -> mode SCO (eSCO not supported)");
+ }
+
+ BTM_TRACE_DEBUG(" txbw 0x%08x, rxbw 0x%08x, max_lat 0x%04x, voice 0x%04x, pkt 0x%04x, rtx effort 0x%02x",
+ p_def->tx_bw, p_def->rx_bw, p_def->max_latency,
+ p_def->voice_contfmt, p_def->packet_types,
+ p_def->retrans_effort);
+
+ return (BTM_SUCCESS);
+}
+
+
+
+/*******************************************************************************
+**
+** Function BTM_RegForEScoEvts
+**
+** Description This function registers a SCO event callback with the
+** specified instance. It should be used to received
+** connection indication events and change of link parameter
+** events.
+**
+** Returns BTM_SUCCESS if the successful.
+** BTM_ILLEGAL_VALUE if there is an illegal sco_inx
+** BTM_MODE_UNSUPPORTED if controller version is not BT1.2 or
+** later or does not support eSCO.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_RegForEScoEvts (UINT16 sco_inx, tBTM_ESCO_CBACK *p_esco_cback)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ if (!btm_cb.sco_cb.esco_supported) {
+ btm_cb.sco_cb.sco_db[sco_inx].esco.p_esco_cback = NULL;
+ return (BTM_MODE_UNSUPPORTED);
+ }
+
+ if (sco_inx < BTM_MAX_SCO_LINKS &&
+ btm_cb.sco_cb.sco_db[sco_inx].state != SCO_ST_UNUSED) {
+ btm_cb.sco_cb.sco_db[sco_inx].esco.p_esco_cback = p_esco_cback;
+ return (BTM_SUCCESS);
+ }
+ return (BTM_ILLEGAL_VALUE);
+#else
+ return (BTM_MODE_UNSUPPORTED);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadEScoLinkParms
+**
+** Description This function returns the current eSCO link parameters for
+** the specified handle. This can be called anytime a connection
+** is active, but is typically called after receiving the SCO
+** opened callback.
+**
+** Note: If called over a 1.1 controller, only the packet types
+** field has meaning.
+**
+** Returns BTM_SUCCESS if returned data is valid connection.
+** BTM_WRONG_MODE if no connection with a peer device or bad sco_inx.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadEScoLinkParms (UINT16 sco_inx, tBTM_ESCO_DATA *p_parms)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ UINT8 index;
+
+ BTM_TRACE_API("BTM_ReadEScoLinkParms -> sco_inx 0x%04x", sco_inx);
+
+ if (sco_inx < BTM_MAX_SCO_LINKS &&
+ btm_cb.sco_cb.sco_db[sco_inx].state >= SCO_ST_CONNECTED) {
+ *p_parms = btm_cb.sco_cb.sco_db[sco_inx].esco.data;
+ return (BTM_SUCCESS);
+ }
+
+ if (sco_inx == BTM_FIRST_ACTIVE_SCO_INDEX) {
+ for (index = 0; index < BTM_MAX_SCO_LINKS; index++) {
+ if (btm_cb.sco_cb.sco_db[index].state >= SCO_ST_CONNECTED) {
+ BTM_TRACE_API("BTM_ReadEScoLinkParms the first active SCO index is %d", index);
+ *p_parms = btm_cb.sco_cb.sco_db[index].esco.data;
+ return (BTM_SUCCESS);
+ }
+ }
+ }
+
+#endif
+
+ BTM_TRACE_API("BTM_ReadEScoLinkParms cannot find the SCO index!");
+ memset(p_parms, 0, sizeof(tBTM_ESCO_DATA));
+ return (BTM_WRONG_MODE);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ChangeEScoLinkParms
+**
+** Description This function requests renegotiation of the parameters on
+** the current eSCO Link. If any of the changes are accepted
+** by the controllers, the BTM_ESCO_CHG_EVT event is sent in
+** the tBTM_ESCO_CBACK function with the current settings of
+** the link. The callback is registered through the call to
+** BTM_SetEScoMode.
+**
+** Note: If called over a SCO link (including 1.1 controller),
+** a change packet type request is sent out instead.
+**
+** Returns BTM_CMD_STARTED if command is successfully initiated.
+** BTM_NO_RESOURCES - not enough resources to initiate command.
+** BTM_WRONG_MODE if no connection with a peer device or bad sco_inx.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ChangeEScoLinkParms (UINT16 sco_inx, tBTM_CHG_ESCO_PARAMS *p_parms)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tBTM_ESCO_PARAMS *p_setup;
+ tSCO_CONN *p_sco;
+ UINT16 temp_pkt_types;
+
+ /* Make sure sco handle is valid and on an active link */
+ if (sco_inx >= BTM_MAX_SCO_LINKS ||
+ btm_cb.sco_cb.sco_db[sco_inx].state != SCO_ST_CONNECTED) {
+ return (BTM_WRONG_MODE);
+ }
+
+ p_sco = &btm_cb.sco_cb.sco_db[sco_inx];
+ p_setup = &p_sco->esco.setup;
+
+ /* If SCO connection OR eSCO not supported just send change packet types */
+ if (p_sco->esco.data.link_type == BTM_LINK_TYPE_SCO ||
+ !btm_cb.sco_cb.esco_supported) {
+ p_setup->packet_types = p_parms->packet_types &
+ (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_LINK_ONLY_MASK);
+
+
+ BTM_TRACE_API("BTM_ChangeEScoLinkParms -> SCO Link for handle 0x%04x, pkt 0x%04x",
+ p_sco->hci_handle, p_setup->packet_types);
+
+ if (!btsnd_hcic_change_conn_type (p_sco->hci_handle,
+ BTM_ESCO_2_SCO(p_setup->packet_types))) {
+ return (BTM_NO_RESOURCES);
+ }
+ } else {
+ temp_pkt_types = (p_parms->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK &
+ btm_cb.btm_sco_pkt_types_supported);
+
+ /* OR in any exception packet types */
+ temp_pkt_types |= ((p_parms->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
+ (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
+
+ BTM_TRACE_API("BTM_ChangeEScoLinkParms -> eSCO Link for handle 0x%04x", p_sco->hci_handle);
+ BTM_TRACE_API(" txbw 0x%x, rxbw 0x%x, lat 0x%x, voice 0x%x, retrans 0x%02x, pkt 0x%04x",
+ p_setup->tx_bw, p_setup->rx_bw, p_parms->max_latency,
+ p_setup->voice_contfmt, p_parms->retrans_effort, temp_pkt_types);
+
+ /* When changing an existing link, only change latency, retrans, and pkts */
+ if (!btsnd_hcic_setup_esco_conn(p_sco->hci_handle, p_setup->tx_bw,
+ p_setup->rx_bw, p_parms->max_latency,
+ p_setup->voice_contfmt,
+ p_parms->retrans_effort,
+ temp_pkt_types)) {
+ return (BTM_NO_RESOURCES);
+ } else {
+ p_parms->packet_types = temp_pkt_types;
+ }
+ }
+
+ return (BTM_CMD_STARTED);
+#else
+ return (BTM_WRONG_MODE);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_EScoConnRsp
+**
+** Description This function is called upon receipt of an (e)SCO connection
+** request event (BTM_ESCO_CONN_REQ_EVT) to accept or reject
+** the request. Parameters used to negotiate eSCO links.
+** If p_parms is NULL, then values set through BTM_SetEScoMode
+** are used.
+** If the link type of the incoming request is SCO, then only
+** the tx_bw, max_latency, content format, and packet_types are
+** valid. The hci_status parameter should be
+** ([0x0] to accept, [0x0d..0x0f] to reject)
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_EScoConnRsp (UINT16 sco_inx, UINT8 hci_status, tBTM_ESCO_PARAMS *p_parms)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ if (sco_inx < BTM_MAX_SCO_LINKS &&
+ btm_cb.sco_cb.sco_db[sco_inx].state == SCO_ST_W4_CONN_RSP) {
+ btm_esco_conn_rsp(sco_inx, hci_status,
+ btm_cb.sco_cb.sco_db[sco_inx].esco.data.bd_addr,
+ p_parms);
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_read_def_esco_mode
+**
+** Description This function copies the current default esco settings into
+** the return buffer.
+**
+** Returns tBTM_SCO_TYPE
+**
+*******************************************************************************/
+tBTM_SCO_TYPE btm_read_def_esco_mode (tBTM_ESCO_PARAMS *p_parms)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ *p_parms = btm_cb.sco_cb.def_esco_parms;
+ return btm_cb.sco_cb.desired_sco_mode;
+#else
+ return BTM_LINK_TYPE_SCO;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_esco_proc_conn_chg
+**
+** Description This function is called by BTIF when an SCO connection
+** is changed.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_esco_proc_conn_chg (UINT8 status, UINT16 handle, UINT8 tx_interval,
+ UINT8 retrans_window, UINT16 rx_pkt_len,
+ UINT16 tx_pkt_len)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+ tBTM_CHG_ESCO_EVT_DATA data;
+ UINT16 xx;
+
+ BTM_TRACE_EVENT("btm_esco_proc_conn_chg -> handle 0x%04x, status 0x%02x",
+ handle, status);
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if (p->state == SCO_ST_CONNECTED && handle == p->hci_handle) {
+ /* If upper layer wants notification */
+ if (p->esco.p_esco_cback) {
+ memcpy(data.bd_addr, p->esco.data.bd_addr, BD_ADDR_LEN);
+ data.hci_status = status;
+ data.sco_inx = xx;
+ data.rx_pkt_len = p->esco.data.rx_pkt_len = rx_pkt_len;
+ data.tx_pkt_len = p->esco.data.tx_pkt_len = tx_pkt_len;
+ data.tx_interval = p->esco.data.tx_interval = tx_interval;
+ data.retrans_window = p->esco.data.retrans_window = retrans_window;
+
+ (*p->esco.p_esco_cback)(BTM_ESCO_CHG_EVT,
+ (tBTM_ESCO_EVT_DATA *)&data);
+ }
+ return;
+ }
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_is_sco_active
+**
+** Description This function is called to see if a SCO handle is already in
+** use.
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btm_is_sco_active (UINT16 handle)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ UINT16 xx;
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if (handle == p->hci_handle && p->state == SCO_ST_CONNECTED) {
+ return (TRUE);
+ }
+ }
+#endif
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetNumScoLinks
+**
+** Description This function returns the number of active sco links.
+**
+** Returns UINT8
+**
+*******************************************************************************/
+UINT8 BTM_GetNumScoLinks (void)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+ UINT16 xx;
+ UINT8 num_scos = 0;
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ switch (p->state) {
+ case SCO_ST_W4_CONN_RSP:
+ case SCO_ST_CONNECTING:
+ case SCO_ST_CONNECTED:
+ case SCO_ST_DISCONNECTING:
+ case SCO_ST_PEND_UNPARK:
+ num_scos++;
+ }
+ }
+ return (num_scos);
+#else
+ return (0);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function btm_is_sco_active_by_bdaddr
+**
+** Description This function is called to see if a SCO active to a bd address.
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btm_is_sco_active_by_bdaddr (BD_ADDR remote_bda)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+ UINT8 xx;
+ tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+
+ /* If any SCO is being established to the remote BD address, refuse this */
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if ((!memcmp (p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN)) && (p->state == SCO_ST_CONNECTED)) {
+ return (TRUE);
+ }
+ }
+#endif
+ return (FALSE);
+}
+#else /* SCO_EXCLUDED == TRUE (Link in stubs) */
+
+tBTM_STATUS BTM_CreateSco (BD_ADDR remote_bda, BOOLEAN is_orig,
+ UINT16 pkt_types, UINT16 *p_sco_inx,
+ tBTM_SCO_CB *p_conn_cb,
+ tBTM_SCO_CB *p_disc_cb)
+{
+ return (BTM_NO_RESOURCES);
+}
+tBTM_STATUS BTM_RemoveSco (UINT16 sco_inx)
+{
+ return (BTM_NO_RESOURCES);
+}
+tBTM_STATUS BTM_SetScoPacketTypes (UINT16 sco_inx, UINT16 pkt_types)
+{
+ return (BTM_NO_RESOURCES);
+}
+UINT16 BTM_ReadScoPacketTypes (UINT16 sco_inx)
+{
+ return (0);
+}
+UINT16 BTM_ReadDeviceScoPacketTypes (void)
+{
+ return (0);
+}
+UINT16 BTM_ReadScoHandle (UINT16 sco_inx)
+{
+ return (BTM_INVALID_HCI_HANDLE);
+}
+UINT8 *BTM_ReadScoBdAddr(UINT16 sco_inx)
+{
+ return ((UINT8 *) NULL);
+}
+UINT16 BTM_ReadScoDiscReason (void)
+{
+ return (BTM_INVALID_SCO_DISC_REASON);
+}
+tBTM_STATUS BTM_SetEScoMode (tBTM_SCO_TYPE sco_mode, tBTM_ESCO_PARAMS *p_parms)
+{
+ return (BTM_MODE_UNSUPPORTED);
+}
+tBTM_STATUS BTM_RegForEScoEvts (UINT16 sco_inx, tBTM_ESCO_CBACK *p_esco_cback)
+{
+ return (BTM_ILLEGAL_VALUE);
+}
+tBTM_STATUS BTM_ReadEScoLinkParms (UINT16 sco_inx, tBTM_ESCO_DATA *p_parms)
+{
+ return (BTM_MODE_UNSUPPORTED);
+}
+tBTM_STATUS BTM_ChangeEScoLinkParms (UINT16 sco_inx, tBTM_CHG_ESCO_PARAMS *p_parms)
+{
+ return (BTM_MODE_UNSUPPORTED);
+}
+void BTM_EScoConnRsp (UINT16 sco_inx, UINT8 hci_status, tBTM_ESCO_PARAMS *p_parms) {}
+UINT8 BTM_GetNumScoLinks (void)
+{
+ return (0);
+}
+
+#endif /* If SCO is being used */
diff --git a/lib/bt/host/bluedroid/stack/btm/btm_sec.c b/lib/bt/host/bluedroid/stack/btm/btm_sec.c
new file mode 100644
index 00000000..7d06a45e
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/btm_sec.c
@@ -0,0 +1,6382 @@
+/******************************************************************************
+ *
+ * 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 functions for the Bluetooth Security Manager
+ *
+ ******************************************************************************/
+
+//#define LOG_TAG "bt_btm_sec"
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "stack/bt_types.h"
+#include "device/controller.h"
+#include "stack/hcimsgs.h"
+#include "stack/btu.h"
+#include "btm_int.h"
+#include "l2c_int.h"
+#include "osi/fixed_queue.h"
+#include "osi/alarm.h"
+#include "stack/btm_ble_api.h"
+
+#if (BT_USE_TRACES == TRUE && BT_TRACE_VERBOSE == FALSE)
+/* needed for sprintf() */
+#include <stdio.h>
+#endif
+
+#if BLE_INCLUDED == TRUE
+#include "gatt_int.h"
+#endif
+
+#define BTM_SEC_MAX_COLLISION_DELAY (5000)
+
+#ifdef APPL_AUTH_WRITE_EXCEPTION
+BOOLEAN (APPL_AUTH_WRITE_EXCEPTION)(BD_ADDR bd_addr);
+#endif
+
+
+/********************************************************************************
+** L O C A L F U N C T I O N P R O T O T Y P E S *
+*********************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static tBTM_SEC_SERV_REC *btm_sec_find_next_serv (tBTM_SEC_SERV_REC *p_cur);
+static tBTM_SEC_SERV_REC *btm_sec_find_mx_serv (UINT8 is_originator, UINT16 psm,
+ UINT32 mx_proto_id,
+ UINT32 mx_chan_id);
+static tBTM_STATUS btm_sec_execute_procedure (tBTM_SEC_DEV_REC *p_dev_rec);
+static BOOLEAN btm_sec_start_get_name (tBTM_SEC_DEV_REC *p_dev_rec);
+static BOOLEAN btm_sec_start_authentication (tBTM_SEC_DEV_REC *p_dev_rec);
+static BOOLEAN btm_sec_start_encryption (tBTM_SEC_DEV_REC *p_dev_rec);
+static void btm_sec_collision_timeout (TIMER_LIST_ENT *p_tle);
+static void btm_restore_mode(void);
+static void btm_sec_pairing_timeout (TIMER_LIST_ENT *p_tle);
+static tBTM_STATUS btm_sec_dd_create_conn (tBTM_SEC_DEV_REC *p_dev_rec);
+static void btm_sec_change_pairing_state (tBTM_PAIRING_STATE new_state);
+#endif ///SMP_INCLUDED == TRUE
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+static char *btm_pair_state_descr (tBTM_PAIRING_STATE state);
+#endif
+#if (SMP_INCLUDED == TRUE)
+static void btm_sec_check_pending_reqs(void);
+static BOOLEAN btm_sec_queue_mx_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_orig,
+ UINT32 mx_proto_id, UINT32 mx_chan_id,
+ tBTM_SEC_CALLBACK *p_callback, void *p_ref_data);
+static void btm_sec_bond_cancel_complete (void);
+static void btm_send_link_key_notif (tBTM_SEC_DEV_REC *p_dev_rec);
+static BOOLEAN btm_sec_check_prefetch_pin (tBTM_SEC_DEV_REC *p_dev_rec);
+static UINT8 btm_sec_start_authorization (tBTM_SEC_DEV_REC *p_dev_rec);
+#endif ///SMP_INCLUDED == TRUE
+BOOLEAN btm_sec_are_all_trusted(UINT32 p_mask[]);
+#if (SMP_INCLUDED == TRUE)
+static tBTM_STATUS btm_sec_send_hci_disconnect (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 reason, UINT16 conn_handle);
+#endif ///SMP_INCLUDED == TRUE
+UINT8 btm_sec_start_role_switch (tBTM_SEC_DEV_REC *p_dev_rec);
+tBTM_SEC_DEV_REC *btm_sec_find_dev_by_sec_state (UINT8 state);
+
+static BOOLEAN btm_sec_set_security_level ( CONNECTION_TYPE conn_type, const char *p_name, UINT8 service_id,
+ UINT16 sec_level, UINT16 psm, UINT32 mx_proto_id,
+ UINT32 mx_chan_id);
+#if (SMP_INCLUDED == TRUE)
+static BOOLEAN btm_dev_authenticated(tBTM_SEC_DEV_REC *p_dev_rec);
+static BOOLEAN btm_dev_encrypted(tBTM_SEC_DEV_REC *p_dev_rec);
+static BOOLEAN btm_dev_authorized(tBTM_SEC_DEV_REC *p_dev_rec);
+static BOOLEAN btm_serv_trusted(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_SEC_SERV_REC *p_serv_rec);
+static BOOLEAN btm_sec_is_serv_level0 (UINT16 psm);
+static UINT16 btm_sec_set_serv_level4_flags (UINT16 cur_security, BOOLEAN is_originator);
+
+static BOOLEAN btm_sec_queue_encrypt_request (BD_ADDR bd_addr, tBT_TRANSPORT transport,
+ tBTM_SEC_CALLBACK *p_callback, void *p_ref_data);
+static void btm_sec_check_pending_enc_req (tBTM_SEC_DEV_REC *p_dev_rec, tBT_TRANSPORT transport,
+ UINT8 encr_enable);
+static BOOLEAN btm_sec_use_smp_br_chnl(tBTM_SEC_DEV_REC *p_dev_rec);
+static BOOLEAN btm_sec_is_master(tBTM_SEC_DEV_REC *p_dev_rec);
+#endif ///SMP_INCLUDED == TRUE
+
+/* TRUE - authenticated link key is possible */
+static const BOOLEAN btm_sec_io_map [BTM_IO_CAP_MAX][BTM_IO_CAP_MAX] = {
+ /* OUT, IO, IN, NONE */
+ /* OUT */ {FALSE, FALSE, TRUE, FALSE},
+ /* IO */ {FALSE, TRUE, TRUE, FALSE},
+ /* IN */ {TRUE, TRUE, TRUE, FALSE},
+ /* NONE */ {FALSE, FALSE, FALSE, FALSE}
+};
+/* BTM_IO_CAP_OUT 0 DisplayOnly */
+/* BTM_IO_CAP_IO 1 DisplayYesNo */
+/* BTM_IO_CAP_IN 2 KeyboardOnly */
+/* BTM_IO_CAP_NONE 3 NoInputNoOutput */
+
+/*******************************************************************************
+**
+** Function btm_dev_authenticated
+**
+** Description check device is authenticated
+**
+** Returns BOOLEAN TRUE or FALSE
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static BOOLEAN btm_dev_authenticated (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ if (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED) {
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function btm_dev_encrypted
+**
+** Description check device is encrypted
+**
+** Returns BOOLEAN TRUE or FALSE
+**
+*******************************************************************************/
+static BOOLEAN btm_dev_encrypted (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ if (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) {
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function btm_dev_authorized
+**
+** Description check device is authorized
+**
+** Returns BOOLEAN TRUE or FALSE
+**
+*******************************************************************************/
+static BOOLEAN btm_dev_authorized (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ if (p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED) {
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function btm_dev_16_digit_authenticated
+**
+** Description check device is authenticated by using 16 digit pin or MITM
+**
+** Returns BOOLEAN TRUE or FALSE
+**
+*******************************************************************************/
+static BOOLEAN btm_dev_16_digit_authenticated(tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ // BTM_SEC_16_DIGIT_PIN_AUTHED is set if MITM or 16 digit pin is used
+ if (p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED) {
+ return (TRUE);
+ }
+ return (FALSE);
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_serv_trusted
+**
+** Description check service is trusted
+**
+** Returns BOOLEAN TRUE or FALSE
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static BOOLEAN btm_serv_trusted(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_SEC_SERV_REC *p_serv_rec)
+{
+ if (BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask, p_serv_rec->service_id)) {
+ return (TRUE);
+ }
+ return (FALSE);
+}
+#endif ///SMP_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function BTM_SecRegister
+**
+** Description Application manager calls this function to register for
+** security services. There can be one and only one application
+** saving link keys. BTM allows only first registration.
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_SecRegister(tBTM_APPL_INFO *p_cb_info)
+{
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ BT_OCTET16 temp_value = {0};
+#endif
+
+ BTM_TRACE_EVENT("%s application registered\n", __func__);
+
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ BTM_TRACE_DEBUG("%s p_cb_info->p_le_callback == 0x%p\n", __func__, p_cb_info->p_le_callback);
+ if (p_cb_info->p_le_callback) {
+ BTM_TRACE_EVENT("%s SMP_Register( btm_proc_smp_cback )\n", __func__);
+ SMP_Register(btm_proc_smp_cback);
+ /* if no IR is loaded, need to regenerate all the keys */
+ if (memcmp(btm_cb.devcb.id_keys.ir, &temp_value, sizeof(BT_OCTET16)) == 0) {
+ btm_ble_reset_id();
+ }
+#if (CONTROLLER_RPA_LIST_ENABLE == TRUE)
+ else {
+ btm_ble_add_default_entry_to_resolving_list();
+ }
+#endif
+ } else {
+ BTM_TRACE_WARNING("%s p_cb_info->p_le_callback == NULL\n", __func__);
+ }
+#endif
+
+ btm_cb.api = *p_cb_info;
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ BTM_TRACE_DEBUG("%s btm_cb.api.p_le_callback = 0x%p\n", __func__, btm_cb.api.p_le_callback);
+#endif
+ BTM_TRACE_EVENT("%s application registered\n", __func__);
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SecRegisterLinkKeyNotificationCallback
+**
+** Description Application manager calls this function to register for
+** link key notification. When there is nobody registered
+** we should avoid changing link key
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_SecRegisterLinkKeyNotificationCallback (tBTM_LINK_KEY_CALLBACK *p_callback)
+{
+ btm_cb.api.p_link_key_callback = p_callback;
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function BTM_SecAddRmtNameNotifyCallback
+**
+** Description Any profile can register to be notified when name of the
+** remote device is resolved.
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE) || (CLASSIC_BT_INCLUDED == TRUE)
+BOOLEAN BTM_SecAddRmtNameNotifyCallback (tBTM_RMT_NAME_CALLBACK *p_callback)
+{
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++) {
+ if (btm_cb.p_rmt_name_callback[i] == NULL) {
+ btm_cb.p_rmt_name_callback[i] = p_callback;
+ return (TRUE);
+ }
+ }
+ return (FALSE);
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function BTM_SecDeleteRmtNameNotifyCallback
+**
+** Description Any profile can deregister notification when a new Link Key
+** is generated per connection.
+**
+** Returns TRUE if OK, else FALSE
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE) || (CLASSIC_BT_INCLUDED == TRUE)
+BOOLEAN BTM_SecDeleteRmtNameNotifyCallback (tBTM_RMT_NAME_CALLBACK *p_callback)
+{
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++) {
+ if (btm_cb.p_rmt_name_callback[i] == p_callback) {
+ btm_cb.p_rmt_name_callback[i] = NULL;
+ return (TRUE);
+ }
+ }
+ return (FALSE);
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function BTM_GetSecurityFlags
+**
+** Description Get security flags for the device
+**
+** Returns BOOLEAN TRUE or FALSE is device found
+**
+*******************************************************************************/
+BOOLEAN BTM_GetSecurityFlags (BD_ADDR bd_addr, UINT8 *p_sec_flags)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL) {
+ *p_sec_flags = (UINT8) p_dev_rec->sec_flags;
+ return (TRUE);
+ }
+ BTM_TRACE_ERROR ("BTM_GetSecurityFlags false");
+ return (FALSE);
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetSecurityFlagsByTransport
+**
+** Description Get security flags for the device on a particular transport
+**
+** Returns BOOLEAN TRUE or FALSE is device found
+**
+*******************************************************************************/
+BOOLEAN BTM_GetSecurityFlagsByTransport (BD_ADDR bd_addr, UINT8 *p_sec_flags,
+ tBT_TRANSPORT transport)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL) {
+ if (transport == BT_TRANSPORT_BR_EDR) {
+ *p_sec_flags = (UINT8) p_dev_rec->sec_flags;
+ } else {
+ *p_sec_flags = (UINT8) (p_dev_rec->sec_flags >> 8);
+ }
+
+ return (TRUE);
+ }
+ BTM_TRACE_ERROR ("BTM_GetSecurityFlags false\n");
+ return (FALSE);
+}
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function BTM_SetPinType
+**
+** Description Set PIN type for the device.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_SetPinType (UINT8 pin_type, PIN_CODE pin_code, UINT8 pin_code_len)
+{
+ BTM_TRACE_API ("BTM_SetPinType: pin type %d [variable-0, fixed-1], code %s, length %d\n",
+ pin_type, (char *) pin_code, pin_code_len);
+
+ /* If device is not up security mode will be set as a part of startup */
+ if ( (btm_cb.cfg.pin_type != pin_type)
+ && controller_get_interface()->get_is_ready() ) {
+ btsnd_hcic_write_pin_type (pin_type);
+ }
+
+ btm_cb.cfg.pin_type = pin_type;
+ btm_cb.cfg.pin_code_len = pin_code_len;
+ memcpy (btm_cb.cfg.pin_code, pin_code, pin_code_len);
+}
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function BTM_SetPairableMode
+**
+** Description Enable or disable pairing
+**
+** Parameters allow_pairing - (TRUE or FALSE) whether or not the device
+** allows pairing.
+** connect_only_paired - (TRUE or FALSE) whether or not to
+** only allow paired devices to connect.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_SetPairableMode (BOOLEAN allow_pairing, BOOLEAN connect_only_paired)
+{
+ BTM_TRACE_API ("BTM_SetPairableMode() allow_pairing: %u connect_only_paired: %u\n", allow_pairing, connect_only_paired);
+
+ btm_cb.pairing_disabled = !allow_pairing;
+ btm_cb.connect_only_paired = connect_only_paired;
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetSecureConnectionsOnly
+**
+** Description Enable or disable default treatment for Mode 4 Level 0 services
+**
+** Parameter secure_connections_only_mode - (TRUE or FALSE) whether or not the device
+** TRUE means that the device should treat Mode 4 Level 0 services as
+** services of other levels. (Secure_connections_only_mode)
+** FALSE means that the device should provide default treatment for
+** Mode 4 Level 0 services.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_SetSecureConnectionsOnly (BOOLEAN secure_connections_only_mode)
+{
+ BTM_TRACE_API("%s: Mode : %u\n", __FUNCTION__,
+ secure_connections_only_mode);
+
+ btm_cb.devcb.secure_connections_only = secure_connections_only_mode;
+ btm_cb.security_mode = BTM_SEC_MODE_SC;
+}
+#define BTM_NO_AVAIL_SEC_SERVICES ((UINT16) 0xffff)
+
+/*******************************************************************************
+**
+** Function BTM_SetSecurityLevel
+**
+** Description Register service security level with Security Manager
+**
+** Parameters: is_originator - TRUE if originating the connection, FALSE if not
+** p_name - Name of the service relevant only if
+** authorization will show this name to user. ignored
+** if BTM_SEC_SERVICE_NAME_LEN is 0.
+** service_id - service ID for the service passed to authorization callback
+** sec_level - bit mask of the security features
+** psm - L2CAP PSM
+** mx_proto_id - protocol ID of multiplexing proto below
+** mx_chan_id - channel ID of multiplexing proto below
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_SetSecurityLevel (BOOLEAN is_originator, const char *p_name, UINT8 service_id,
+ UINT16 sec_level, UINT16 psm, UINT32 mx_proto_id,
+ UINT32 mx_chan_id)
+{
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ CONNECTION_TYPE conn_type;
+
+ if (is_originator) {
+ conn_type = CONN_ORIENT_ORIG;
+ } else {
+ conn_type = CONN_ORIENT_TERM;
+ }
+
+ return (btm_sec_set_security_level (conn_type, p_name, service_id,
+ sec_level, psm, mx_proto_id, mx_chan_id));
+#else
+ return (btm_sec_set_security_level (is_originator, p_name, service_id,
+ sec_level, psm, mx_proto_id, mx_chan_id));
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_set_security_level
+**
+** Description Register service security level with Security Manager
+**
+** Parameters: conn_type - TRUE if originating the connection, FALSE if not
+** p_name - Name of the service relevant only if
+** authorization will show this name to user. ignored
+** if BTM_SEC_SERVICE_NAME_LEN is 0.
+** service_id - service ID for the service passed to authorization callback
+** sec_level - bit mask of the security features
+** psm - L2CAP PSM
+** mx_proto_id - protocol ID of multiplexing proto below
+** mx_chan_id - channel ID of multiplexing proto below
+**
+** Returns TRUE if registered OK, else FALSE
+**
+*******************************************************************************/
+static BOOLEAN btm_sec_set_security_level (CONNECTION_TYPE conn_type, const char *p_name, UINT8 service_id,
+ UINT16 sec_level, UINT16 psm, UINT32 mx_proto_id,
+ UINT32 mx_chan_id)
+{
+#if (SMP_INCLUDED == TRUE)
+ tBTM_SEC_SERV_REC *p_srec;
+ UINT16 index;
+ UINT16 first_unused_record = BTM_NO_AVAIL_SEC_SERVICES;
+ BOOLEAN record_allocated = FALSE;
+ BOOLEAN is_originator;
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ BOOLEAN is_ucd;
+
+ if (conn_type & CONNECTION_TYPE_ORIG_MASK) {
+ is_originator = TRUE;
+ } else {
+ is_originator = FALSE;
+ }
+
+ if (conn_type & CONNECTION_TYPE_CONNLESS_MASK ) {
+ is_ucd = TRUE;
+ } else {
+ is_ucd = FALSE;
+ }
+#else
+ is_originator = conn_type;
+#endif
+
+ BTM_TRACE_API("%s : sec: 0x%x\n", __func__, sec_level);
+
+ /* See if the record can be reused (same service name, psm, mx_proto_id,
+ service_id, and mx_chan_id), or obtain the next unused record */
+
+ p_srec = &btm_cb.sec_serv_rec[0];
+
+
+ for (index = 0; index < BTM_SEC_MAX_SERVICE_RECORDS; index++, p_srec++) {
+ /* Check if there is already a record for this service */
+ if (p_srec->security_flags & BTM_SEC_IN_USE) {
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ if (p_srec->psm == psm &&
+ p_srec->mx_proto_id == mx_proto_id &&
+ service_id == p_srec->service_id &&
+ (!strncmp (p_name, (char *) p_srec->orig_service_name,
+ BTM_SEC_SERVICE_NAME_LEN) ||
+ !strncmp (p_name, (char *) p_srec->term_service_name,
+ BTM_SEC_SERVICE_NAME_LEN)))
+#else
+ if (p_srec->psm == psm &&
+ p_srec->mx_proto_id == mx_proto_id &&
+ service_id == p_srec->service_id)
+#endif
+ {
+ record_allocated = TRUE;
+ break;
+ }
+ }
+ /* Mark the first available service record */
+ else if (!record_allocated) {
+ memset (p_srec, 0, sizeof(tBTM_SEC_SERV_REC));
+ record_allocated = TRUE;
+ first_unused_record = index;
+ }
+ }
+
+ if (!record_allocated) {
+ BTM_TRACE_WARNING("BTM_SEC_REG: Out of Service Records (%d)\n", BTM_SEC_MAX_SERVICE_RECORDS);
+ return (record_allocated);
+ }
+
+ /* Process the request if service record is valid */
+ /* If a duplicate service wasn't found, use the first available */
+ if (index >= BTM_SEC_MAX_SERVICE_RECORDS) {
+ index = first_unused_record;
+ p_srec = &btm_cb.sec_serv_rec[index];
+ }
+
+ p_srec->psm = psm;
+ p_srec->service_id = service_id;
+ p_srec->mx_proto_id = mx_proto_id;
+
+ if (is_originator) {
+ p_srec->orig_mx_chan_id = mx_chan_id;
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ BCM_STRNCPY_S ((char *)p_srec->orig_service_name, p_name, BTM_SEC_SERVICE_NAME_LEN);
+ p_srec->orig_service_name[BTM_SEC_SERVICE_NAME_LEN] = '\0';
+#endif
+ /* clear out the old setting, just in case it exists */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( is_ucd ) {
+ p_srec->ucd_security_flags &=
+ ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM |
+ BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
+ } else
+#endif
+ {
+ p_srec->security_flags &=
+ ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM |
+ BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
+ }
+
+ /* Parameter validation. Originator should not set requirements for incoming connections */
+ sec_level &= ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE
+ | BTM_SEC_IN_MITM | BTM_SEC_IN_MIN_16_DIGIT_PIN );
+
+ if (btm_cb.security_mode == BTM_SEC_MODE_SP ||
+ btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+ btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ if (sec_level & BTM_SEC_OUT_AUTHENTICATE) {
+ sec_level |= BTM_SEC_OUT_MITM;
+ }
+ }
+
+ /* Make sure the authenticate bit is set, when encrypt bit is set */
+ if (sec_level & BTM_SEC_OUT_ENCRYPT) {
+ sec_level |= BTM_SEC_OUT_AUTHENTICATE;
+ }
+
+ /* outgoing connections usually set the security level right before
+ * the connection is initiated.
+ * set it to be the outgoing service */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( is_ucd == FALSE )
+#endif
+ {
+ btm_cb.p_out_serv = p_srec;
+ }
+ } else {
+ p_srec->term_mx_chan_id = mx_chan_id;
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ BCM_STRNCPY_S ((char *)p_srec->term_service_name, p_name, BTM_SEC_SERVICE_NAME_LEN);
+ p_srec->term_service_name[BTM_SEC_SERVICE_NAME_LEN] = '\0';
+#endif
+ /* clear out the old setting, just in case it exists */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( is_ucd ) {
+ p_srec->ucd_security_flags &=
+ ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM |
+ BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE
+ | BTM_SEC_IN_MIN_16_DIGIT_PIN);
+ } else
+#endif
+ {
+ p_srec->security_flags &=
+ ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM |
+ BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE
+ | BTM_SEC_IN_MIN_16_DIGIT_PIN);
+ }
+
+ /* Parameter validation. Acceptor should not set requirements for outgoing connections */
+ sec_level &= ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM);
+
+ if (btm_cb.security_mode == BTM_SEC_MODE_SP ||
+ btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+ btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ if (sec_level & BTM_SEC_IN_AUTHENTICATE) {
+ sec_level |= BTM_SEC_IN_MITM;
+ }
+ }
+
+ /* Make sure the authenticate bit is set, when encrypt bit is set */
+ if (sec_level & BTM_SEC_IN_ENCRYPT) {
+ sec_level |= BTM_SEC_IN_AUTHENTICATE;
+ }
+ }
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( is_ucd ) {
+ p_srec->security_flags |= (UINT16)(BTM_SEC_IN_USE);
+ p_srec->ucd_security_flags |= (UINT16)(sec_level | BTM_SEC_IN_USE);
+ } else {
+ p_srec->security_flags |= (UINT16)(sec_level | BTM_SEC_IN_USE);
+ }
+
+ BTM_TRACE_API("BTM_SEC_REG[%d]: id %d, conn_type 0x%x, psm 0x%04x, proto_id %d, chan_id %d\n",
+ index, service_id, conn_type, psm, mx_proto_id, mx_chan_id);
+
+ BTM_TRACE_API(" : security_flags: 0x%04x, ucd_security_flags: 0x%04x\n",
+ p_srec->security_flags, p_srec->ucd_security_flags);
+
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ BTM_TRACE_API(" : service name [%s] (up to %d chars saved)\n",
+ p_name, BTM_SEC_SERVICE_NAME_LEN);
+#endif
+#else
+ p_srec->security_flags |= (UINT16)(sec_level | BTM_SEC_IN_USE);
+
+ BTM_TRACE_API("BTM_SEC_REG[%d]: id %d, is_orig %d, psm 0x%04x, proto_id %d, chan_id %d\n",
+ index, service_id, is_originator, psm, mx_proto_id, mx_chan_id);
+
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ BTM_TRACE_API(" : sec: 0x%x, service name [%s] (up to %d chars saved)\n",
+ p_srec->security_flags, p_name, BTM_SEC_SERVICE_NAME_LEN);
+#endif
+#endif
+
+
+ return (record_allocated);
+#else
+ return FALSE;
+#endif ///SMP_INCLUDED == TRUE
+}
+
+/*******************************************************************************
+**
+** Function BTM_SecClrService
+**
+** Description Removes specified service record(s) from the security database.
+** All service records with the specified name are removed.
+** Typically used only by devices with limited RAM so that it can
+** reuse an old security service record.
+**
+** Note: Unpredictable results may occur if a service is cleared
+** that is still in use by an application/profile.
+**
+** Parameters Service ID - Id of the service to remove. ('0' removes all service
+** records (except SDP).
+**
+** Returns Number of records that were freed.
+**
+*******************************************************************************/
+#if (SDP_INCLUDED == TRUE)
+UINT8 BTM_SecClrService (UINT8 service_id)
+{
+ tBTM_SEC_SERV_REC *p_srec = &btm_cb.sec_serv_rec[0];
+ UINT8 num_freed = 0;
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++) {
+ /* Delete services with specified name (if in use and not SDP) */
+ if ((p_srec->security_flags & BTM_SEC_IN_USE) && (p_srec->psm != BT_PSM_SDP) &&
+ (!service_id || (service_id == p_srec->service_id))) {
+ BTM_TRACE_API("BTM_SEC_CLR[%d]: id %d\n", i, service_id);
+ p_srec->security_flags = 0;
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ p_srec->ucd_security_flags = 0;
+#endif
+ num_freed++;
+ }
+ }
+
+ return (num_freed);
+}
+#endif ///SDP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_sec_clr_service_by_psm
+**
+** Description Removes specified service record from the security database.
+** All service records with the specified psm are removed.
+** Typically used by L2CAP to free up the service record used
+** by dynamic PSM clients when the channel is closed.
+** The given psm must be a virtual psm.
+**
+** Parameters Service ID - Id of the service to remove. ('0' removes all service
+** records (except SDP).
+**
+** Returns Number of records that were freed.
+**
+*******************************************************************************/
+#if (SDP_INCLUDED== TRUE)
+UINT8 btm_sec_clr_service_by_psm (UINT16 psm)
+{
+ tBTM_SEC_SERV_REC *p_srec = &btm_cb.sec_serv_rec[0];
+ UINT8 num_freed = 0;
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++) {
+ /* Delete services with specified name (if in use and not SDP) */
+ if ((p_srec->security_flags & BTM_SEC_IN_USE) && (p_srec->psm == psm) ) {
+ BTM_TRACE_API("BTM_SEC_CLR[%d]: id %d\n", i, p_srec->service_id);
+ p_srec->security_flags = 0;
+ num_freed++;
+ }
+ }
+ BTM_TRACE_API("btm_sec_clr_service_by_psm psm:0x%x num_freed:%d\n", psm, num_freed);
+
+ return (num_freed);
+}
+#endif ///SDP_INCLUDED== TRUE
+
+/*******************************************************************************
+**
+** Function btm_sec_clr_temp_auth_service
+**
+** Description Removes specified device record's temporary authorization
+** flag from the security database.
+**
+** Parameters Device address to be cleared
+**
+** Returns void.
+**
+*******************************************************************************/
+void btm_sec_clr_temp_auth_service (BD_ADDR bda)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ if ((p_dev_rec = btm_find_dev (bda)) == NULL) {
+ BTM_TRACE_WARNING ("btm_sec_clr_temp_auth_service() - no dev CB\n");
+ return;
+ }
+
+ /* Reset the temporary authorized flag so that next time (untrusted) service is accessed autorization will take place */
+ if (p_dev_rec->last_author_service_id != BTM_SEC_NO_LAST_SERVICE_ID && p_dev_rec->p_cur_service) {
+ BTM_TRACE_DEBUG ("btm_sec_clr_auth_service_by_psm [clearing device: %02x:%02x:%02x:%02x:%02x:%02x]\n",
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+
+ p_dev_rec->last_author_service_id = BTM_SEC_NO_LAST_SERVICE_ID;
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_PINCodeReply
+**
+** Description This function is called after Security Manager submitted
+** PIN code request to the UI.
+**
+** Parameters: bd_addr - Address of the device for which PIN was requested
+** res - result of the operation BTM_SUCCESS if success
+** pin_len - length in bytes of the PIN Code
+** p_pin - pointer to array with the PIN Code
+** trusted_mask - bitwise OR of trusted services (array of UINT32)
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+#if (CLASSIC_BT_INCLUDED == TRUE)
+void BTM_PINCodeReply (BD_ADDR bd_addr, UINT8 res, UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[])
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_API ("BTM_PINCodeReply(): PairState: %s PairFlags: 0x%02x PinLen:%d Result:%d\n",
+ btm_pair_state_descr(btm_cb.pairing_state), btm_cb.pairing_flags, pin_len, res);
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_PIN) {
+ BTM_TRACE_WARNING ("BTM_PINCodeReply() - Wrong State: %d\n", btm_cb.pairing_state);
+ return;
+ }
+
+ if (memcmp (bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) != 0) {
+ BTM_TRACE_ERROR ("BTM_PINCodeReply() - Wrong BD Addr\n");
+ return;
+ }
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL) {
+ BTM_TRACE_ERROR ("BTM_PINCodeReply() - no dev CB\n");
+ return;
+ }
+
+ if ( (pin_len > PIN_CODE_LEN) || (pin_len == 0) || (p_pin == NULL) ) {
+ res = BTM_ILLEGAL_VALUE;
+ }
+
+ if (res != BTM_SUCCESS) {
+ /* if peer started dd OR we started dd and pre-fetch pin was not used send negative reply */
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PEER_STARTED_DD) ||
+ ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) &&
+ (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE)) ) {
+ /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed event */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+
+ btsnd_hcic_pin_code_neg_reply (bd_addr);
+ } else {
+ p_dev_rec->security_required = BTM_SEC_NONE;
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ }
+ return;
+ }
+ if (trusted_mask) {
+ BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
+ }
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+ if (pin_len >= 16) {
+ p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+ }
+
+ if ( (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ && (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE)
+ && (btm_cb.security_mode_changed == FALSE) ) {
+ /* This is start of the dedicated bonding if local device is 2.0 */
+ btm_cb.pin_code_len = pin_len;
+ p_dev_rec->pin_code_length = pin_len;
+ memcpy (btm_cb.pin_code, p_pin, pin_len);
+
+ btm_cb.security_mode_changed = TRUE;
+#ifdef APPL_AUTH_WRITE_EXCEPTION
+ if (!(APPL_AUTH_WRITE_EXCEPTION)(p_dev_rec->bd_addr))
+#endif
+ {
+ btsnd_hcic_write_auth_enable (TRUE);
+ }
+
+ btm_cb.acl_disc_reason = 0xff ;
+
+ /* if we rejected incoming connection request, we have to wait HCI_Connection_Complete event */
+ /* before originating */
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) {
+ BTM_TRACE_WARNING ("BTM_PINCodeReply(): waiting HCI_Connection_Complete after rejected incoming connection\n");
+ /* we change state little bit early so btm_sec_connected() will originate connection */
+ /* when existing ACL link is down completely */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
+ }
+ /* if we already accepted incoming connection from pairing device */
+ else if (p_dev_rec->sm4 & BTM_SM4_CONN_PEND) {
+ BTM_TRACE_WARNING ("BTM_PINCodeReply(): link is connecting so wait pin code request from peer\n");
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
+ } else if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED) {
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_AUTHED;
+
+ if (btm_cb.api.p_auth_complete_callback) {
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, HCI_ERR_AUTH_FAILURE);
+ }
+ }
+ return;
+ }
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ btm_cb.acl_disc_reason = HCI_SUCCESS;
+
+#ifdef PORCHE_PAIRING_CONFLICT
+ BTM_TRACE_EVENT("BTM_PINCodeReply(): Saving pin_len: %d btm_cb.pin_code_len: %d\n", pin_len, btm_cb.pin_code_len);
+ /* if this was not pre-fetched, save the PIN */
+ if (btm_cb.pin_code_len == 0) {
+ memcpy (btm_cb.pin_code, p_pin, pin_len);
+ }
+ btm_cb.pin_code_len_saved = pin_len;
+#endif
+ btsnd_hcic_pin_code_req_reply (bd_addr, pin_len, p_pin);
+}
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+#endif ///SMP_INCLUDED == TRUE
+
+
+/*******************************************************************************
+**
+** Function btm_sec_bond_by_transport
+**
+** Description this is the bond function that will start either SSP or SMP.
+**
+** Parameters: bd_addr - Address of the device to bond
+** pin_len - length in bytes of the PIN Code
+** p_pin - pointer to array with the PIN Code
+** trusted_mask - bitwise OR of trusted services (array of UINT32)
+**
+** Note: After 2.1 parameters are not used and preserved here not to change API
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+tBTM_STATUS btm_sec_bond_by_transport (BD_ADDR bd_addr, tBT_TRANSPORT transport,
+ UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[])
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_STATUS status;
+#if (!CONFIG_BT_STACK_NO_LOG)
+ UINT8 *p_features;
+#endif
+ UINT8 ii;
+ tACL_CONN *p = btm_bda_to_acl(bd_addr, transport);
+ BTM_TRACE_API ("btm_sec_bond_by_transport BDA: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+ BTM_TRACE_DEBUG("btm_sec_bond_by_transport: Transport used %d\n" , transport);
+
+
+ /* Other security process is in progress */
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) {
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_ERROR ("BTM_SecBond: already busy in state: %s\n", btm_pair_state_descr(btm_cb.pairing_state));
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ return (BTM_WRONG_MODE);
+ }
+
+ if ((p_dev_rec = btm_find_or_alloc_dev (bd_addr)) == NULL) {
+ return (BTM_NO_RESOURCES);
+ }
+
+ BTM_TRACE_DEBUG ("before update sec_flags=0x%x\n", p_dev_rec->sec_flags);
+
+ /* Finished if connection is active and already paired */
+ if ( ((p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE) && transport == BT_TRANSPORT_BR_EDR
+ && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))
+#if (BLE_INCLUDED == TRUE)
+ || ((p_dev_rec->ble_hci_handle != BTM_SEC_INVALID_HANDLE) && transport == BT_TRANSPORT_LE
+ && (p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED))
+#endif
+
+ ) {
+ BTM_TRACE_WARNING("BTM_SecBond -> Already Paired\n");
+ return (BTM_SUCCESS);
+ }
+
+ /* Tell controller to get rid of the link key if it has one stored */
+ if ((BTM_DeleteStoredLinkKey (bd_addr, NULL)) != BTM_SUCCESS) {
+ return (BTM_NO_RESOURCES);
+ }
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ /* Save the PIN code if we got a valid one */
+ if (p_pin && (pin_len <= PIN_CODE_LEN) && (pin_len != 0)) {
+ btm_cb.pin_code_len = pin_len;
+ p_dev_rec->pin_code_length = pin_len;
+ memcpy (btm_cb.pin_code, p_pin, PIN_CODE_LEN);
+ }
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+
+ memcpy (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN);
+
+ btm_cb.pairing_flags = BTM_PAIR_FLAGS_WE_STARTED_DD;
+
+ p_dev_rec->security_required = BTM_SEC_OUT_AUTHENTICATE;
+ p_dev_rec->is_originator = TRUE;
+ if (trusted_mask) {
+ BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
+ }
+
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ if (transport == BT_TRANSPORT_LE) {
+ btm_ble_init_pseudo_addr (p_dev_rec, bd_addr);
+ p_dev_rec->sec_flags &= ~ BTM_SEC_LE_MASK;
+
+ if (SMP_Pair(bd_addr) == SMP_STARTED) {
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_LE_ACTIVE;
+ p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ return BTM_CMD_STARTED;
+ }
+
+ btm_cb.pairing_flags = 0;
+ return (BTM_NO_RESOURCES);
+ }
+#endif
+
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED
+ | BTM_SEC_ROLE_SWITCHED | BTM_SEC_LINK_KEY_AUTHED);
+
+
+ BTM_TRACE_DEBUG ("after update sec_flags=0x%x\n", p_dev_rec->sec_flags);
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ if (!controller_get_interface()->supports_simple_pairing()) {
+ /* The special case when we authenticate keyboard. Set pin type to fixed */
+ /* It would be probably better to do it from the application, but it is */
+ /* complicated */
+ if (((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) == BTM_COD_MAJOR_PERIPHERAL)
+ && (p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD)
+ && (btm_cb.cfg.pin_type != HCI_PIN_TYPE_FIXED)) {
+ btm_cb.pin_type_changed = TRUE;
+ btsnd_hcic_write_pin_type (HCI_PIN_TYPE_FIXED);
+ }
+ }
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+
+ for (ii = 0; ii <= HCI_EXT_FEATURES_PAGE_MAX; ii++) {
+#if (!CONFIG_BT_STACK_NO_LOG)
+ p_features = p_dev_rec->features[ii];
+#endif
+ BTM_TRACE_EVENT(" remote_features page[%1d] = %02x-%02x-%02x-%02x\n",
+ ii, p_features[0], p_features[1], p_features[2], p_features[3]);
+ BTM_TRACE_EVENT(" %02x-%02x-%02x-%02x\n",
+ p_features[4], p_features[5], p_features[6], p_features[7]);
+ }
+
+ BTM_TRACE_EVENT ("BTM_SecBond: Remote sm4: 0x%x HCI Handle: 0x%04x\n", p_dev_rec->sm4, p_dev_rec->hci_handle);
+
+#if BTM_SEC_FORCE_RNR_FOR_DBOND == TRUE
+ p_dev_rec->sec_flags &= ~BTM_SEC_NAME_KNOWN;
+#endif
+
+ /* If connection already exists... */
+ if (p && p->hci_handle != BTM_SEC_INVALID_HANDLE) {
+ if (!btm_sec_start_authentication (p_dev_rec)) {
+ return (BTM_NO_RESOURCES);
+ }
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
+
+ /* Mark lcb as bonding */
+ l2cu_update_lcb_4_bonding (bd_addr, TRUE);
+ return (BTM_CMD_STARTED);
+ }
+
+ BTM_TRACE_DEBUG ("sec mode: %d sm4:x%x\n", btm_cb.security_mode, p_dev_rec->sm4);
+ if (!controller_get_interface()->supports_simple_pairing()
+ || (p_dev_rec->sm4 == BTM_SM4_KNOWN)) {
+ if ( btm_sec_check_prefetch_pin (p_dev_rec) ) {
+ return (BTM_CMD_STARTED);
+ }
+ }
+ if ((btm_cb.security_mode == BTM_SEC_MODE_SP ||
+ btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+ btm_cb.security_mode == BTM_SEC_MODE_SC) &&
+ BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) {
+ /* local is 2.1 and peer is unknown */
+ if ((p_dev_rec->sm4 & BTM_SM4_CONN_PEND) == 0) {
+ /* we are not accepting connection request from peer
+ * -> RNR (to learn if peer is 2.1)
+ * RNR when no ACL causes HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_GET_REM_NAME);
+ BTM_ReadRemoteDeviceName(bd_addr, NULL, BT_TRANSPORT_BR_EDR);
+ } else {
+ /* We are accepting connection request from peer */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
+ }
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_DEBUG ("State:%s sm4: 0x%x sec_state:%d\n",
+ btm_pair_state_descr (btm_cb.pairing_state), p_dev_rec->sm4, p_dev_rec->sec_state);
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ return BTM_CMD_STARTED;
+ }
+
+ /* both local and peer are 2.1 */
+ status = btm_sec_dd_create_conn(p_dev_rec);
+
+ if (status != BTM_CMD_STARTED) {
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function BTM_SecBondByTransport
+**
+** Description This function is called to perform bonding with peer device.
+** If the connection is already up, but not secure, pairing
+** is attempted. If already paired BTM_SUCCESS is returned.
+**
+** Parameters: bd_addr - Address of the device to bond
+** transport - doing SSP over BR/EDR or SMP over LE
+** pin_len - length in bytes of the PIN Code
+** p_pin - pointer to array with the PIN Code
+** trusted_mask - bitwise OR of trusted services (array of UINT32)
+**
+** Note: After 2.1 parameters are not used and preserved here not to change API
+*******************************************************************************/
+tBTM_STATUS BTM_SecBondByTransport (BD_ADDR bd_addr, tBT_TRANSPORT transport,
+ UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[])
+{
+#if (BLE_INCLUDED == TRUE)
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type = 0;
+
+ BTM_ReadDevInfo(bd_addr, &dev_type, &addr_type);
+ /* LE device, do SMP pairing */
+ if ((transport == BT_TRANSPORT_LE && (dev_type & BT_DEVICE_TYPE_BLE) == 0) ||
+ (transport == BT_TRANSPORT_BR_EDR && (dev_type & BT_DEVICE_TYPE_BREDR) == 0)) {
+ return BTM_ILLEGAL_ACTION;
+ }
+#endif ///BLE_INCLUDED == TRUE
+
+ return btm_sec_bond_by_transport(bd_addr, transport, pin_len, p_pin, trusted_mask);
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function BTM_SecBond
+**
+** Description This function is called to perform bonding with peer device.
+** If the connection is already up, but not secure, pairing
+** is attempted. If already paired BTM_SUCCESS is returned.
+**
+** Parameters: bd_addr - Address of the device to bond
+** pin_len - length in bytes of the PIN Code
+** p_pin - pointer to array with the PIN Code
+** trusted_mask - bitwise OR of trusted services (array of UINT32)
+**
+** Note: After 2.1 parameters are not used and preserved here not to change API
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+tBTM_STATUS BTM_SecBond (BD_ADDR bd_addr, UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[])
+{
+ tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+#if (BLE_INCLUDED == TRUE)
+ if (BTM_UseLeLink(bd_addr)) {
+ transport = BT_TRANSPORT_LE;
+ }
+#endif ///BLE_INCLUDED == TRUE
+ return btm_sec_bond_by_transport(bd_addr, transport, pin_len, p_pin, trusted_mask);
+}
+/*******************************************************************************
+**
+** Function BTM_SecBondCancel
+**
+** Description This function is called to cancel ongoing bonding process
+** with peer device.
+**
+** Parameters: bd_addr - Address of the peer device
+** transport - FALSE for BR/EDR link; TRUE for LE link
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SecBondCancel (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_API ("BTM_SecBondCancel() State: %s flags:0x%x\n",
+ btm_pair_state_descr (btm_cb.pairing_state), btm_cb.pairing_flags);
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ if (((p_dev_rec = btm_find_dev (bd_addr)) == NULL)
+ || (memcmp (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0) ) {
+ return BTM_UNKNOWN_ADDR;
+ }
+
+#if SMP_INCLUDED == TRUE
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_LE_ACTIVE) {
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) {
+ BTM_TRACE_DEBUG ("Cancel LE pairing\n");
+ if (SMP_PairCancel(bd_addr)) {
+ return BTM_CMD_STARTED;
+ }
+ }
+ return BTM_WRONG_MODE;
+ }
+
+#endif
+ BTM_TRACE_DEBUG ("hci_handle:0x%x sec_state:%d\n", p_dev_rec->hci_handle, p_dev_rec->sec_state );
+ if (BTM_PAIR_STATE_WAIT_LOCAL_PIN == btm_cb.pairing_state &&
+ BTM_PAIR_FLAGS_WE_STARTED_DD & btm_cb.pairing_flags) {
+ /* pre-fetching pin for dedicated bonding */
+ btm_sec_bond_cancel_complete();
+ return BTM_SUCCESS;
+ }
+
+ /* If this BDA is in a bonding procedure */
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)) {
+ /* If the HCI link is up */
+ if (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE) {
+ /* If some other thread disconnecting, we do not send second command */
+ if ((p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING) ||
+ (p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING_BOTH)) {
+ return (BTM_CMD_STARTED);
+ }
+
+ /* If the HCI link was set up by Bonding process */
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) {
+ return btm_sec_send_hci_disconnect(p_dev_rec, HCI_ERR_PEER_USER, p_dev_rec->hci_handle);
+ } else {
+ l2cu_update_lcb_4_bonding(bd_addr, FALSE);
+ }
+
+ return BTM_NOT_AUTHORIZED;
+ } else { /*HCI link is not up */
+ /* If the HCI link creation was started by Bonding process */
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) {
+ if (btsnd_hcic_create_conn_cancel(bd_addr)) {
+ return BTM_CMD_STARTED;
+ }
+
+ return BTM_NO_RESOURCES;
+ }
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME) {
+ BTM_CancelRemoteDeviceName();
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_WE_CANCEL_DD;
+ return BTM_CMD_STARTED;
+ }
+ return BTM_NOT_AUTHORIZED;
+ }
+ }
+ return BTM_WRONG_MODE;
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SecGetDeviceLinkKey
+**
+** Description This function is called to obtain link key for the device
+** it returns BTM_SUCCESS if link key is available, or
+** BTM_UNKNOWN_ADDR if Security Manager does not know about
+** the device or device record does not contain link key info
+**
+** Parameters: bd_addr - Address of the device
+** link_key - Link Key is copied into this array
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SecGetDeviceLinkKey (BD_ADDR bd_addr, LINK_KEY link_key)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ if (((p_dev_rec = btm_find_dev (bd_addr)) != NULL)
+ && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) {
+ memcpy (link_key, p_dev_rec->link_key, LINK_KEY_LEN);
+ return (BTM_SUCCESS);
+ }
+ return (BTM_UNKNOWN_ADDR);
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function BTM_SecGetDeviceLinkKeyType
+**
+** Description This function is called to obtain link key type for the
+** device.
+** it returns BTM_SUCCESS if link key is available, or
+** BTM_UNKNOWN_ADDR if Security Manager does not know about
+** the device or device record does not contain link key info
+**
+** Returns BTM_LKEY_TYPE_IGNORE if link key is unknown, link type
+** otherwise.
+**
+*******************************************************************************/
+tBTM_LINK_KEY_TYPE BTM_SecGetDeviceLinkKeyType (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+
+ if ((p_dev_rec != NULL) && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) {
+ return p_dev_rec->link_key_type;
+ }
+ return BTM_LKEY_TYPE_IGNORE;
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetEncryption
+**
+** Description This function is called to ensure that connection is
+** encrypted. Should be called only on an open connection.
+** Typically only needed for connections that first want to
+** bring up unencrypted links, then later encrypt them.
+**
+** Parameters: bd_addr - Address of the peer device
+** p_callback - Pointer to callback function called if
+** this function returns PENDING after required
+** procedures are completed. Can be set to NULL
+** if status is not desired.
+** p_ref_data - pointer to any data the caller wishes to receive
+** in the callback function upon completion.
+* can be set to NULL if not used.
+** transport - TRUE to encryption the link over LE transport
+** or FALSE for BR/EDR transport
+**
+** Returns BTM_SUCCESS - already encrypted
+** BTM_PENDING - command will be returned in the callback
+** BTM_WRONG_MODE- connection not up.
+** BTM_BUSY - security procedures are currently active
+** BTM_MODE_UNSUPPORTED - if security manager not linked in.
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+tBTM_STATUS BTM_SetEncryption (BD_ADDR bd_addr, tBT_TRANSPORT transport, tBTM_SEC_CBACK *p_callback,
+ void *p_ref_data)
+{
+ tBTM_STATUS rc = 0;
+
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+ if (!p_dev_rec ||
+ (transport == BT_TRANSPORT_BR_EDR && p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE)
+#if BLE_INCLUDED == TRUE
+ || (transport == BT_TRANSPORT_LE && p_dev_rec->ble_hci_handle == BTM_SEC_INVALID_HANDLE)
+#endif
+ ) {
+ /* Connection should be up and runnning */
+ BTM_TRACE_WARNING ("Security Manager: BTM_SetEncryption not connected\n");
+
+ if (p_callback) {
+ (*p_callback) (bd_addr, transport, p_ref_data, BTM_WRONG_MODE);
+ }
+
+ return (BTM_WRONG_MODE);
+ }
+
+ if ((transport == BT_TRANSPORT_BR_EDR &&
+ (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ || (transport == BT_TRANSPORT_LE &&
+ (p_dev_rec->sec_flags & BTM_SEC_LE_ENCRYPTED))
+#endif
+ ) {
+ BTM_TRACE_EVENT ("Security Manager: BTM_SetEncryption already encrypted\n");
+
+ if (p_callback) {
+ (*p_callback) (bd_addr, transport, p_ref_data, BTM_SUCCESS);
+ }
+
+ return (BTM_SUCCESS);
+ }
+ p_dev_rec->enc_init_by_we = TRUE;
+ /* enqueue security request if security is active */
+ if (p_dev_rec->p_callback || (p_dev_rec->sec_state != BTM_SEC_STATE_IDLE)) {
+ BTM_TRACE_WARNING ("Security Manager: BTM_SetEncryption busy, enqueue request\n");
+
+ if (btm_sec_queue_encrypt_request(bd_addr, transport, p_callback, p_ref_data)) {
+ return BTM_CMD_STARTED;
+ } else {
+ if (p_callback) {
+ (*p_callback) (bd_addr, transport, p_ref_data, BTM_NO_RESOURCES);
+ }
+ return BTM_NO_RESOURCES;
+ }
+ }
+
+ p_dev_rec->p_callback = p_callback;
+ p_dev_rec->p_ref_data = p_ref_data;
+ p_dev_rec->security_required |= (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT);
+ p_dev_rec->is_originator = FALSE;
+
+ BTM_TRACE_API ("Security Manager: BTM_SetEncryption Handle:%d State:%d Flags:0x%x Required:0x%x\n",
+ p_dev_rec->hci_handle, p_dev_rec->sec_state, p_dev_rec->sec_flags,
+ p_dev_rec->security_required);
+
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ if (transport == BT_TRANSPORT_LE) {
+ tACL_CONN *p = btm_bda_to_acl(bd_addr, transport);
+ if (p) {
+ rc = btm_ble_set_encryption(bd_addr, p_ref_data, p->link_role);
+ } else {
+ rc = BTM_WRONG_MODE;
+ BTM_TRACE_WARNING("%s: cannot call btm_ble_set_encryption, p is NULL\n", __FUNCTION__);
+ }
+ } else
+#endif
+ {
+ rc = btm_sec_execute_procedure (p_dev_rec);
+ }
+
+ if (rc != BTM_CMD_STARTED && rc != BTM_BUSY) {
+ if (p_callback) {
+ p_dev_rec->p_callback = NULL;
+ (*p_callback) (bd_addr, transport, p_dev_rec->p_ref_data, rc);
+ }
+ }
+
+ return (rc);
+}
+
+/*******************************************************************************
+ * disconnect the ACL link, if it's not done yet.
+*******************************************************************************/
+static tBTM_STATUS btm_sec_send_hci_disconnect (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 reason, UINT16 conn_handle)
+{
+ UINT8 old_state = p_dev_rec->sec_state;
+ tBTM_STATUS status = BTM_CMD_STARTED;
+
+ BTM_TRACE_EVENT ("btm_sec_send_hci_disconnect: handle:0x%x, reason=0x%x\n",
+ conn_handle, reason);
+
+ /* send HCI_Disconnect on a transport only once */
+ switch (old_state) {
+ case BTM_SEC_STATE_DISCONNECTING:
+ if (conn_handle == p_dev_rec->hci_handle) {
+ return status;
+ }
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_DISCONNECTING_BOTH;
+ break;
+
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ case BTM_SEC_STATE_DISCONNECTING_BLE:
+ if (conn_handle == p_dev_rec->ble_hci_handle) {
+ return status;
+ }
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_DISCONNECTING_BOTH;
+ break;
+
+ case BTM_SEC_STATE_DISCONNECTING_BOTH:
+ return status;
+#endif
+
+ default:
+ p_dev_rec->sec_state = (conn_handle == p_dev_rec->hci_handle) ?
+ BTM_SEC_STATE_DISCONNECTING : BTM_SEC_STATE_DISCONNECTING_BLE;
+
+ break;
+ }
+
+ /* If a role switch is in progress, delay the HCI Disconnect to avoid controller problem */
+ if (p_dev_rec->rs_disc_pending == BTM_SEC_RS_PENDING && p_dev_rec->hci_handle == conn_handle) {
+ BTM_TRACE_DEBUG("RS in progress - Set DISC Pending flag in btm_sec_send_hci_disconnect to delay disconnect\n");
+ p_dev_rec->rs_disc_pending = BTM_SEC_DISC_PENDING;
+ status = BTM_SUCCESS;
+ }
+ /* Tear down the HCI link */
+ else if (!btsnd_hcic_disconnect (conn_handle, reason)) {
+ /* could not send disconnect. restore old state */
+ p_dev_rec->sec_state = old_state;
+ status = BTM_NO_RESOURCES;
+ }
+
+ return status;
+}
+#endif ///SMP_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function BTM_ConfirmReqReply
+**
+** Description This function is called to confirm the numeric value for
+** Simple Pairing in response to BTM_SP_CFM_REQ_EVT
+**
+** Parameters: res - result of the operation BTM_SUCCESS if success
+** bd_addr - Address of the peer device
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+void BTM_ConfirmReqReply(tBTM_STATUS res, BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_EVENT ("BTM_ConfirmReqReply() State: %s Res: %u",
+ btm_pair_state_descr(btm_cb.pairing_state), res);
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM)
+ || (memcmp (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0) ) {
+ return;
+ }
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+
+ if ( (res == BTM_SUCCESS) || (res == BTM_SUCCESS_NO_SECURITY) ) {
+ btm_cb.acl_disc_reason = HCI_SUCCESS;
+
+ if (res == BTM_SUCCESS) {
+ if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL) {
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+ p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+ }
+ }
+
+ btsnd_hcic_user_conf_reply (bd_addr, TRUE);
+ } else {
+ /* Report authentication failed event from state BTM_PAIR_STATE_WAIT_AUTH_COMPLETE */
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+ btsnd_hcic_user_conf_reply (bd_addr, FALSE);
+ }
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function BTM_PasskeyReqReply
+**
+** Description This function is called to provide the passkey for
+** Simple Pairing in response to BTM_SP_KEY_REQ_EVT
+**
+** Parameters: res - result of the operation BTM_SUCCESS if success
+** bd_addr - Address of the peer device
+** passkey - numeric value in the range of
+** BTM_MIN_PASSKEY_VAL(0) - BTM_MAX_PASSKEY_VAL(999999(0xF423F)).
+**
+*******************************************************************************/
+#if (CLASSIC_BT_INCLUDED == TRUE)
+void BTM_PasskeyReqReply(tBTM_STATUS res, BD_ADDR bd_addr, UINT32 passkey)
+{
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_API ("BTM_PasskeyReqReply: State: %s res:%d\n",
+ btm_pair_state_descr(btm_cb.pairing_state), res);
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ if ( (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE)
+ || (memcmp (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0) ) {
+ return;
+ }
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if ( (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_AUTH_COMPLETE) && (res != BTM_SUCCESS) ) {
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+ if (p_dev_rec != NULL) {
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+
+ if (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE) {
+ btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE, p_dev_rec->hci_handle);
+ } else {
+ BTM_SecBondCancel(bd_addr);
+ }
+
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_AUTHED | BTM_SEC_LINK_KEY_KNOWN);
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ return;
+ }
+ } else if (btm_cb.pairing_state != BTM_PAIR_STATE_KEY_ENTRY) {
+ return;
+ }
+
+ if (passkey > BTM_MAX_PASSKEY_VAL) {
+ res = BTM_ILLEGAL_VALUE;
+ }
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+
+ if (res != BTM_SUCCESS) {
+ /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed event */
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+ btsnd_hcic_user_passkey_neg_reply (bd_addr);
+ } else {
+ btm_cb.acl_disc_reason = HCI_SUCCESS;
+ btsnd_hcic_user_passkey_reply (bd_addr, passkey);
+ }
+}
+#endif /* (CLASSIC_BT_INCLUDED == TRUE) */
+
+/*******************************************************************************
+**
+** Function BTM_SendKeypressNotif
+**
+** Description This function is used during the passkey entry model
+** by a device with KeyboardOnly IO capabilities
+** (very likely to be a HID Device).
+** It is called by a HID Device to inform the remote device when
+** a key has been entered or erased.
+**
+** Parameters: bd_addr - Address of the peer device
+** type - notification type
+**
+*******************************************************************************/
+#if (CLASSIC_BT_INCLUDED == TRUE)
+void BTM_SendKeypressNotif(BD_ADDR bd_addr, tBTM_SP_KEY_TYPE type)
+{
+ /* This API only make sense between PASSKEY_REQ and SP complete */
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_KEY_ENTRY) {
+ btsnd_hcic_send_keypress_notif (bd_addr, type);
+ }
+}
+#endif /* (CLASSIC_BT_INCLUDED == TRUE) */
+
+#if BTM_OOB_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function BTM_IoCapRsp
+**
+** Description This function is called in response to BTM_SP_IO_REQ_EVT
+** When the event data io_req.oob_data is set to BTM_OOB_UNKNOWN
+** by the tBTM_SP_CALLBACK implementation, this function is
+** called to provide the actual response
+**
+** Parameters: bd_addr - Address of the peer device
+** io_cap - The IO capability of local device.
+** oob - BTM_OOB_NONE or BTM_OOB_PRESENT.
+** auth_req- MITM protection required or not.
+**
+*******************************************************************************/
+void BTM_IoCapRsp(BD_ADDR bd_addr, tBTM_IO_CAP io_cap, tBTM_OOB_DATA oob, tBTM_AUTH_REQ auth_req)
+{
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_EVENT ("BTM_IoCapRsp: state: %s oob: %d io_cap: %d\n",
+ btm_pair_state_descr(btm_cb.pairing_state), oob, io_cap);
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS)
+ || (memcmp (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0) ) {
+ return;
+ }
+
+ if (oob < BTM_OOB_UNKNOWN && io_cap < BTM_IO_CAP_MAX) {
+ btm_cb.devcb.loc_auth_req = auth_req;
+ btm_cb.devcb.loc_io_caps = io_cap;
+
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) {
+ auth_req = (BTM_AUTH_DD_BOND | (auth_req & BTM_AUTH_YN_BIT));
+ }
+
+ btsnd_hcic_io_cap_req_reply (bd_addr, io_cap, oob, auth_req);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalOobData
+**
+** Description This function is called to read the local OOB data from
+** LM
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadLocalOobData(void)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ if (btsnd_hcic_read_local_oob_data() == FALSE) {
+ status = BTM_NO_RESOURCES;
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function BTM_RemoteOobDataReply
+**
+** Description This function is called to provide the remote OOB data for
+** Simple Pairing in response to BTM_SP_RMT_OOB_EVT
+**
+** Parameters: bd_addr - Address of the peer device
+** c - simple pairing Hash C.
+** r - simple pairing Randomizer C.
+**
+*******************************************************************************/
+void BTM_RemoteOobDataReply(tBTM_STATUS res, BD_ADDR bd_addr, BT_OCTET16 c, BT_OCTET16 r)
+{
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_EVENT ("%s() - State: %s res: %d\n", __func__,
+ btm_pair_state_descr(btm_cb.pairing_state), res);
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP) {
+ return;
+ }
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+
+ if (res != BTM_SUCCESS) {
+ /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed event */
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+ btsnd_hcic_rem_oob_neg_reply (bd_addr);
+ } else {
+ btm_cb.acl_disc_reason = HCI_SUCCESS;
+ btsnd_hcic_rem_oob_reply (bd_addr, c, r);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTM_BuildOobData
+**
+** Description This function is called to build the OOB data payload to
+** be sent over OOB (non-Bluetooth) link
+**
+** Parameters: p_data - the location for OOB data
+** max_len - p_data size.
+** c - simple pairing Hash C.
+** r - simple pairing Randomizer C.
+** name_len- 0, local device name would not be included.
+** otherwise, the local device name is included for
+** up to this specified length
+**
+** Returns Number of bytes in p_data.
+**
+*******************************************************************************/
+UINT16 BTM_BuildOobData(UINT8 *p_data, UINT16 max_len, BT_OCTET16 c,
+ BT_OCTET16 r, UINT8 name_len)
+{
+ UINT8 *p = p_data;
+ UINT16 len = 0;
+#if BTM_MAX_LOC_BD_NAME_LEN > 0
+ UINT16 name_size;
+ UINT8 name_type = BTM_EIR_SHORTENED_LOCAL_NAME_TYPE;
+#endif
+
+ if (p_data && max_len >= BTM_OOB_MANDATORY_SIZE) {
+ /* add mandatory part */
+ UINT16_TO_STREAM(p, len);
+ BDADDR_TO_STREAM(p, controller_get_interface()->get_address()->address);
+
+ len = BTM_OOB_MANDATORY_SIZE;
+ max_len -= len;
+
+ /* now optional part */
+
+ /* add Hash C */
+ UINT16 delta = BTM_OOB_HASH_C_SIZE + 2;
+ if (max_len >= delta) {
+ *p++ = BTM_OOB_HASH_C_SIZE + 1;
+ *p++ = BTM_EIR_OOB_SSP_HASH_C_TYPE;
+ ARRAY_TO_STREAM(p, c, BTM_OOB_HASH_C_SIZE);
+ len += delta;
+ max_len -= delta;
+ }
+
+ /* add Rand R */
+ delta = BTM_OOB_RAND_R_SIZE + 2;
+ if (max_len >= delta) {
+ *p++ = BTM_OOB_RAND_R_SIZE + 1;
+ *p++ = BTM_EIR_OOB_SSP_RAND_R_TYPE;
+ ARRAY_TO_STREAM(p, r, BTM_OOB_RAND_R_SIZE);
+ len += delta;
+ max_len -= delta;
+ }
+
+ /* add class of device */
+ delta = BTM_OOB_COD_SIZE + 2;
+ if (max_len >= delta) {
+ *p++ = BTM_OOB_COD_SIZE + 1;
+ *p++ = BTM_EIR_OOB_COD_TYPE;
+ DEVCLASS_TO_STREAM(p, btm_cb.devcb.dev_class);
+ len += delta;
+ max_len -= delta;
+ }
+#if BTM_MAX_LOC_BD_NAME_LEN > 0
+ name_size = name_len;
+ if (name_size > strlen(btm_cb.cfg.bd_name)) {
+ name_type = BTM_EIR_COMPLETE_LOCAL_NAME_TYPE;
+ name_size = (UINT16)strlen(btm_cb.cfg.bd_name);
+ }
+ delta = name_size + 2;
+ if (max_len >= delta) {
+ *p++ = name_size + 1;
+ *p++ = name_type;
+ ARRAY_TO_STREAM (p, btm_cb.cfg.bd_name, name_size);
+ len += delta;
+ max_len -= delta;
+ }
+#endif
+ /* update len */
+ p = p_data;
+ UINT16_TO_STREAM(p, len);
+ }
+ return len;
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadOobData
+**
+** Description This function is called to parse the OOB data payload
+** received over OOB (non-Bluetooth) link
+**
+** Parameters: p_data - the location for OOB data
+** eir_tag - The associated EIR tag to read the data.
+** *p_len(output) - the length of the data with the given tag.
+**
+** Returns the beginning of the data with the given tag.
+** NULL, if the tag is not found.
+**
+*******************************************************************************/
+UINT8 *BTM_ReadOobData(UINT8 *p_data, UINT8 eir_tag, UINT8 *p_len)
+{
+ UINT8 *p = p_data;
+ UINT16 max_len;
+ UINT8 len, type;
+ UINT8 *p_ret = NULL;
+ UINT8 ret_len = 0;
+
+ if (p_data) {
+ STREAM_TO_UINT16(max_len, p);
+ if (max_len >= BTM_OOB_MANDATORY_SIZE) {
+ if (BTM_EIR_OOB_BD_ADDR_TYPE == eir_tag) {
+ p_ret = p; /* the location for bd_addr */
+ ret_len = BTM_OOB_BD_ADDR_SIZE;
+ } else {
+ p += BD_ADDR_LEN;
+ max_len -= BTM_OOB_MANDATORY_SIZE;
+ /* now the optional data in EIR format */
+ while (max_len > 0) {
+ len = *p++; /* tag data len + 1 */
+ type = *p++;
+ if (eir_tag == type) {
+ p_ret = p;
+ ret_len = len - 1;
+ break;
+ }
+ /* the data size of this tag is len + 1 (tag data len + 2) */
+ if (max_len > len) {
+ max_len -= len;
+ max_len--;
+ len--;
+ p += len;
+ } else {
+ max_len = 0;
+ }
+ }
+ }
+ }
+ }
+
+ if (p_len) {
+ *p_len = ret_len;
+ }
+
+ return p_ret;
+}
+#endif ///BTM_OOB_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function BTM_BothEndsSupportSecureConnections
+**
+** Description This function is called to check if both the local device and the peer device
+** specified by bd_addr support BR/EDR Secure Connections.
+**
+** Parameters: bd_addr - address of the peer
+**
+** Returns TRUE if BR/EDR Secure Connections are supported by both local
+** and the remote device.
+** else FALSE.
+**
+*******************************************************************************/
+BOOLEAN BTM_BothEndsSupportSecureConnections(BD_ADDR bd_addr)
+{
+ return ((controller_get_interface()->supports_secure_connections()) &&
+ (BTM_PeerSupportsSecureConnections(bd_addr)));
+}
+
+/*******************************************************************************
+**
+** Function BTM_PeerSupportsSecureConnections
+**
+** Description This function is called to check if the peer supports
+** BR/EDR Secure Connections.
+**
+** Parameters: bd_addr - address of the peer
+**
+** Returns TRUE if BR/EDR Secure Connections are supported by the peer,
+** else FALSE.
+**
+*******************************************************************************/
+BOOLEAN BTM_PeerSupportsSecureConnections(BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ if ((p_dev_rec = btm_find_dev(bd_addr)) == NULL) {
+ BTM_TRACE_WARNING("%s: unknown BDA: %08x%04x\n", __FUNCTION__,
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5]);
+ return FALSE;
+ }
+
+ return (p_dev_rec->remote_supports_secure_connections);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetOutService
+**
+** Description This function is called to set the service for
+** outgoing connections.
+**
+** If the profile/application calls BTM_SetSecurityLevel
+** before initiating a connection, this function does not
+** need to be called.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_SetOutService(BD_ADDR bd_addr, UINT8 service_id, UINT32 mx_chan_id)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_SEC_SERV_REC *p_serv_rec = &btm_cb.sec_serv_rec[0];
+
+ btm_cb.p_out_serv = p_serv_rec;
+ p_dev_rec = btm_find_dev (bd_addr);
+
+ for (int i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++) {
+ if ((p_serv_rec->security_flags & BTM_SEC_IN_USE)
+ && (p_serv_rec->service_id == service_id)
+ && (p_serv_rec->orig_mx_chan_id == mx_chan_id)) {
+ BTM_TRACE_API("BTM_SetOutService p_out_serv id %d, psm 0x%04x, proto_id %d, chan_id %d\n",
+ p_serv_rec->service_id, p_serv_rec->psm, p_serv_rec->mx_proto_id, p_serv_rec->orig_mx_chan_id);
+ btm_cb.p_out_serv = p_serv_rec;
+ if (p_dev_rec) {
+ p_dev_rec->p_cur_service = p_serv_rec;
+ }
+ break;
+ }
+ }
+}
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+
+
+/************************************************************************
+** I N T E R N A L F U N C T I O N S
+*************************************************************************/
+/*******************************************************************************
+**
+** Function btm_sec_is_upgrade_possible
+**
+** Description This function returns TRUE if the existing link key
+** can be upgraded or if the link key does not exist.
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static BOOLEAN btm_sec_is_upgrade_possible(tBTM_SEC_DEV_REC *p_dev_rec, BOOLEAN is_originator)
+{
+ UINT16 mtm_check = is_originator ? BTM_SEC_OUT_MITM : BTM_SEC_IN_MITM;
+ BOOLEAN is_possible = TRUE;
+
+ if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) {
+ is_possible = FALSE;
+ if (p_dev_rec->p_cur_service) {
+ BTM_TRACE_DEBUG ("%s() id: %d, link_key_typet: %d, rmt_io_caps: %d, chk flags: 0x%x, flags: 0x%x\n",
+ __func__, p_dev_rec->p_cur_service->service_id, p_dev_rec->link_key_type,
+ p_dev_rec->rmt_io_caps, mtm_check, p_dev_rec->p_cur_service->security_flags);
+ } else {
+ BTM_TRACE_DEBUG ("%s() link_key_typet: %d, rmt_io_caps: %d, chk flags: 0x%x\n",
+ __func__, p_dev_rec->link_key_type, p_dev_rec->rmt_io_caps, mtm_check);
+ }
+ /* Already have a link key to the connected peer. Is the link key secure enough?
+ ** Is a link key upgrade even possible?
+ */
+ if ((p_dev_rec->security_required & mtm_check) /* needs MITM */
+ && ((p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB) ||
+ (p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256))
+ /* has unauthenticated
+ link key */
+ && (p_dev_rec->rmt_io_caps < BTM_IO_CAP_MAX) /* a valid peer IO cap */
+ && (btm_sec_io_map[p_dev_rec->rmt_io_caps][btm_cb.devcb.loc_io_caps]))
+ /* authenticated
+ link key is possible */
+ {
+ /* upgrade is possible: check if the application wants the upgrade.
+ * If the application is configured to use a global MITM flag,
+ * it probably would not want to upgrade the link key based on the security level database */
+ is_possible = TRUE;
+ }
+ }
+ BTM_TRACE_DEBUG ("%s() is_possible: %d sec_flags: 0x%x\n", __func__, is_possible, p_dev_rec->sec_flags);
+ return is_possible;
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_sec_check_upgrade
+**
+** Description This function is called to check if the existing link key
+** needs to be upgraded.
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static void btm_sec_check_upgrade(tBTM_SEC_DEV_REC *p_dev_rec, BOOLEAN is_originator)
+{
+
+ BTM_TRACE_DEBUG ("%s()\n", __func__);
+
+ /* Only check if link key already exists */
+ if (!(p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) {
+ return;
+ }
+
+ if (btm_sec_is_upgrade_possible (p_dev_rec, is_originator) == TRUE) {
+ BTM_TRACE_DEBUG ("need upgrade!! sec_flags:0x%x\n", p_dev_rec->sec_flags);
+ /* upgrade is possible: check if the application wants the upgrade.
+ * If the application is configured to use a global MITM flag,
+ * it probably would not want to upgrade the link key based on the security level database */
+ tBTM_SP_UPGRADE evt_data;
+ memcpy (evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ evt_data.upgrade = TRUE;
+ if (btm_cb.api.p_sp_callback) {
+ (*btm_cb.api.p_sp_callback) (BTM_SP_UPGRADE_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+ }
+
+ BTM_TRACE_DEBUG ("evt_data.upgrade:0x%x\n", evt_data.upgrade);
+ if (evt_data.upgrade) {
+ /* if the application confirms the upgrade, set the upgrade bit */
+ p_dev_rec->sm4 |= BTM_SM4_UPGRADE;
+
+ /* Clear the link key known to go through authentication/pairing again */
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED);
+ p_dev_rec->sec_flags &= ~BTM_SEC_AUTHENTICATED;
+ BTM_TRACE_DEBUG ("sec_flags:0x%x\n", p_dev_rec->sec_flags);
+ }
+ }
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_sec_l2cap_access_req
+**
+** Description This function is called by the L2CAP to grant permission to
+** establish L2CAP connection to or from the peer device.
+**
+** Parameters: bd_addr - Address of the peer device
+** psm - L2CAP PSM
+** is_originator - TRUE if protocol above L2CAP originates
+** connection
+** p_callback - Pointer to callback function called if
+** this function returns PENDING after required
+** procedures are complete. MUST NOT BE NULL.
+**
+** Returns tBTM_STATUS
+**
+*******************************************************************************/
+tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle,
+ CONNECTION_TYPE conn_type,
+ tBTM_SEC_CALLBACK *p_callback,
+ void *p_ref_data)
+{
+#if (SMP_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_SEC_SERV_REC *p_serv_rec;
+ UINT16 security_required;
+ UINT16 old_security_required;
+ BOOLEAN old_is_originator;
+ tBTM_STATUS rc = BTM_SUCCESS;
+ BOOLEAN chk_acp_auth_done = FALSE;
+ BOOLEAN is_originator;
+ BOOLEAN transport = FALSE; /* should check PSM range in LE connection oriented L2CAP connection */
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (conn_type & CONNECTION_TYPE_ORIG_MASK) {
+ is_originator = TRUE;
+ } else {
+ is_originator = FALSE;
+ }
+
+ BTM_TRACE_DEBUG ("%s() conn_type: 0x%x, %p\n", __func__, conn_type, p_ref_data);
+#else
+ is_originator = conn_type;
+
+ BTM_TRACE_DEBUG ("%s() is_originator:%d, %p\n", __func__, is_originator, p_ref_data);
+#endif
+
+ /* Find or get oldest record */
+ p_dev_rec = btm_find_or_alloc_dev (bd_addr);
+
+ p_dev_rec->hci_handle = handle;
+
+ /* Find the service record for the PSM */
+ p_serv_rec = btm_sec_find_first_serv (conn_type, psm);
+
+ /* If there is no application registered with this PSM do not allow connection */
+ if (!p_serv_rec) {
+ BTM_TRACE_WARNING ("%s() PSM: %d no application registerd\n", __func__, psm);
+ (*p_callback) (bd_addr, transport, p_ref_data, BTM_MODE_UNSUPPORTED);
+ return (BTM_MODE_UNSUPPORTED);
+ }
+
+ /* Services level0 by default have no security */
+ if ((btm_sec_is_serv_level0(psm)) && (!btm_cb.devcb.secure_connections_only)) {
+ (*p_callback) (bd_addr, transport, p_ref_data, BTM_SUCCESS_NO_SECURITY);
+ return (BTM_SUCCESS);
+ }
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( conn_type & CONNECTION_TYPE_CONNLESS_MASK ) {
+ if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ security_required = btm_sec_set_serv_level4_flags (p_serv_rec->ucd_security_flags,
+ is_originator);
+ } else {
+ security_required = p_serv_rec->ucd_security_flags;
+ }
+
+ rc = BTM_CMD_STARTED;
+ if (is_originator) {
+ if (((security_required & BTM_SEC_OUT_FLAGS) == 0) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_AUTHENTICATE) && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) == (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) && (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_FLAGS) && (p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED))) ) {
+ rc = BTM_SUCCESS;
+ }
+ } else {
+ if (((security_required & BTM_SEC_IN_FLAGS) == 0) ||
+ ((((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHENTICATE) && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))) ||
+ ((((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) && (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) ||
+ ((((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_FLAGS) && (p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED))) ) {
+ // Check for 16 digits (or MITM)
+ if (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == 0) ||
+ (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == BTM_SEC_IN_MIN_16_DIGIT_PIN) &&
+ btm_dev_16_digit_authenticated(p_dev_rec))) {
+ rc = BTM_SUCCESS;
+ }
+ }
+ }
+
+ if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) &&
+ (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ rc = BTM_CMD_STARTED;
+ }
+
+ if (rc == BTM_SUCCESS) {
+ if (p_callback) {
+ (*p_callback) (bd_addr, transport, (void *)p_ref_data, BTM_SUCCESS);
+ }
+
+ return (BTM_SUCCESS);
+ }
+ } else
+#endif
+ {
+ if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ security_required = btm_sec_set_serv_level4_flags (p_serv_rec->security_flags,
+ is_originator);
+ } else {
+ security_required = p_serv_rec->security_flags;
+ }
+ }
+
+ BTM_TRACE_DEBUG("%s: security_required 0x%04x, is_originator 0x%02x, psm 0x%04x\n",
+ __FUNCTION__, security_required, is_originator, psm);
+
+ if ((!is_originator) && (security_required & BTM_SEC_MODE4_LEVEL4)) {
+ BOOLEAN local_supports_sc = controller_get_interface()->supports_secure_connections();
+ /* acceptor receives L2CAP Channel Connect Request for Secure Connections Only service */
+ if (!(local_supports_sc) || !(p_dev_rec->remote_supports_secure_connections)) {
+ BTM_TRACE_DEBUG("%s: SC only service, local_support_for_sc %d\n"
+ "rmt_support_for_sc : %d -> fail pairing\n", __FUNCTION__,
+ local_supports_sc,
+ p_dev_rec->remote_supports_secure_connections);
+ if (p_callback) {
+ (*p_callback) (bd_addr, transport, (void *)p_ref_data,
+ BTM_MODE4_LEVEL4_NOT_SUPPORTED);
+ }
+
+ return (BTM_MODE4_LEVEL4_NOT_SUPPORTED);
+ }
+ }
+
+ /* there are some devices (moto KRZR) which connects to several services at the same time */
+ /* we will process one after another */
+ if ( (p_dev_rec->p_callback) || (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) ) {
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_EVENT ("%s() - busy - PSM:%d delayed state: %s mode:%d, sm4:0x%x\n", __func__,
+ psm, btm_pair_state_descr(btm_cb.pairing_state), btm_cb.security_mode, p_dev_rec->sm4);
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ BTM_TRACE_EVENT ("security_flags:x%x, sec_flags:x%x\n", security_required, p_dev_rec->sec_flags);
+ rc = BTM_CMD_STARTED;
+ if ((btm_cb.security_mode == BTM_SEC_MODE_UNDEFINED ||
+ btm_cb.security_mode == BTM_SEC_MODE_NONE ||
+ btm_cb.security_mode == BTM_SEC_MODE_SERVICE ||
+ btm_cb.security_mode == BTM_SEC_MODE_LINK) ||
+ (BTM_SM4_KNOWN == p_dev_rec->sm4) || (BTM_SEC_IS_SM4(p_dev_rec->sm4) &&
+ (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == FALSE))) {
+ /* legacy mode - local is legacy or local is lisbon/peer is legacy
+ * or SM4 with no possibility of link key upgrade */
+ if (is_originator) {
+ if (((security_required & BTM_SEC_OUT_FLAGS) == 0) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_AUTHENTICATE) && btm_dev_authenticated(p_dev_rec))) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) == (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) && btm_dev_encrypted(p_dev_rec))) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_FLAGS) && btm_dev_authorized(p_dev_rec) && btm_dev_encrypted(p_dev_rec))) ) {
+ rc = BTM_SUCCESS;
+ }
+ } else {
+ if (((security_required & BTM_SEC_IN_FLAGS) == 0) ||
+ (((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHENTICATE) && btm_dev_authenticated(p_dev_rec)) ||
+ (((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) && btm_dev_encrypted(p_dev_rec)) ||
+ (((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHORIZE) && (btm_dev_authorized(p_dev_rec) || btm_serv_trusted(p_dev_rec, p_serv_rec))) ||
+ (((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_AUTHORIZE)) && ((btm_dev_authorized(p_dev_rec) || btm_serv_trusted(p_dev_rec, p_serv_rec)) && btm_dev_authenticated(p_dev_rec))) ||
+ (((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHORIZE)) && ((btm_dev_authorized(p_dev_rec) || btm_serv_trusted(p_dev_rec, p_serv_rec)) && btm_dev_encrypted(p_dev_rec))) ||
+ (((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_FLAGS) && btm_dev_encrypted(p_dev_rec) && (btm_dev_authorized(p_dev_rec) || btm_serv_trusted(p_dev_rec, p_serv_rec)))) {
+ // Check for 16 digits (or MITM)
+ if (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == 0) ||
+ (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == BTM_SEC_IN_MIN_16_DIGIT_PIN) && btm_dev_16_digit_authenticated(p_dev_rec))) {
+ rc = BTM_SUCCESS;
+ }
+ }
+ }
+
+ if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) &&
+ (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ rc = BTM_CMD_STARTED;
+ }
+
+ if (rc == BTM_SUCCESS) {
+ if (p_callback) {
+ (*p_callback) (bd_addr, transport, (void *)p_ref_data, BTM_SUCCESS);
+ }
+ return (BTM_SUCCESS);
+ }
+ }
+
+ btm_cb.sec_req_pending = TRUE;
+ return (BTM_CMD_STARTED);
+ }
+
+ /* Save pointer to service record */
+ p_dev_rec->p_cur_service = p_serv_rec;
+
+ /* Modify security_required in btm_sec_l2cap_access_req for Lisbon */
+ if (btm_cb.security_mode == BTM_SEC_MODE_SP ||
+ btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+ btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) {
+ if (is_originator) {
+ /* SM4 to SM4 -> always authenticate & encrypt */
+ security_required |= (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT);
+ } else { /* acceptor */
+ /* SM4 to SM4: the acceptor needs to make sure the authentication is already done */
+ chk_acp_auth_done = TRUE;
+ /* SM4 to SM4 -> always authenticate & encrypt */
+ security_required |= (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT);
+ }
+ } else if (!(BTM_SM4_KNOWN & p_dev_rec->sm4)) {
+ /* the remote features are not known yet */
+ BTM_TRACE_ERROR("%s: (%s) remote features unknown!!sec_flags:0x%02x\n", __FUNCTION__,
+ (is_originator) ? "initiator" : "acceptor", p_dev_rec->sec_flags);
+
+ p_dev_rec->sm4 |= BTM_SM4_REQ_PEND;
+ return (BTM_CMD_STARTED);
+ }
+ }
+
+ BTM_TRACE_DEBUG ("%s() sm4:0x%x, sec_flags:0x%x, security_required:0x%x chk:%d\n", __func__,
+ p_dev_rec->sm4, p_dev_rec->sec_flags, security_required, chk_acp_auth_done);
+
+ old_security_required = p_dev_rec->security_required;
+ old_is_originator = p_dev_rec->is_originator;
+ p_dev_rec->security_required = security_required;
+ p_dev_rec->p_ref_data = p_ref_data;
+ p_dev_rec->is_originator = is_originator;
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( conn_type & CONNECTION_TYPE_CONNLESS_MASK ) {
+ p_dev_rec->is_ucd = TRUE;
+ } else {
+ p_dev_rec->is_ucd = FALSE;
+ }
+#endif
+
+ /* If there are multiple service records used through the same PSM */
+ /* leave security decision for the multiplexor on the top */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (((btm_sec_find_next_serv (p_serv_rec)) != NULL)
+ && (!( conn_type & CONNECTION_TYPE_CONNLESS_MASK ))) /* if not UCD */
+#else
+ if ((btm_sec_find_next_serv (p_serv_rec)) != NULL)
+#endif
+ {
+ BTM_TRACE_DEBUG ("no next_serv sm4:0x%x, chk:%d\n", p_dev_rec->sm4, chk_acp_auth_done);
+ if (!BTM_SEC_IS_SM4(p_dev_rec->sm4)) {
+ BTM_TRACE_EVENT ("Security Manager: l2cap_access_req PSM:%d postponed for multiplexer\n", psm);
+ /* pre-Lisbon: restore the old settings */
+ p_dev_rec->security_required = old_security_required;
+ p_dev_rec->is_originator = old_is_originator;
+
+ (*p_callback) (bd_addr, transport, p_ref_data, BTM_SUCCESS);
+
+ return (BTM_SUCCESS);
+ }
+ }
+
+ /* if the originator is using dynamic PSM in legacy mode, do not start any security process now
+ * The layer above L2CAP needs to carry out the security requirement after L2CAP connect
+ * response is received */
+ if (is_originator &&
+ ((btm_cb.security_mode == BTM_SEC_MODE_UNDEFINED ||
+ btm_cb.security_mode == BTM_SEC_MODE_NONE ||
+ btm_cb.security_mode == BTM_SEC_MODE_SERVICE ||
+ btm_cb.security_mode == BTM_SEC_MODE_LINK) ||
+ !BTM_SEC_IS_SM4(p_dev_rec->sm4)) && (psm >= 0x1001)) {
+ BTM_TRACE_EVENT ("dynamic PSM:0x%x in legacy mode - postponed for upper layer\n", psm);
+ /* restore the old settings */
+ p_dev_rec->security_required = old_security_required;
+ p_dev_rec->is_originator = old_is_originator;
+
+ (*p_callback) (bd_addr, transport, p_ref_data, BTM_SUCCESS);
+
+ return (BTM_SUCCESS);
+ }
+
+ if (chk_acp_auth_done) {
+ BTM_TRACE_DEBUG ("(SM4 to SM4) btm_sec_l2cap_access_req rspd. authenticated: x%x, enc: x%x\n",
+ (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED), (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED));
+ /* SM4, but we do not know for sure which level of security we need.
+ * as long as we have a link key, it's OK */
+ if ((0 == (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))
+ || (0 == (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) {
+ rc = BTM_DELAY_CHECK;
+ /*
+ 2046 may report HCI_Encryption_Change and L2C Connection Request out of sequence
+ because of data path issues. Delay this disconnect a little bit
+ */
+ BTM_TRACE_API("%s peer should have initiated security process by now (SM4 to SM4)\n", __func__);
+ p_dev_rec->p_callback = p_callback;
+ p_dev_rec->sec_state = BTM_SEC_STATE_DELAY_FOR_ENC;
+ (*p_callback) (bd_addr, transport, p_ref_data, rc);
+
+ return BTM_SUCCESS;
+ }
+ }
+
+ p_dev_rec->p_callback = p_callback;
+
+ if (p_dev_rec->last_author_service_id == BTM_SEC_NO_LAST_SERVICE_ID
+ || p_dev_rec->last_author_service_id != p_dev_rec->p_cur_service->service_id) {
+ /* Although authentication and encryption are per connection
+ ** authorization is per access request. For example when serial connection
+ ** is up and authorized and client requests to read file (access to other
+ ** scn), we need to request user's permission again.
+ */
+ p_dev_rec->sec_flags &= ~BTM_SEC_AUTHORIZED;
+ }
+
+ if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) {
+ if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) &&
+ (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ /* BTM_LKEY_TYPE_AUTH_COMB_P_256 is the only acceptable key in this case */
+ if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) != 0) {
+ p_dev_rec->sm4 |= BTM_SM4_UPGRADE;
+ }
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED |
+ BTM_SEC_AUTHENTICATED);
+ BTM_TRACE_DEBUG ("%s: sec_flags:0x%x", __FUNCTION__, p_dev_rec->sec_flags);
+ } else {
+ /* If we already have a link key to the connected peer, is it secure enough? */
+ btm_sec_check_upgrade(p_dev_rec, is_originator);
+ }
+ }
+
+ BTM_TRACE_EVENT ("%s() PSM:%d Handle:%d State:%d Flags: 0x%x Required: 0x%x Service ID:%d\n",
+ __func__, psm, handle, p_dev_rec->sec_state, p_dev_rec->sec_flags,
+ p_dev_rec->security_required, p_dev_rec->p_cur_service->service_id);
+
+ if ((rc = btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED) {
+ p_dev_rec->p_callback = NULL;
+ (*p_callback) (bd_addr, transport, p_dev_rec->p_ref_data, (UINT8)rc);
+ }
+
+ return (rc);
+#else
+ return BTM_MODE_UNSUPPORTED;
+#endif ///SMP_INCLUDED == TRUE
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_mx_access_request
+**
+** Description This function is called by all Multiplexing Protocols during
+** establishing connection to or from peer device to grant
+** permission to establish application connection.
+**
+** Parameters: bd_addr - Address of the peer device
+** psm - L2CAP PSM
+** is_originator - TRUE if protocol above L2CAP originates
+** connection
+** mx_proto_id - protocol ID of the multiplexer
+** mx_chan_id - multiplexer channel to reach application
+** p_callback - Pointer to callback function called if
+** this function returns PENDING after required
+** procedures are completed
+** p_ref_data - Pointer to any reference data needed by the
+** the callback function.
+**
+** Returns BTM_CMD_STARTED
+**
+*******************************************************************************/
+tBTM_STATUS btm_sec_mx_access_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_originator,
+ UINT32 mx_proto_id, UINT32 mx_chan_id,
+ tBTM_SEC_CALLBACK *p_callback, void *p_ref_data)
+{
+#if (SMP_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_SEC_SERV_REC *p_serv_rec;
+ tBTM_STATUS rc;
+ UINT16 security_required;
+ BOOLEAN transport = FALSE;/* should check PSM range in LE connection oriented L2CAP connection */
+
+ BTM_TRACE_DEBUG ("%s() is_originator: %d\n", __func__, is_originator);
+ /* Find or get oldest record */
+ p_dev_rec = btm_find_or_alloc_dev (bd_addr);
+
+ /* Find the service record for the PSM */
+ p_serv_rec = btm_sec_find_mx_serv (is_originator, psm, mx_proto_id, mx_chan_id);
+
+ /* If there is no application registered with this PSM do not allow connection */
+ if (!p_serv_rec) {
+ if (p_callback) {
+ (*p_callback) (bd_addr, transport, p_ref_data, BTM_MODE_UNSUPPORTED);
+ }
+
+ BTM_TRACE_ERROR ("Security Manager: MX service not found PSM:%d Proto:%d SCN:%d\n",
+ psm, mx_proto_id, mx_chan_id);
+ return BTM_NO_RESOURCES;
+ }
+
+ if ((btm_cb.security_mode == BTM_SEC_MODE_SC) && (!btm_sec_is_serv_level0(psm))) {
+ security_required = btm_sec_set_serv_level4_flags (p_serv_rec->security_flags,
+ is_originator);
+ } else {
+ security_required = p_serv_rec->security_flags;
+ }
+
+ /* there are some devices (moto phone) which connects to several services at the same time */
+ /* we will process one after another */
+ if ( (p_dev_rec->p_callback) || (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) ) {
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_EVENT ("%s() service PSM:%d Proto:%d SCN:%d delayed state: %s\n", __func__,
+ psm, mx_proto_id, mx_chan_id, btm_pair_state_descr(btm_cb.pairing_state));
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ rc = BTM_CMD_STARTED;
+
+ if ((btm_cb.security_mode == BTM_SEC_MODE_UNDEFINED ||
+ btm_cb.security_mode == BTM_SEC_MODE_NONE ||
+ btm_cb.security_mode == BTM_SEC_MODE_SERVICE ||
+ btm_cb.security_mode == BTM_SEC_MODE_LINK) ||
+ (BTM_SM4_KNOWN == p_dev_rec->sm4) || (BTM_SEC_IS_SM4(p_dev_rec->sm4) &&
+ (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == FALSE))) {
+ /* legacy mode - local is legacy or local is lisbon/peer is legacy
+ * or SM4 with no possibility of link key upgrade */
+ if (is_originator) {
+ if (((security_required & BTM_SEC_OUT_FLAGS) == 0) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_AUTHENTICATE) && btm_dev_authenticated(p_dev_rec))) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) == (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) && btm_dev_encrypted(p_dev_rec)))
+ ) {
+ rc = BTM_SUCCESS;
+ }
+ } else {
+ if (((security_required & BTM_SEC_IN_FLAGS) == 0) ||
+ ((((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHENTICATE) && btm_dev_authenticated(p_dev_rec))) ||
+ (((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHORIZE) && (btm_dev_authorized(p_dev_rec) || btm_serv_trusted(p_dev_rec, p_serv_rec))) ||
+ (((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_AUTHENTICATE)) && ((btm_dev_authorized(p_dev_rec) || btm_serv_trusted(p_dev_rec, p_serv_rec)) && btm_dev_authenticated(p_dev_rec))) ||
+ (((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT)) && ((btm_dev_authorized(p_dev_rec) || btm_serv_trusted(p_dev_rec, p_serv_rec)) && btm_dev_encrypted(p_dev_rec))) ||
+ ((((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) && btm_dev_encrypted(p_dev_rec)))
+ ) {
+ // Check for 16 digits (or MITM)
+ if (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == 0) ||
+ (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == BTM_SEC_IN_MIN_16_DIGIT_PIN) && btm_dev_16_digit_authenticated(p_dev_rec))) {
+ rc = BTM_SUCCESS;
+ }
+ }
+ }
+ if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) &&
+ (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ rc = BTM_CMD_STARTED;
+ }
+ }
+
+ if (rc == BTM_SUCCESS) {
+ BTM_TRACE_EVENT("%s: allow to bypass, checking authorization\n", __FUNCTION__);
+ /* the security in BTM_SEC_IN_FLAGS is fullfilled so far, check the requirements in */
+ /* btm_sec_execute_procedure */
+ if ((is_originator && (p_serv_rec->security_flags & BTM_SEC_OUT_AUTHORIZE)) ||
+ (!is_originator && (p_serv_rec->security_flags & BTM_SEC_IN_AUTHORIZE))) {
+ BTM_TRACE_EVENT("%s: still need authorization\n", __FUNCTION__);
+ rc = BTM_CMD_STARTED;
+ }
+ }
+
+ /* Check whether there is a pending security procedure, if so we should always queue */
+ /* the new security request */
+ if (p_dev_rec->sec_state != BTM_SEC_STATE_IDLE) {
+ BTM_TRACE_EVENT("%s: There is a pending security procedure\n", __FUNCTION__);
+ rc = BTM_CMD_STARTED;
+ }
+ if (rc == BTM_CMD_STARTED) {
+ BTM_TRACE_EVENT("%s: call btm_sec_queue_mx_request\n", __FUNCTION__);
+ btm_sec_queue_mx_request (bd_addr, psm, is_originator, mx_proto_id,
+ mx_chan_id, p_callback, p_ref_data);
+ } else { /* rc == BTM_SUCCESS */
+ /* access granted */
+ if (p_callback) {
+ (*p_callback) (bd_addr, transport, p_ref_data, (UINT8)rc);
+ }
+ }
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_EVENT("%s: return with rc = 0x%02x in delayed state %s\n", __FUNCTION__, rc,
+ btm_pair_state_descr(btm_cb.pairing_state));
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ return rc;
+ }
+
+ if ((!is_originator) && ((security_required & BTM_SEC_MODE4_LEVEL4) ||
+ (btm_cb.security_mode == BTM_SEC_MODE_SC))) {
+ BOOLEAN local_supports_sc = controller_get_interface()->supports_secure_connections();
+ /* acceptor receives service connection establishment Request for */
+ /* Secure Connections Only service */
+ if (!(local_supports_sc) || !(p_dev_rec->remote_supports_secure_connections)) {
+ BTM_TRACE_DEBUG("%s: SC only service,local_support_for_sc %d,\n"
+ "remote_support_for_sc %d: fail pairing\n", __FUNCTION__,
+ local_supports_sc, p_dev_rec->remote_supports_secure_connections);
+
+ if (p_callback) {
+ (*p_callback) (bd_addr, transport, (void *)p_ref_data,
+ BTM_MODE4_LEVEL4_NOT_SUPPORTED);
+ }
+
+ return (BTM_MODE4_LEVEL4_NOT_SUPPORTED);
+ }
+ }
+
+ p_dev_rec->p_cur_service = p_serv_rec;
+ p_dev_rec->security_required = security_required;
+
+ if (btm_cb.security_mode == BTM_SEC_MODE_SP ||
+ btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+ btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) {
+ if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) &&
+ (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ /* BTM_LKEY_TYPE_AUTH_COMB_P_256 is the only acceptable key in this case */
+ if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) != 0) {
+ p_dev_rec->sm4 |= BTM_SM4_UPGRADE;
+ }
+
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED |
+ BTM_SEC_AUTHENTICATED);
+ BTM_TRACE_DEBUG("%s: sec_flags:0x%x\n", __FUNCTION__, p_dev_rec->sec_flags);
+ } else {
+ /* If we already have a link key, check if that link key is good enough */
+ btm_sec_check_upgrade(p_dev_rec, is_originator);
+ }
+ }
+ }
+
+ p_dev_rec->is_originator = is_originator;
+ p_dev_rec->p_callback = p_callback;
+ p_dev_rec->p_ref_data = p_ref_data;
+
+ /* Although authentication and encryption are per connection */
+ /* authorization is per access request. For example when serial connection */
+ /* is up and authorized and client requests to read file (access to other */
+ /* scn, we need to request user's permission again. */
+ p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED);
+
+ BTM_TRACE_EVENT ("%s() proto_id:%d chan_id:%d State:%d Flags:0x%x Required:0x%x Service ID:%d\n",
+ __func__, mx_proto_id, mx_chan_id, p_dev_rec->sec_state, p_dev_rec->sec_flags,
+ p_dev_rec->security_required, p_dev_rec->p_cur_service->service_id);
+
+ if ((rc = btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED) {
+ if (p_callback) {
+ p_dev_rec->p_callback = NULL;
+ (*p_callback) (bd_addr, transport, p_ref_data, (UINT8)rc);
+ }
+ }
+
+ return rc;
+#else
+ return BTM_MODE_UNSUPPORTED;
+#endif ///SMP_INCLUDED == TRUE
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_conn_req
+**
+** Description This function is when the peer device is requesting
+** connection
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+void btm_sec_conn_req (UINT8 *bda, UINT8 *dc)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda);
+ /* Some device may request a connection before we are done with the HCI_Reset sequence */
+ if (!controller_get_interface()->get_is_ready()) {
+ BTM_TRACE_ERROR ("Security Manager: connect request when device not ready\n");
+ btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE);
+ return;
+ }
+
+ /* Security guys wants us not to allow connection from not paired devices */
+
+ /* Check if connection is allowed for only paired devices */
+ if (btm_cb.connect_only_paired) {
+ if (!p_dev_rec || !(p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)) {
+ BTM_TRACE_ERROR ("Security Manager: connect request from non-paired device\n");
+ btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE);
+ return;
+ }
+ }
+
+#if BTM_ALLOW_CONN_IF_NONDISCOVER == FALSE
+ /* If non-discoverable, only allow known devices to connect */
+ if (btm_cb.btm_inq_vars.discoverable_mode == BTM_NON_DISCOVERABLE) {
+ if (!p_dev_rec) {
+ BTM_TRACE_ERROR ("Security Manager: connect request from not paired device\n");
+ btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE);
+ return;
+ }
+ }
+#endif
+
+ if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ && (!memcmp (btm_cb.pairing_bda, bda, BD_ADDR_LEN))) {
+ BTM_TRACE_ERROR ("Security Manager: reject connect request from bonding device\n");
+
+ /* incoming connection from bonding device is rejected */
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_REJECTED_CONNECT;
+ btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE);
+ return;
+ }
+
+ /* Host is not interested or approved connection. Save BDA and DC and */
+ /* pass request to L2CAP */
+ memcpy (btm_cb.connecting_bda, bda, BD_ADDR_LEN);
+ memcpy (btm_cb.connecting_dc, dc, DEV_CLASS_LEN);
+
+ if (l2c_link_hci_conn_req (bda)) {
+ if (!p_dev_rec) {
+ /* accept the connection -> allocate a device record */
+ p_dev_rec = btm_sec_alloc_dev (bda);
+ }
+ if (p_dev_rec) {
+ p_dev_rec->sm4 |= BTM_SM4_CONN_PEND;
+ }
+ }
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_sec_bond_cancel_complete
+**
+** Description This function is called to report bond cancel complete
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static void btm_sec_bond_cancel_complete (void)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) ||
+ (BTM_PAIR_STATE_WAIT_LOCAL_PIN == btm_cb.pairing_state &&
+ BTM_PAIR_FLAGS_WE_STARTED_DD & btm_cb.pairing_flags) ||
+ (btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME &&
+ BTM_PAIR_FLAGS_WE_CANCEL_DD & btm_cb.pairing_flags)) {
+ /* for dedicated bonding in legacy mode, authentication happens at "link level"
+ * btm_sec_connected is called with failed status.
+ * In theory, the code that handles is_pairing_device/TRUE should clean out security related code.
+ * However, this function may clean out the security related flags and btm_sec_connected would not know
+ * this function also needs to do proper clean up.
+ */
+ if ((p_dev_rec = btm_find_dev (btm_cb.pairing_bda)) != NULL) {
+ p_dev_rec->security_required = BTM_SEC_NONE;
+ }
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+ /* Notify application that the cancel succeeded */
+ if (btm_cb.api.p_bond_cancel_cmpl_callback) {
+ btm_cb.api.p_bond_cancel_cmpl_callback(BTM_SUCCESS);
+ }
+ }
+}
+#endif ///SMP_INCLUDED == TRUE
+
+
+/*******************************************************************************
+**
+** Function btm_create_conn_cancel_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the create connection cancel
+** command.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_create_conn_cancel_complete (UINT8 *p)
+{
+ UINT8 status;
+
+ STREAM_TO_UINT8 (status, p);
+ //BTM_TRACE_EVENT ("btm_create_conn_cancel_complete(): in State: %s status:%d\n",
+ // btm_pair_state_descr(btm_cb.pairing_state), status);
+
+ /* if the create conn cancel cmd was issued by the bond cancel,
+ ** the application needs to be notified that bond cancel succeeded
+ */
+ switch (status) {
+ case HCI_SUCCESS:
+#if (SMP_INCLUDED == TRUE)
+ btm_sec_bond_cancel_complete();
+#endif ///SMP_INCLUDED == TRUE
+ break;
+ case HCI_ERR_CONNECTION_EXISTS:
+ case HCI_ERR_NO_CONNECTION:
+ default:
+ /* Notify application of the error */
+ if (btm_cb.api.p_bond_cancel_cmpl_callback) {
+ btm_cb.api.p_bond_cancel_cmpl_callback(BTM_ERR_PROCESSING);
+ }
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_check_pending_reqs
+**
+** Description This function is called at the end of the security procedure
+** to let L2CAP and RFCOMM know to re-submit any pending requests
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+void btm_sec_check_pending_reqs (void)
+{
+ tBTM_SEC_QUEUE_ENTRY *p_e;
+ fixed_queue_t *bq;
+
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE) {
+ /* First, resubmit L2CAP requests */
+ if (btm_cb.sec_req_pending) {
+ btm_cb.sec_req_pending = FALSE;
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ l2cu_resubmit_pending_sec_req (NULL);
+#endif ///SMP_INCLUDED == TRUE
+ }
+
+ /* Now, re-submit anything in the mux queue */
+ bq = btm_cb.sec_pending_q;
+
+ btm_cb.sec_pending_q = fixed_queue_new(QUEUE_SIZE_MAX);
+
+
+ while ((p_e = (tBTM_SEC_QUEUE_ENTRY *)fixed_queue_dequeue(bq, 0)) != NULL) {
+ /* Check that the ACL is still up before starting security procedures */
+ if (btm_bda_to_acl(p_e->bd_addr, p_e->transport) != NULL) {
+ if (p_e->psm != 0) {
+ BTM_TRACE_EVENT("%s PSM:0x%04x Is_Orig:%u mx_proto_id:%u mx_chan_id:%u\n",
+ __FUNCTION__, p_e->psm, p_e->is_orig,
+ p_e->mx_proto_id, p_e->mx_chan_id);
+
+ btm_sec_mx_access_request (p_e->bd_addr, p_e->psm, p_e->is_orig,
+ p_e->mx_proto_id, p_e->mx_chan_id,
+ p_e->p_callback, p_e->p_ref_data);
+ } else {
+ BTM_SetEncryption(p_e->bd_addr, p_e->transport, p_e->p_callback,
+ p_e->p_ref_data);
+ }
+ }
+
+ osi_free (p_e);
+ }
+ fixed_queue_free(bq, NULL);
+ }
+}
+#endif ///SMP_INCLUDED == TRUE
+
+
+/*******************************************************************************
+**
+** Function btm_sec_init
+**
+** Description This function is on the SEC startup
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+void btm_sec_init (UINT8 sec_mode)
+{
+ btm_cb.security_mode = sec_mode;
+ memset (btm_cb.pairing_bda, 0xff, BD_ADDR_LEN);
+ btm_cb.max_collision_delay = BTM_SEC_MAX_COLLISION_DELAY;
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_sec_device_down
+**
+** Description This function should be called when device is disabled or
+** turned off
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+void btm_sec_device_down (void)
+{
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_EVENT ("%s() State: %s\n", __func__, btm_pair_state_descr(btm_cb.pairing_state));
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+}
+#endif ///SMP_INCLUDED == TRUE
+
+
+/*******************************************************************************
+**
+** Function btm_sec_dev_reset
+**
+** Description This function should be called after device reset
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_dev_reset (void)
+{
+ if (controller_get_interface()->supports_simple_pairing()) {
+ /* set the default IO capabilities */
+ btm_cb.devcb.loc_io_caps = BTM_LOCAL_IO_CAPS;
+ /* add mx service to use no security */
+ BTM_SetSecurityLevel(FALSE, "RFC_MUX\n", BTM_SEC_SERVICE_RFC_MUX,
+ BTM_SEC_NONE, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 0);
+ } else {
+ btm_cb.security_mode = BTM_SEC_MODE_SERVICE;
+ }
+
+ BTM_TRACE_DEBUG ("btm_sec_dev_reset sec mode: %d\n", btm_cb.security_mode);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_abort_access_req
+**
+** Description This function is called by the L2CAP or RFCOMM to abort
+** the pending operation.
+**
+** Parameters: bd_addr - Address of the peer device
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_abort_access_req (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+
+ if (!p_dev_rec) {
+ return;
+ }
+
+ if ((p_dev_rec->sec_state != BTM_SEC_STATE_AUTHORIZING)
+ && (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING)) {
+ return;
+ }
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ p_dev_rec->p_callback = NULL;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_dd_create_conn
+**
+** Description This function is called to create the ACL connection for
+** the dedicated boding process
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static tBTM_STATUS btm_sec_dd_create_conn (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR);
+ if (p_lcb && (p_lcb->link_state == LST_CONNECTED || p_lcb->link_state == LST_CONNECTING)) {
+ BTM_TRACE_WARNING("%s Connection already exists\n", __func__);
+ return BTM_CMD_STARTED;
+ }
+
+ /* Make sure an L2cap link control block is available */
+ if (!p_lcb && (p_lcb = l2cu_allocate_lcb (p_dev_rec->bd_addr, TRUE, BT_TRANSPORT_BR_EDR)) == NULL) {
+ BTM_TRACE_WARNING ("Security Manager: failed allocate LCB [%02x%02x%02x%02x%02x%02x]\n",
+ p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2],
+ p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]);
+
+ return (BTM_NO_RESOURCES);
+ }
+
+ /* set up the control block to indicated dedicated bonding */
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE;
+
+ if (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == FALSE) {
+ BTM_TRACE_WARNING ("Security Manager: failed create [%02x%02x%02x%02x%02x%02x]\n",
+ p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2],
+ p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]);
+
+ l2cu_release_lcb(p_lcb);
+ return (BTM_NO_RESOURCES);
+ }
+
+ btm_acl_update_busy_level (BTM_BLI_PAGE_EVT);
+
+ BTM_TRACE_DEBUG ("Security Manager: btm_sec_dd_create_conn [%02x%02x%02x%02x%02x%02x]\n",
+ p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2],
+ p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]);
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
+ return (BTM_CMD_STARTED);
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_sec_rmt_name_request_complete
+**
+** Description This function is called when remote name was obtained from
+** the peer device
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+void btm_sec_rmt_name_request_complete (UINT8 *p_bd_addr, UINT8 *p_bd_name, UINT8 status)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+ int i;
+ DEV_CLASS dev_class;
+ UINT8 old_sec_state;
+ UINT8 res;
+
+ BTM_TRACE_EVENT ("btm_sec_rmt_name_request_complete\n");
+ if (((p_bd_addr == NULL) && !BTM_ACL_IS_CONNECTED(btm_cb.connecting_bda))
+ || ((p_bd_addr != NULL) && !BTM_ACL_IS_CONNECTED(p_bd_addr))) {
+ btm_acl_resubmit_page();
+ }
+
+ /* If remote name request failed, p_bd_addr is null and we need to search */
+ /* based on state assuming that we are doing 1 at a time */
+ if (p_bd_addr) {
+ p_dev_rec = btm_find_dev (p_bd_addr);
+ } else {
+ list_node_t *p_node = NULL;
+ for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
+ p_dev_rec = list_node(p_node);
+ if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE)
+ && (p_dev_rec->sec_state == BTM_SEC_STATE_GETTING_NAME)) {
+ p_bd_addr = p_dev_rec->bd_addr;
+ break;
+ }
+ }
+ if (!p_bd_addr) {
+ p_dev_rec = NULL;
+ }
+ }
+
+
+ /* Commenting out trace due to obf/compilation problems.
+ */
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ if (!p_bd_name) {
+ p_bd_name = (UINT8 *)"";
+ }
+
+ if (p_dev_rec) {
+ BTM_TRACE_EVENT ("Security Manager: rmt_name_complete PairState: %s RemName: %s status: %d State:%d p_dev_rec: %p \n",
+ btm_pair_state_descr (btm_cb.pairing_state), p_bd_name,
+ status, p_dev_rec->sec_state, p_dev_rec);
+ } else {
+ BTM_TRACE_EVENT ("Security Manager: rmt_name_complete PairState: %s RemName: %s status: %d\n",
+ btm_pair_state_descr (btm_cb.pairing_state), p_bd_name,
+ status);
+ }
+#endif
+
+ if (p_dev_rec) {
+ old_sec_state = p_dev_rec->sec_state;
+ if (status == HCI_SUCCESS) {
+ BCM_STRNCPY_S ((char *)p_dev_rec->sec_bd_name, (char *)p_bd_name, BTM_MAX_REM_BD_NAME_LEN);
+ p_dev_rec->sec_bd_name[BTM_MAX_REM_BD_NAME_LEN] = '\0';
+ p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
+ BTM_TRACE_EVENT ("setting BTM_SEC_NAME_KNOWN sec_flags:0x%x\n", p_dev_rec->sec_flags);
+ } else {
+ /* Notify all clients waiting for name to be resolved even if it failed so clients can continue */
+ p_dev_rec->sec_bd_name[0] = '\0';
+ }
+
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_GETTING_NAME) {
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ }
+
+ /* Notify all clients waiting for name to be resolved */
+ for (i = 0; i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++) {
+ if (btm_cb.p_rmt_name_callback[i] && p_bd_addr) {
+ (*btm_cb.p_rmt_name_callback[i])(p_bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name);
+ }
+ }
+ } else {
+ dev_class[0] = 0;
+ dev_class[1] = 0;
+ dev_class[2] = 0;
+
+ /* Notify all clients waiting for name to be resolved even if not found so clients can continue */
+ for (i = 0; i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++) {
+ if (btm_cb.p_rmt_name_callback[i] && p_bd_addr) {
+ (*btm_cb.p_rmt_name_callback[i])(p_bd_addr, dev_class, (UINT8 *)"");
+ }
+ }
+
+ return;
+ }
+
+ /* If we were delaying asking UI for a PIN because name was not resolved, ask now */
+ if ( (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_LOCAL_PIN) && p_bd_addr
+ && (memcmp (btm_cb.pairing_bda, p_bd_addr, BD_ADDR_LEN) == 0) ) {
+ BTM_TRACE_EVENT ("btm_sec_rmt_name_request_complete() delayed pin now being requested flags:0x%x, (p_pin_callback=%p)\n", btm_cb.pairing_flags, btm_cb.api.p_pin_callback);
+
+ if (((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) == 0) &&
+ ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PIN_REQD) == 0) &&
+ btm_cb.api.p_pin_callback) {
+ BTM_TRACE_EVENT ("btm_sec_rmt_name_request_complete() calling pin_callback\n");
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD;
+ (*btm_cb.api.p_pin_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class, p_bd_name,
+ (p_dev_rec->p_cur_service == NULL) ? FALSE
+ : (p_dev_rec->p_cur_service->security_flags & BTM_SEC_IN_MIN_16_DIGIT_PIN));
+ }
+
+ /* Set the same state again to force the timer to be restarted */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_LOCAL_PIN);
+ return;
+ }
+
+ /* Check if we were delaying bonding because name was not resolved */
+ if ( btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME) {
+ if (p_bd_addr && memcmp (btm_cb.pairing_bda, p_bd_addr, BD_ADDR_LEN) == 0) {
+ BTM_TRACE_EVENT ("btm_sec_rmt_name_request_complete() continue bonding sm4: 0x%04x, status:0x%x\n", p_dev_rec->sm4, status);
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_CANCEL_DD) {
+ btm_sec_bond_cancel_complete();
+ return;
+ }
+
+ if (status != HCI_SUCCESS) {
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+ if (btm_cb.api.p_auth_complete_callback)
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, status);
+ return;
+ }
+
+ /* if peer is very old legacy devices, HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT is not reported */
+ if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) {
+ /* set the KNOWN flag only if BTM_PAIR_FLAGS_REJECTED_CONNECT is not set.*/
+ /* If it is set, there may be a race condition */
+ BTM_TRACE_DEBUG ("btm_sec_rmt_name_request_complete IS_SM4_UNKNOWN Flags:0x%04x\n",
+ btm_cb.pairing_flags);
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) == 0) {
+ p_dev_rec->sm4 |= BTM_SM4_KNOWN;
+ }
+ }
+
+ BTM_TRACE_DEBUG("%s, SM4 Value: %x, Legacy:%d,IS SM4:%d, Unknown:%d\n", __FUNCTION__,
+ p_dev_rec->sm4, BTM_SEC_IS_SM4_LEGACY(p_dev_rec->sm4),
+ BTM_SEC_IS_SM4(p_dev_rec->sm4), BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4));
+
+ /* BT 2.1 or carkit, bring up the connection to force the peer to request PIN.
+ ** Else prefetch (btm_sec_check_prefetch_pin will do the prefetching if needed)
+ */
+ if ((p_dev_rec->sm4 != BTM_SM4_KNOWN) || !btm_sec_check_prefetch_pin(p_dev_rec)) {
+ /* if we rejected incoming connection request, we have to wait HCI_Connection_Complete event */
+ /* before originating */
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) {
+ BTM_TRACE_WARNING ("btm_sec_rmt_name_request_complete: waiting HCI_Connection_Complete after rejecting connection\n");
+ }
+ /* Both we and the peer are 2.1 - continue to create connection */
+ else if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED) {
+ BTM_TRACE_WARNING ("btm_sec_rmt_name_request_complete: failed to start connection\n");
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+ if (btm_cb.api.p_auth_complete_callback) {
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, HCI_ERR_MEMORY_FULL);
+ }
+ }
+ }
+ return;
+ } else {
+ BTM_TRACE_WARNING ("btm_sec_rmt_name_request_complete: wrong BDA, retry with pairing BDA\n");
+
+ BTM_ReadRemoteDeviceName (btm_cb.pairing_bda, NULL, BT_TRANSPORT_BR_EDR);
+ return;
+ }
+ }
+
+ /* check if we were delaying link_key_callback because name was not resolved */
+ if (p_dev_rec->link_key_not_sent) {
+ /* If HCI connection complete has not arrived, wait for it */
+ if (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE) {
+ return;
+ }
+
+ p_dev_rec->link_key_not_sent = FALSE;
+ btm_send_link_key_notif(p_dev_rec);
+
+ /* If its not us who perform authentication, we should tell stackserver */
+ /* that some authentication has been completed */
+ /* This is required when different entities receive link notification and auth complete */
+ if (!(p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE)) {
+ if (btm_cb.api.p_auth_complete_callback) {
+ res = (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, HCI_SUCCESS);
+ if (res == BTM_SEC_DEV_REC_REMOVED) {
+ p_dev_rec = NULL;
+ }
+ }
+
+ }
+ }
+
+ if(!p_dev_rec) {
+ return;
+ }
+
+ /* If this is a bonding procedure can disconnect the link now */
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) {
+ BTM_TRACE_WARNING ("btm_sec_rmt_name_request_complete (none/ce)\n");
+ p_dev_rec->security_required &= ~(BTM_SEC_OUT_AUTHENTICATE);
+ l2cu_start_post_bond_timer(p_dev_rec->hci_handle);
+ return;
+ }
+
+ if (old_sec_state != BTM_SEC_STATE_GETTING_NAME) {
+ return;
+ }
+
+ /* If get name failed, notify the waiting layer */
+ if (status != HCI_SUCCESS) {
+ btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING, FALSE);
+ return;
+ }
+
+ if (p_dev_rec->sm4 & BTM_SM4_REQ_PEND) {
+ BTM_TRACE_EVENT ("waiting for remote features!!\n");
+ return;
+ }
+
+ /* Remote Name succeeded, execute the next security procedure, if any */
+ status = (UINT8)btm_sec_execute_procedure (p_dev_rec);
+
+ /* If result is pending reply from the user or from the device is pending */
+ if (status == BTM_CMD_STARTED) {
+ return;
+ }
+
+ /* There is no next procedure or start of procedure failed, notify the waiting layer */
+ btm_sec_dev_rec_cback_event (p_dev_rec, status, FALSE);
+}
+#endif ///SMP_INCLUDED == TRUE
+
+
+/*******************************************************************************
+**
+** Function btm_sec_rmt_host_support_feat_evt
+**
+** Description This function is called when the
+** HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT is received
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_rmt_host_support_feat_evt (UINT8 *p)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BD_ADDR bd_addr; /* peer address */
+ BD_FEATURES features;
+
+ STREAM_TO_BDADDR (bd_addr, p);
+ p_dev_rec = btm_find_or_alloc_dev (bd_addr);
+
+ BTM_TRACE_EVENT ("btm_sec_rmt_host_support_feat_evt sm4: 0x%x p[0]: 0x%x\n", p_dev_rec->sm4, p[0]);
+
+ if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) {
+ p_dev_rec->sm4 = BTM_SM4_KNOWN;
+ STREAM_TO_ARRAY(features, p, HCI_FEATURE_BYTES_PER_PAGE);
+ if (HCI_SSP_HOST_SUPPORTED(features)) {
+ p_dev_rec->sm4 = BTM_SM4_TRUE;
+ }
+ BTM_TRACE_EVENT ("btm_sec_rmt_host_support_feat_evt sm4: 0x%x features[0]: 0x%x\n", p_dev_rec->sm4, features[0]);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_io_capabilities_req
+**
+** Description This function is called when LM request for the IO
+** capability of the local device and
+** if the OOB data is present for the device in the event
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+void btm_io_capabilities_req (UINT8 *p)
+{
+ tBTM_SP_IO_REQ evt_data;
+ UINT8 err_code = 0;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BOOLEAN is_orig = TRUE;
+ UINT8 callback_rc = BTM_SUCCESS;
+
+ STREAM_TO_BDADDR (evt_data.bd_addr, p);
+
+ /* setup the default response according to compile options */
+ /* assume that the local IO capability does not change
+ * loc_io_caps is initialized with the default value */
+ evt_data.io_cap = btm_cb.devcb.loc_io_caps;
+ evt_data.oob_data = BTM_OOB_NONE;
+ evt_data.auth_req = BTM_DEFAULT_AUTH_REQ;
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_EVENT("%s: State: %s\n", __FUNCTION__, btm_pair_state_descr(btm_cb.pairing_state));
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ p_dev_rec = btm_find_or_alloc_dev (evt_data.bd_addr);
+
+ BTM_TRACE_DEBUG("%s:Security mode: %d, Num Read Remote Feat pages: %d\n", __FUNCTION__,
+ btm_cb.security_mode, p_dev_rec->num_read_pages);
+
+ if ((btm_cb.security_mode == BTM_SEC_MODE_SC) && (p_dev_rec->num_read_pages == 0)) {
+ BTM_TRACE_EVENT("%s: Device security mode is SC only.\n"
+ "To continue need to know remote features.\n", __FUNCTION__);
+
+ p_dev_rec->remote_features_needed = TRUE;
+ return;
+ }
+
+ p_dev_rec->sm4 |= BTM_SM4_TRUE;
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_EVENT("%s: State: %s Flags: 0x%04x p_cur_service: %p\n",
+ __FUNCTION__, btm_pair_state_descr(btm_cb.pairing_state),
+ btm_cb.pairing_flags, p_dev_rec->p_cur_service);
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ if (p_dev_rec->p_cur_service) {
+ BTM_TRACE_EVENT("%s: cur_service psm: 0x%04x, security_flags: 0x%04x\n",
+ __FUNCTION__, p_dev_rec->p_cur_service->psm,
+ p_dev_rec->p_cur_service->security_flags);
+ }
+
+ switch (btm_cb.pairing_state) {
+ /* initiator connecting */
+ case BTM_PAIR_STATE_IDLE:
+ //TODO: Handle Idle pairing state
+ //security_required = p_dev_rec->security_required;
+ break;
+
+ /* received IO capability response already->acceptor */
+ case BTM_PAIR_STATE_INCOMING_SSP:
+ is_orig = FALSE;
+
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_PEER_STARTED_DD) {
+ /* acceptor in dedicated bonding */
+ evt_data.auth_req = BTM_DEFAULT_DD_AUTH_REQ;
+ }
+ break;
+
+ /* initiator, at this point it is expected to be dedicated bonding
+ initiated by local device */
+ case BTM_PAIR_STATE_WAIT_PIN_REQ:
+ if (!memcmp (evt_data.bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN)) {
+ evt_data.auth_req = BTM_DEFAULT_DD_AUTH_REQ;
+ } else {
+ err_code = HCI_ERR_HOST_BUSY_PAIRING;
+ }
+ break;
+
+ /* any other state is unexpected */
+ default:
+ err_code = HCI_ERR_HOST_BUSY_PAIRING;
+ BTM_TRACE_ERROR("%s: Unexpected Pairing state received %d\n", __FUNCTION__,
+ btm_cb.pairing_state);
+ break;
+ }
+
+ if (btm_cb.pairing_disabled) {
+ /* pairing is not allowed */
+ BTM_TRACE_DEBUG("%s: Pairing is not allowed -> fail pairing.\n", __FUNCTION__);
+ err_code = HCI_ERR_PAIRING_NOT_ALLOWED;
+ } else if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ BOOLEAN local_supports_sc = controller_get_interface()->supports_secure_connections();
+ /* device in Secure Connections Only mode */
+ if (!(local_supports_sc) || !(p_dev_rec->remote_supports_secure_connections)) {
+ BTM_TRACE_DEBUG("%s: SC only service, local_support_for_sc %d,\n"
+ " remote_support_for_sc 0x%02x -> fail pairing\n", __FUNCTION__,
+ local_supports_sc, p_dev_rec->remote_supports_secure_connections);
+
+ err_code = HCI_ERR_PAIRING_NOT_ALLOWED;
+ }
+ }
+
+ if (err_code != 0) {
+ /* coverity[uninit_use_in_call]
+ Event uninit_use_in_call: Using uninitialized element of array "evt_data.bd_addr" in call to function "memcmp"
+ False-positive: evt_data.bd_addr is set at the beginning with: STREAM_TO_BDADDR (evt_data.bd_addr, p);
+ */
+ btsnd_hcic_io_cap_req_neg_reply(evt_data.bd_addr, err_code);
+ return;
+ }
+
+ evt_data.is_orig = is_orig;
+
+ if (is_orig) {
+ /* local device initiated the pairing non-bonding -> use p_cur_service */
+ if (!(btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) &&
+ p_dev_rec->p_cur_service &&
+ (p_dev_rec->p_cur_service->security_flags & BTM_SEC_OUT_AUTHENTICATE)) {
+ if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ /* SC only mode device requires MITM protection */
+ evt_data.auth_req = BTM_AUTH_SP_YES;
+ } else {
+ evt_data.auth_req = (p_dev_rec->p_cur_service->security_flags &
+ BTM_SEC_OUT_MITM) ? BTM_AUTH_SP_YES : BTM_AUTH_SP_NO;
+ }
+ }
+ }
+
+ /* Notify L2CAP to increase timeout */
+ l2c_pin_code_request (evt_data.bd_addr);
+
+ memcpy (btm_cb.pairing_bda, evt_data.bd_addr, BD_ADDR_LEN);
+
+ /* coverity[uninit_use_in_call]
+ Event uninit_use_in_call: Using uninitialized element of array "evt_data.bd_addr" in call to function "memcmp"
+ False-positive: False-positive: evt_data.bd_addr is set at the beginning with: STREAM_TO_BDADDR (evt_data.bd_addr, p);
+ */
+ if (!memcmp (evt_data.bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN)) {
+ memcpy (p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN);
+ }
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS);
+
+ callback_rc = BTM_SUCCESS;
+ if (p_dev_rec->sm4 & BTM_SM4_UPGRADE) {
+ p_dev_rec->sm4 &= ~BTM_SM4_UPGRADE;
+
+ /* link key upgrade: always use SPGB_YES - assuming we want to save the link key */
+ evt_data.auth_req = BTM_AUTH_SPGB_YES;
+ } else if (btm_cb.api.p_sp_callback) {
+ /* the callback function implementation may change the IO capability... */
+ callback_rc = (*btm_cb.api.p_sp_callback) (BTM_SP_IO_REQ_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+ }
+
+#if BTM_OOB_INCLUDED == TRUE
+ if ((callback_rc == BTM_SUCCESS) || (BTM_OOB_UNKNOWN != evt_data.oob_data))
+#else
+ if (callback_rc == BTM_SUCCESS)
+#endif
+ {
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)) {
+ evt_data.auth_req = (BTM_AUTH_DD_BOND | (evt_data.auth_req & BTM_AUTH_YN_BIT));
+ }
+
+ if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ /* At this moment we know that both sides are SC capable, device in */
+ /* SC only mode requires MITM for any service so let's set MITM bit */
+ evt_data.auth_req |= BTM_AUTH_YN_BIT;
+ BTM_TRACE_DEBUG("%s: for device in \"SC only\" mode set auth_req to 0x%02x\n",
+ __FUNCTION__, evt_data.auth_req);
+ }
+
+ /* if the user does not indicate "reply later" by setting the oob_data to unknown */
+ /* send the response right now. Save the current IO capability in the control block */
+ btm_cb.devcb.loc_auth_req = evt_data.auth_req;
+ btm_cb.devcb.loc_io_caps = evt_data.io_cap;
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_EVENT("%s: State: %s IO_CAP:%d oob_data:%d auth_req:%d",
+ __FUNCTION__, btm_pair_state_descr(btm_cb.pairing_state), evt_data.io_cap,
+ evt_data.oob_data, evt_data.auth_req);
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ btsnd_hcic_io_cap_req_reply(evt_data.bd_addr, evt_data.io_cap,
+ evt_data.oob_data, evt_data.auth_req);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_io_capabilities_rsp
+**
+** Description This function is called when the IO capability of the
+** specified device is received
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_io_capabilities_rsp (UINT8 *p)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_SP_IO_RSP evt_data;
+
+ STREAM_TO_BDADDR (evt_data.bd_addr, p);
+ STREAM_TO_UINT8 (evt_data.io_cap, p);
+ STREAM_TO_UINT8 (evt_data.oob_data, p);
+ STREAM_TO_UINT8 (evt_data.auth_req, p);
+
+ /* Allocate a new device record or reuse the oldest one */
+ p_dev_rec = btm_find_or_alloc_dev (evt_data.bd_addr);
+
+ /* If no security is in progress, this indicates incoming security */
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE) {
+ memcpy (btm_cb.pairing_bda, evt_data.bd_addr, BD_ADDR_LEN);
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_INCOMING_SSP);
+
+ /* Make sure we reset the trusted mask to help against attacks */
+ BTM_SEC_CLR_TRUSTED_DEVICE(p_dev_rec->trusted_mask);
+
+ /* work around for FW bug */
+ btm_inq_stop_on_ssp();
+ }
+
+ /* Notify L2CAP to increase timeout */
+ l2c_pin_code_request (evt_data.bd_addr);
+
+ /* We must have a device record here.
+ * Use the connecting device's CoD for the connection */
+ /* coverity[uninit_use_in_call]
+ Event uninit_use_in_call: Using uninitialized element of array "evt_data.bd_addr" in call to function "memcmp"
+ FALSE-POSITIVE error from Coverity test-tool. evt_data.bd_addr is set at the beginning with: STREAM_TO_BDADDR (evt_data.bd_addr, p);
+ */
+ if (!memcmp (evt_data.bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN)) {
+ memcpy (p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN);
+ }
+
+ /* peer sets dedicated bonding bit and we did not initiate dedicated bonding */
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_INCOMING_SSP /* peer initiated bonding */
+ && (evt_data.auth_req & BTM_AUTH_DD_BOND) ) { /* and dedicated bonding bit is set */
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PEER_STARTED_DD;
+ }
+
+ /* save the IO capability in the device record */
+ p_dev_rec->rmt_io_caps = evt_data.io_cap;
+ p_dev_rec->rmt_auth_req = evt_data.auth_req;
+
+ if (btm_cb.api.p_sp_callback) {
+ (*btm_cb.api.p_sp_callback) (BTM_SP_IO_RSP_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_proc_sp_req_evt
+**
+** Description This function is called to process/report
+** HCI_USER_CONFIRMATION_REQUEST_EVT
+** or HCI_USER_PASSKEY_REQUEST_EVT
+** or HCI_USER_PASSKEY_NOTIFY_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+#if (CLASSIC_BT_INCLUDED == TRUE)
+void btm_proc_sp_req_evt (tBTM_SP_EVT event, UINT8 *p)
+{
+ tBTM_STATUS status = BTM_ERR_PROCESSING;
+ tBTM_SP_EVT_DATA evt_data;
+ UINT8 *p_bda = evt_data.cfm_req.bd_addr;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ /* All events start with bd_addr */
+ STREAM_TO_BDADDR (p_bda, p);
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_EVENT ("btm_proc_sp_req_evt() BDA: %08x%04x event: 0x%x, State: %s\n",
+ (p_bda[0] << 24) + (p_bda[1] << 16) + (p_bda[2] << 8) + p_bda[3], (p_bda[4] << 8) + p_bda[5],
+ event, btm_pair_state_descr(btm_cb.pairing_state));
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ if ( ((p_dev_rec = btm_find_dev (p_bda)) != NULL)
+ && (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (memcmp (btm_cb.pairing_bda, p_bda, BD_ADDR_LEN) == 0) ) {
+ memcpy (evt_data.cfm_req.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ memcpy (evt_data.cfm_req.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+ BCM_STRCPY_S ((char *)evt_data.cfm_req.bd_name,(char *)p_dev_rec->sec_bd_name);
+
+ switch (event) {
+ case BTM_SP_CFM_REQ_EVT:
+ /* Numeric confirmation. Need user to conf the passkey */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM);
+
+ /* The device record must be allocated in the "IO cap exchange" step */
+ STREAM_TO_UINT32 (evt_data.cfm_req.num_val, p);
+
+ evt_data.cfm_req.just_works = TRUE;
+
+ /* process user confirm req in association with the auth_req param */
+// #if (BTM_LOCAL_IO_CAPS == BTM_IO_CAP_IO)
+ if ( (p_dev_rec->rmt_io_caps == BTM_IO_CAP_IO)
+ && (btm_cb.devcb.loc_io_caps == BTM_IO_CAP_IO)
+ && ((p_dev_rec->rmt_auth_req & BTM_AUTH_SP_YES) || (btm_cb.devcb.loc_auth_req & BTM_AUTH_SP_YES)) ) {
+ /* Both devices are DisplayYesNo and one or both devices want to authenticate
+ -> use authenticated link key */
+ evt_data.cfm_req.just_works = FALSE;
+ }
+// #endif
+ BTM_TRACE_DEBUG ("btm_proc_sp_req_evt() just_works:%d, io loc:%d, rmt:%d, auth loc:%d, rmt:%d\n",
+ evt_data.cfm_req.just_works, btm_cb.devcb.loc_io_caps, p_dev_rec->rmt_io_caps,
+ btm_cb.devcb.loc_auth_req, p_dev_rec->rmt_auth_req);
+
+ evt_data.cfm_req.loc_auth_req = btm_cb.devcb.loc_auth_req;
+ evt_data.cfm_req.rmt_auth_req = p_dev_rec->rmt_auth_req;
+ evt_data.cfm_req.loc_io_caps = btm_cb.devcb.loc_io_caps;
+ evt_data.cfm_req.rmt_io_caps = p_dev_rec->rmt_io_caps;
+ break;
+
+ case BTM_SP_KEY_NOTIF_EVT:
+ /* Passkey notification (other side is a keyboard) */
+ STREAM_TO_UINT32 (evt_data.key_notif.passkey, p);
+
+ BTM_TRACE_DEBUG ("BTM_SP_KEY_NOTIF_EVT: passkey: %u\n", evt_data.key_notif.passkey);
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ break;
+
+ case BTM_SP_KEY_REQ_EVT:
+ /* HCI_USER_PASSKEY_REQUEST_EVT */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_KEY_ENTRY);
+ break;
+ }
+
+ if (btm_cb.api.p_sp_callback) {
+ status = (*btm_cb.api.p_sp_callback) (event, (tBTM_SP_EVT_DATA *)&evt_data);
+ if (status != BTM_NOT_AUTHORIZED) {
+ return;
+ }
+ /* else BTM_NOT_AUTHORIZED means when the app wants to reject the req right now */
+ } else if ( (event == BTM_SP_CFM_REQ_EVT) && (evt_data.cfm_req.just_works == TRUE) ) {
+ /* automatically reply with just works if no sp_cback */
+ status = BTM_SUCCESS;
+ }
+
+ if (event == BTM_SP_CFM_REQ_EVT) {
+ BTM_TRACE_DEBUG ("calling BTM_ConfirmReqReply with status: %d\n", status);
+ BTM_ConfirmReqReply (status, p_bda);
+ } else if (event == BTM_SP_KEY_REQ_EVT) {
+ BTM_PasskeyReqReply(status, p_bda, 0);
+ }
+ return;
+ }
+ /* Something bad. we can only fail this connection */
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+
+ if (BTM_SP_CFM_REQ_EVT == event) {
+ btsnd_hcic_user_conf_reply (p_bda, FALSE);
+ } else if (BTM_SP_KEY_NOTIF_EVT == event) {
+ /* do nothing -> it very unlikely to happen.
+ This event is most likely to be received by a HID host when it first connects to a HID device.
+ Usually the Host initiated the connection in this case.
+ On Mobile platforms, if there's a security process happening,
+ the host probably can not initiate another connection.
+ BTW (PC) is another story. */
+ if (NULL != (p_dev_rec = btm_find_dev (p_bda)) ) {
+ btm_sec_disconnect (p_dev_rec->hci_handle, HCI_ERR_AUTH_FAILURE);
+ }
+ } else {
+ btsnd_hcic_user_passkey_neg_reply(p_bda);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_keypress_notif_evt
+**
+** Description This function is called when a key press notification is
+** received
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_keypress_notif_evt (UINT8 *p)
+{
+ tBTM_SP_KEYPRESS evt_data;
+ UINT8 *p_bda;
+
+ /* parse & report BTM_SP_KEYPRESS_EVT */
+ if (btm_cb.api.p_sp_callback) {
+ p_bda = evt_data.bd_addr;
+
+ STREAM_TO_BDADDR (p_bda, p);
+ evt_data.notif_type = *p;
+
+ (*btm_cb.api.p_sp_callback) (BTM_SP_KEYPRESS_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_simple_pair_complete
+**
+** Description This function is called when simple pairing process is
+** complete
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_simple_pair_complete (UINT8 *p)
+{
+ tBTM_SP_COMPLT evt_data;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ UINT8 status;
+ BOOLEAN disc = FALSE;
+
+ status = *p++;
+ STREAM_TO_BDADDR (evt_data.bd_addr, p);
+
+ if ((p_dev_rec = btm_find_dev (evt_data.bd_addr)) == NULL) {
+ BTM_TRACE_ERROR ("btm_simple_pair_complete() with unknown BDA: %08x%04x\n",
+ (evt_data.bd_addr[0] << 24) + (evt_data.bd_addr[1] << 16) + (evt_data.bd_addr[2] << 8) + evt_data.bd_addr[3],
+ (evt_data.bd_addr[4] << 8) + evt_data.bd_addr[5]);
+ return;
+ }
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_EVENT ("btm_simple_pair_complete() Pair State: %s Status:%d sec_state: %u\n",
+ btm_pair_state_descr(btm_cb.pairing_state), status, p_dev_rec->sec_state);
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ evt_data.status = BTM_ERR_PROCESSING;
+ if (status == HCI_SUCCESS) {
+ evt_data.status = BTM_SUCCESS;
+ p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED;
+ } else {
+ if (status == HCI_ERR_PAIRING_NOT_ALLOWED) {
+ /* The test spec wants the peer device to get this failure code. */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_DISCONNECT);
+
+ /* Change the timer to 1 second */
+ btu_start_timer (&btm_cb.pairing_tle, BTU_TTYPE_USER_FUNC, BT_1SEC_TIMEOUT);
+ } else if (memcmp (btm_cb.pairing_bda, evt_data.bd_addr, BD_ADDR_LEN) == 0) {
+ /* stop the timer */
+ btu_stop_timer (&btm_cb.pairing_tle);
+
+ if (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING) {
+ /* the initiating side: will receive auth complete event. disconnect ACL at that time */
+ disc = TRUE;
+ }
+ } else {
+ disc = TRUE;
+ }
+ }
+
+ /* Let the pairing state stay active, p_auth_complete_callback will report the failure */
+ memcpy (evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ memcpy (evt_data.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+ if (btm_cb.api.p_sp_callback) {
+ (*btm_cb.api.p_sp_callback) (BTM_SP_COMPLT_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+ }
+
+ if (disc) {
+ /* simple pairing failed */
+ /* Avoid sending disconnect on HCI_ERR_PEER_USER */
+ if ((status != HCI_ERR_PEER_USER) && (status != HCI_ERR_CONN_CAUSE_LOCAL_HOST)) {
+ btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE, p_dev_rec->hci_handle);
+ }
+ }
+}
+#endif /* (CLASSIC_BT_INCLUDED == TRUE) */
+#endif ///SMP_INCLUDED == TRUE
+
+
+#if BTM_OOB_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function btm_rem_oob_req
+**
+** Description This function is called to process/report
+** HCI_REMOTE_OOB_DATA_REQUEST_EVT
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_rem_oob_req (UINT8 *p)
+{
+ UINT8 *p_bda;
+ tBTM_SP_RMT_OOB evt_data;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BT_OCTET16 c;
+ BT_OCTET16 r;
+
+ p_bda = evt_data.bd_addr;
+
+ STREAM_TO_BDADDR (p_bda, p);
+
+ BTM_TRACE_EVENT ("btm_rem_oob_req() BDA: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
+
+ if ( (NULL != (p_dev_rec = btm_find_dev (p_bda))) &&
+ btm_cb.api.p_sp_callback) {
+ memcpy (evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ memcpy (evt_data.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN);
+ BCM_STRNCPY_S((char *)evt_data.bd_name, (char *)p_dev_rec->sec_bd_name, BTM_MAX_REM_BD_NAME_LEN);
+ evt_data.bd_name[BTM_MAX_REM_BD_NAME_LEN] = '\0';
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP);
+ if ((*btm_cb.api.p_sp_callback) (BTM_SP_RMT_OOB_EVT, (tBTM_SP_EVT_DATA *)&evt_data) == BTM_NOT_AUTHORIZED) {
+ BTM_RemoteOobDataReply(TRUE, p_bda, c, r);
+ }
+ return;
+ }
+
+ /* something bad. we can only fail this connection */
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+ btsnd_hcic_rem_oob_neg_reply (p_bda);
+}
+
+/*******************************************************************************
+**
+** Function btm_read_local_oob_complete
+**
+** Description This function is called when read local oob data is
+** completed by the LM
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_local_oob_complete (UINT8 *p)
+{
+ tBTM_SP_LOC_OOB evt_data;
+ UINT8 status = *p++;
+
+ BTM_TRACE_EVENT ("btm_read_local_oob_complete:%d\n", status);
+ if (status == HCI_SUCCESS) {
+ evt_data.status = BTM_SUCCESS;
+ STREAM_TO_ARRAY16(evt_data.c, p);
+ STREAM_TO_ARRAY16(evt_data.r, p);
+ } else {
+ evt_data.status = BTM_ERR_PROCESSING;
+ }
+
+ if (btm_cb.api.p_sp_callback) {
+ (*btm_cb.api.p_sp_callback) (BTM_SP_LOC_OOB_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+ }
+}
+#endif /* BTM_OOB_INCLUDED */
+
+/*******************************************************************************
+**
+** Function btm_sec_auth_collision
+**
+** Description This function is called when authentication or encryption
+** needs to be retried at a later time.
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static void btm_sec_auth_collision (UINT16 handle)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ if (!btm_cb.collision_start_time) {
+ btm_cb.collision_start_time = osi_time_get_os_boottime_ms();
+ }
+
+ if ((osi_time_get_os_boottime_ms() - btm_cb.collision_start_time) < btm_cb.max_collision_delay)
+ {
+ if (handle == BTM_SEC_INVALID_HANDLE)
+ {
+ if ((p_dev_rec = btm_sec_find_dev_by_sec_state (BTM_SEC_STATE_AUTHENTICATING)) == NULL) {
+ p_dev_rec = btm_sec_find_dev_by_sec_state (BTM_SEC_STATE_ENCRYPTING);
+ }
+ } else {
+ p_dev_rec = btm_find_dev_by_handle (handle);
+ }
+
+ if (p_dev_rec != NULL) {
+ BTM_TRACE_DEBUG ("btm_sec_auth_collision: state %d (retrying in a moment...)\n", p_dev_rec->sec_state);
+ /* We will restart authentication after timeout */
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING || p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING) {
+ p_dev_rec->sec_state = 0;
+ }
+
+ btm_cb.p_collided_dev_rec = p_dev_rec;
+ btm_cb.sec_collision_tle.param = (UINT32) btm_sec_collision_timeout;
+ btu_start_timer (&btm_cb.sec_collision_tle, BTU_TTYPE_USER_FUNC, BT_1SEC_TIMEOUT);
+ }
+ }
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_sec_auth_complete
+**
+** Description This function is when authentication of the connection is
+** completed by the LM
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+void btm_sec_auth_complete (UINT16 handle, UINT8 status)
+{
+ UINT8 res;
+ UINT8 old_sm4;
+ tBTM_PAIRING_STATE old_state = btm_cb.pairing_state;
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
+ BOOLEAN are_bonding = FALSE;
+
+ /* Commenting out trace due to obf/compilation problems.
+ */
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ if (p_dev_rec) {
+ BTM_TRACE_EVENT ("Security Manager: auth_complete PairState: %s handle:%u status:%d dev->sec_state: %u Bda:%08x, RName:%s\n",
+ btm_pair_state_descr (btm_cb.pairing_state),
+ handle, status,
+ p_dev_rec->sec_state,
+ (p_dev_rec->bd_addr[2] << 24) + (p_dev_rec->bd_addr[3] << 16) + (p_dev_rec->bd_addr[4] << 8) + p_dev_rec->bd_addr[5],
+ p_dev_rec->sec_bd_name);
+ } else {
+ BTM_TRACE_EVENT ("Security Manager: auth_complete PairState: %s handle:%u status:%d\n",
+ btm_pair_state_descr (btm_cb.pairing_state),
+ handle, status);
+ }
+#endif
+
+ /* For transaction collision we need to wait and repeat. There is no need */
+ /* for random timeout because only slave should receive the result */
+ if ((status == HCI_ERR_LMP_ERR_TRANS_COLLISION) || (status == HCI_ERR_DIFF_TRANSACTION_COLLISION)) {
+ btm_sec_auth_collision(handle);
+ return;
+ }
+ btm_cb.collision_start_time = 0;
+
+ btm_restore_mode();
+
+ /* Check if connection was made just to do bonding. If we authenticate
+ the connection that is up, this is the last event received.
+ */
+ if (p_dev_rec
+ && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ && !(btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE)) {
+ p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+
+ l2cu_start_post_bond_timer (p_dev_rec->hci_handle);
+ }
+
+ if (!p_dev_rec) {
+ return;
+ }
+
+ /* keep the old sm4 flag and clear the retry bit in control block */
+ old_sm4 = p_dev_rec->sm4;
+ p_dev_rec->sm4 &= ~BTM_SM4_RETRY;
+
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ && (memcmp (p_dev_rec->bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) ) {
+ are_bonding = TRUE;
+ }
+
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (memcmp (p_dev_rec->bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) ) {
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ }
+
+ if (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING) {
+ if ( (btm_cb.api.p_auth_complete_callback && status != HCI_SUCCESS)
+ && (old_state != BTM_PAIR_STATE_IDLE) ) {
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, status);
+ }
+ return;
+ }
+
+ /* There can be a race condition, when we are starting authentication and
+ ** the peer device is doing encryption.
+ ** If first we receive encryption change up, then initiated authentication
+ ** can not be performed. According to the spec we can not do authentication
+ ** on the encrypted link, so device is correct.
+ */
+ if ((status == HCI_ERR_COMMAND_DISALLOWED)
+ && ((p_dev_rec->sec_flags & (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED)) ==
+ (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED))) {
+ status = HCI_SUCCESS;
+ }
+
+ /* Currently we do not notify user if it is a keyboard which connects */
+ /* User probably Disabled the keyboard while it was asleep. Let her try */
+ if (btm_cb.api.p_auth_complete_callback) {
+ /* report the authentication status */
+ if (old_state != BTM_PAIR_STATE_IDLE) {
+ res = (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, status);
+ if (res == BTM_SEC_DEV_REC_REMOVED) {
+ p_dev_rec = NULL;
+ }
+ }
+ }
+
+ if(!p_dev_rec) {
+ return;
+ }
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ btm_sec_update_legacy_auth_state(btm_bda_to_acl(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR), BTM_ACL_LEGACY_AUTH_SELF);
+#endif
+ /* If this is a bonding procedure can disconnect the link now */
+ if (are_bonding) {
+ p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+
+ if (status != HCI_SUCCESS) {
+ if (((status != HCI_ERR_PEER_USER) && (status != HCI_ERR_CONN_CAUSE_LOCAL_HOST))) {
+ btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_PEER_USER, p_dev_rec->hci_handle);
+ }
+ } else {
+ BTM_TRACE_DEBUG ("TRYING TO DECIDE IF CAN USE SMP_BR_CHNL\n");
+ if (p_dev_rec->new_encryption_key_is_p256 && (btm_sec_use_smp_br_chnl(p_dev_rec))
+ /* no LE keys are available, do deriving */
+ && (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN) ||
+ /* or BR key is higher security than existing LE keys */
+ (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED) &&
+ (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)))) {
+ BTM_TRACE_DEBUG ("link encrypted afer dedic bonding can use SMP_BR_CHNL\n");
+
+ if (btm_sec_is_master(p_dev_rec)) {
+ // Encryption is required to start SM over BR/EDR
+ // indicate that this is encryption after authentication
+ BTM_SetEncryption(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR, NULL, NULL);
+ }
+ }
+ l2cu_start_post_bond_timer (p_dev_rec->hci_handle);
+ }
+
+ return;
+ }
+
+ /* If authentication failed, notify the waiting layer */
+ if (status != HCI_SUCCESS) {
+ if ((old_sm4 & BTM_SM4_RETRY) == 0) {
+ /* allow retry only once */
+ if (status == HCI_ERR_LMP_ERR_TRANS_COLLISION) {
+ /* not retried yet. set the retry bit */
+ p_dev_rec->sm4 |= BTM_SM4_RETRY;
+ BTM_TRACE_DEBUG ("Collision retry sm4:x%x sec_flags:0x%x\n", p_dev_rec->sm4, p_dev_rec->sec_flags);
+ }
+ /* this retry for missing key is for Lisbon or later only.
+ * Legacy device do not need this. the controller will drive the retry automatically */
+ else if (HCI_ERR_KEY_MISSING == status && BTM_SEC_IS_SM4(p_dev_rec->sm4)) {
+ /* not retried yet. set the retry bit */
+ p_dev_rec->sm4 |= BTM_SM4_RETRY;
+ p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN;
+ BTM_TRACE_DEBUG ("Retry for missing key sm4:x%x sec_flags:0x%x\n", p_dev_rec->sm4, p_dev_rec->sec_flags);
+
+ /* With BRCM controller, we do not need to delete the stored link key in controller.
+ If the stack may sit on top of other controller, we may need this
+ BTM_DeleteStoredLinkKey (bd_addr, NULL); */
+ }
+
+ if (p_dev_rec->sm4 & BTM_SM4_RETRY) {
+ btm_sec_execute_procedure (p_dev_rec);
+ return;
+ }
+ }
+
+ btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING, FALSE);
+
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) {
+ btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE, p_dev_rec->hci_handle);
+ }
+ return;
+ }
+
+ p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED;
+
+ if (p_dev_rec->pin_code_length >= 16 ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) {
+ // If we have MITM protection we have a higher level of security than
+ // provided by 16 digits PIN
+ p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+ }
+
+ /* Authentication succeeded, execute the next security procedure, if any */
+ status = btm_sec_execute_procedure (p_dev_rec);
+
+ /* If there is no next procedure, or procedure failed to start, notify the caller */
+ if (status != BTM_CMD_STARTED) {
+ btm_sec_dev_rec_cback_event (p_dev_rec, status, FALSE);
+ }
+}
+#endif ///SMP_INCLUDED == TRUE
+
+
+/*******************************************************************************
+**
+** Function btm_sec_encrypt_change
+**
+** Description This function is when encryption of the connection is
+** completed by the LM
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+void btm_sec_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ tACL_CONN *p_acl = NULL;
+#endif
+ BTM_TRACE_EVENT ("Security Manager: encrypt_change status:%d State:%d, encr_enable = %d\n",
+ status, (p_dev_rec) ? p_dev_rec->sec_state : 0, encr_enable);
+ BTM_TRACE_DEBUG ("before update p_dev_rec->sec_flags=0x%x\n", (p_dev_rec) ? p_dev_rec->sec_flags : 0 );
+
+ /* For transaction collision we need to wait and repeat. There is no need */
+ /* for random timeout because only slave should receive the result */
+ if ((status == HCI_ERR_LMP_ERR_TRANS_COLLISION) ||
+ (status == HCI_ERR_DIFF_TRANSACTION_COLLISION)) {
+ btm_sec_auth_collision(handle);
+ return;
+ }
+ btm_cb.collision_start_time = 0;
+
+ if (!p_dev_rec) {
+ return;
+ }
+
+ if ((status == HCI_SUCCESS) && encr_enable) {
+ if (p_dev_rec->hci_handle == handle) {
+ p_dev_rec->sec_flags |= (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED);
+ if (p_dev_rec->pin_code_length >= 16 ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) {
+ p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+ }
+ if (p_dev_rec->enc_mode != encr_enable) {
+ p_dev_rec->enc_mode = encr_enable;
+ /* Report the encryption change state of BR/EDR to upper layer */
+ if (btm_cb.api.p_enc_change_callback) {
+ (*btm_cb.api.p_enc_change_callback) (p_dev_rec->bd_addr, encr_enable);
+ }
+ }
+ } else {
+ p_dev_rec->sec_flags |= BTM_SEC_LE_ENCRYPTED;
+ }
+ }
+
+ /* It is possible that we decrypted the link to perform role switch */
+ /* mark link not to be encrypted, so that when we execute security next time it will kick in again */
+ if ((status == HCI_SUCCESS) && !encr_enable) {
+ if (p_dev_rec->hci_handle == handle) {
+ p_dev_rec->sec_flags &= ~BTM_SEC_ENCRYPTED;
+ if (p_dev_rec->enc_mode != encr_enable) {
+ p_dev_rec->enc_mode = encr_enable;
+ /* Report the encryption change state of BR/EDR to upper layer */
+ if (btm_cb.api.p_enc_change_callback) {
+ (*btm_cb.api.p_enc_change_callback) (p_dev_rec->bd_addr, encr_enable);
+ }
+ }
+ } else {
+ p_dev_rec->sec_flags &= ~BTM_SEC_LE_ENCRYPTED;
+ }
+ }
+
+ BTM_TRACE_DEBUG ("after update p_dev_rec->sec_flags=0x%x\n", p_dev_rec->sec_flags );
+
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ p_acl = btm_handle_to_acl(handle);
+
+ if (p_acl != NULL) {
+ btm_sec_check_pending_enc_req(p_dev_rec, p_acl->transport, encr_enable);
+ }
+
+ if (p_acl && p_acl->transport == BT_TRANSPORT_LE) {
+ if (status == HCI_ERR_KEY_MISSING || status == HCI_ERR_AUTH_FAILURE ||
+ status == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) {
+ p_dev_rec->sec_flags &= ~ (BTM_SEC_LE_LINK_KEY_KNOWN);
+ p_dev_rec->ble.key_type = BTM_LE_KEY_NONE;
+ }
+ btm_ble_link_encrypted(p_dev_rec->ble.pseudo_addr, encr_enable);
+ return;
+ } else {
+ /* BR/EDR connection, update the encryption key size to be 16 as always */
+ p_dev_rec->enc_key_size = 16;
+ }
+
+ BTM_TRACE_DEBUG ("in %s new_encr_key_256 is %d\n",
+ __func__, p_dev_rec->new_encryption_key_is_p256);
+
+ if ((status == HCI_SUCCESS) && encr_enable && (p_dev_rec->hci_handle == handle)) {
+ if (p_dev_rec->new_encryption_key_is_p256) {
+ if (btm_sec_use_smp_br_chnl(p_dev_rec) &&
+ btm_sec_is_master(p_dev_rec) &&
+ /* if LE key is not known, do deriving */
+ (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN) ||
+ /* or BR key is higher security than existing LE keys */
+ (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED)
+ && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)))) {
+ /* BR/EDR is encrypted with LK that can be used to derive LE LTK */
+ p_dev_rec->new_encryption_key_is_p256 = FALSE;
+
+ if (p_dev_rec->no_smp_on_br) {
+ BTM_TRACE_DEBUG ("%s NO SM over BR/EDR\n", __func__);
+ } else {
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ BTM_TRACE_DEBUG ("%s start SM over BR/EDR\n", __func__);
+ SMP_BR_PairWith(p_dev_rec->bd_addr);
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+ }
+ }
+ } else {
+ // BR/EDR is successfully encrypted. Correct LK type if needed
+ // (BR/EDR LK derived from LE LTK was used for encryption)
+ if ((encr_enable == 1) && /* encryption is ON for SSP */
+ /* LK type is for BR/EDR SC */
+ (p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256 ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ if (p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256) {
+ p_dev_rec->link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB;
+ } else { /* BTM_LKEY_TYPE_AUTH_COMB_P_256 */
+ p_dev_rec->link_key_type = BTM_LKEY_TYPE_AUTH_COMB;
+ }
+
+ BTM_TRACE_DEBUG("updated link key type to %d\n", p_dev_rec->link_key_type);
+ btm_send_link_key_notif(p_dev_rec);
+ }
+ }
+ }
+#else
+ btm_sec_check_pending_enc_req (p_dev_rec, BT_TRANSPORT_BR_EDR, encr_enable);
+#endif /* BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE */
+
+ /* If this encryption was started by peer do not need to do anything */
+ if (p_dev_rec->sec_state != BTM_SEC_STATE_ENCRYPTING) {
+ if (BTM_SEC_STATE_DELAY_FOR_ENC == p_dev_rec->sec_state) {
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ p_dev_rec->p_callback = NULL;
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ l2cu_resubmit_pending_sec_req (p_dev_rec->bd_addr);
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+ }
+ return;
+ }
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ /* If encryption setup failed, notify the waiting layer */
+ if (status != HCI_SUCCESS) {
+ btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING, FALSE);
+ return;
+ }
+
+ /* Encryption setup succeeded, execute the next security procedure, if any */
+ status = (UINT8)btm_sec_execute_procedure (p_dev_rec);
+ /* If there is no next procedure, or procedure failed to start, notify the caller */
+ if (status != BTM_CMD_STARTED) {
+ btm_sec_dev_rec_cback_event (p_dev_rec, status, FALSE);
+ }
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_sec_connect_after_reject_timeout
+**
+** Description Connection for bonding could not start because of the collision
+** Initiate outgoing connection
+**
+** Returns Pointer to the TLE struct
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static void btm_sec_connect_after_reject_timeout (TIMER_LIST_ENT *p_tle)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_cb.p_collided_dev_rec;
+ UNUSED(p_tle);
+
+ BTM_TRACE_EVENT ("btm_sec_connect_after_reject_timeout()\n");
+ btm_cb.sec_collision_tle.param = 0;
+ btm_cb.p_collided_dev_rec = 0;
+
+ if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED) {
+ BTM_TRACE_WARNING ("Security Manager: btm_sec_connect_after_reject_timeout: failed to start connection\n");
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+ if (btm_cb.api.p_auth_complete_callback) {
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, HCI_ERR_MEMORY_FULL);
+ }
+ }
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_sec_connected
+**
+** Description This function is when a connection to the peer device is
+** establsihed
+**
+** Returns void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda);
+ UINT8 res;
+ UINT8 sec_dev_rec_status;
+ BOOLEAN is_pairing_device = FALSE;
+ tACL_CONN *p_acl_cb;
+ UINT8 bit_shift = 0;
+
+ btm_acl_resubmit_page();
+
+ /* Commenting out trace due to obf/compilation problems.
+ */
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ if (p_dev_rec) {
+ BTM_TRACE_EVENT ("Security Manager: btm_sec_connected in state: %s handle:%d status:%d enc_mode:%d bda:%x RName:%s\n",
+ btm_pair_state_descr(btm_cb.pairing_state), handle, status, enc_mode,
+ (bda[2] << 24) + (bda[3] << 16) + (bda[4] << 8) + bda[5],
+ p_dev_rec->sec_bd_name);
+ } else {
+ BTM_TRACE_EVENT ("Security Manager: btm_sec_connected in state: %s handle:%d status:%d enc_mode:%d bda:%x \n",
+ btm_pair_state_descr(btm_cb.pairing_state), handle, status, enc_mode,
+ (bda[2] << 24) + (bda[3] << 16) + (bda[4] << 8) + bda[5]);
+ }
+#endif
+
+ if (!p_dev_rec) {
+ /* There is no device record for new connection. Allocate one */
+ if (status == HCI_SUCCESS) {
+ p_dev_rec = btm_sec_alloc_dev (bda);
+ } else {
+ /* If the device matches with stored paring address
+ * reset the paring state to idle */
+ if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
+ (memcmp (btm_cb.pairing_bda, bda, BD_ADDR_LEN) == 0)) {
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ }
+
+ /* can not find the device record and the status is error,
+ * just ignore it */
+ return;
+ }
+ } else { /* Update the timestamp for this device */
+
+#if BLE_INCLUDED == TRUE
+ bit_shift = (handle == p_dev_rec->ble_hci_handle) ? 8 : 0;
+#endif
+ p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+ if (p_dev_rec->sm4 & BTM_SM4_CONN_PEND) {
+ /* tell L2CAP it's a bonding connection. */
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (memcmp (btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0)
+ && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) ) {
+ /* if incoming connection failed while pairing, then try to connect and continue */
+ /* Motorola S9 disconnects without asking pin code */
+ if ((status != HCI_SUCCESS) && (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ)) {
+ BTM_TRACE_WARNING ("Security Manager: btm_sec_connected: incoming connection failed without asking PIN\n");
+
+ p_dev_rec->sm4 &= ~BTM_SM4_CONN_PEND;
+ if (p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) {
+ /* Start timer with 0 to initiate connection with new LCB */
+ /* because L2CAP will delete current LCB with this event */
+ btm_cb.p_collided_dev_rec = p_dev_rec;
+ btm_cb.sec_collision_tle.param = (UINT32) btm_sec_connect_after_reject_timeout;
+ btu_start_timer (&btm_cb.sec_collision_tle, BTU_TTYPE_USER_FUNC, 0);
+ } else {
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_GET_REM_NAME);
+ BTM_ReadRemoteDeviceName(p_dev_rec->bd_addr, NULL, BT_TRANSPORT_BR_EDR);
+ }
+#if BTM_DISC_DURING_RS == TRUE
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+#endif
+ return;
+ } else {
+ l2cu_update_lcb_4_bonding(p_dev_rec->bd_addr, TRUE);
+ }
+ }
+ /* always clear the pending flag */
+ p_dev_rec->sm4 &= ~BTM_SM4_CONN_PEND;
+ }
+ }
+
+#if BLE_INCLUDED == TRUE
+ p_dev_rec->device_type |= BT_DEVICE_TYPE_BREDR;
+#endif
+
+#if BTM_DISC_DURING_RS == TRUE
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+#endif
+
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (memcmp (btm_cb.pairing_bda, bda, BD_ADDR_LEN) == 0) ) {
+ /* if we rejected incoming connection from bonding device */
+ if ((status == HCI_ERR_HOST_REJECT_DEVICE)
+ && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT)) {
+ BTM_TRACE_WARNING ("Security Manager: btm_sec_connected: HCI_Conn_Comp Flags:0x%04x, sm4: 0x%x\n",
+ btm_cb.pairing_flags, p_dev_rec->sm4);
+
+ btm_cb.pairing_flags &= ~BTM_PAIR_FLAGS_REJECTED_CONNECT;
+ if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) {
+ /* Try again: RNR when no ACL causes HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_GET_REM_NAME);
+ BTM_ReadRemoteDeviceName(bda, NULL, BT_TRANSPORT_BR_EDR);
+ return;
+ }
+
+ /* if we already have pin code */
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_PIN) {
+ /* Start timer with 0 to initiate connection with new LCB */
+ /* because L2CAP will delete current LCB with this event */
+ btm_cb.p_collided_dev_rec = p_dev_rec;
+ btm_cb.sec_collision_tle.param = (UINT32) btm_sec_connect_after_reject_timeout;
+ btu_start_timer (&btm_cb.sec_collision_tle, BTU_TTYPE_USER_FUNC, 0);
+ }
+
+ return;
+ }
+ /* wait for incoming connection without resetting pairing state */
+ else if (status == HCI_ERR_CONNECTION_EXISTS) {
+ BTM_TRACE_WARNING ("Security Manager: btm_sec_connected: Wait for incoming connection\n");
+ return;
+ }
+
+ is_pairing_device = TRUE;
+ }
+
+ /* If connection was made to do bonding restore link security if changed */
+ btm_restore_mode();
+
+ /* if connection fails during pin request, notify application */
+ if (status != HCI_SUCCESS) {
+ /* If connection failed because of during pairing, need to tell user */
+ if (is_pairing_device) {
+ p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+ p_dev_rec->sec_flags &= ~((BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED) << bit_shift);
+ BTM_TRACE_DEBUG ("security_required:%x \n", p_dev_rec->security_required );
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+ /* We need to notify host that the key is not known any more */
+ if (btm_cb.api.p_auth_complete_callback) {
+ sec_dev_rec_status = (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, status);
+ if (sec_dev_rec_status == BTM_SEC_DEV_REC_REMOVED) {
+ p_dev_rec = NULL;
+ }
+ }
+ }
+ /*
+ Do not send authentication failure, if following conditions hold good
+ 1. BTM Sec Pairing state is idle
+ 2. Link key for the remote device is present.
+ 3. Remote is SSP capable.
+ */
+ else if ((p_dev_rec->link_key_type <= BTM_LKEY_TYPE_REMOTE_UNIT) &&
+ (((status == HCI_ERR_AUTH_FAILURE) ||
+ (status == HCI_ERR_KEY_MISSING) ||
+ (status == HCI_ERR_HOST_REJECT_SECURITY) ||
+ (status == HCI_ERR_PAIRING_NOT_ALLOWED) ||
+ (status == HCI_ERR_UNIT_KEY_USED) ||
+ (status == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
+ (status == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) ||
+ (status == HCI_ERR_REPEATED_ATTEMPTS)))) {
+ p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+ p_dev_rec->sec_flags &= ~ (BTM_SEC_LE_LINK_KEY_KNOWN << bit_shift);
+
+
+#ifdef BRCM_NOT_4_BTE
+ /* If we rejected pairing, pass this special result code */
+ if (btm_cb.acl_disc_reason == HCI_ERR_HOST_REJECT_SECURITY) {
+ status = HCI_ERR_HOST_REJECT_SECURITY;
+ }
+#endif
+
+ /* We need to notify host that the key is not known any more */
+ if (btm_cb.api.p_auth_complete_callback) {
+ sec_dev_rec_status = (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, status);
+ if (sec_dev_rec_status == BTM_SEC_DEV_REC_REMOVED) {
+ p_dev_rec = NULL;
+ }
+ }
+ }
+
+ if (status == HCI_ERR_CONNECTION_TOUT || status == HCI_ERR_LMP_RESPONSE_TIMEOUT ||
+ status == HCI_ERR_UNSPECIFIED || status == HCI_ERR_PAGE_TIMEOUT) {
+ btm_sec_dev_rec_cback_event (p_dev_rec, BTM_DEVICE_TIMEOUT, FALSE);
+ } else {
+ btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING, FALSE);
+ }
+
+ return;
+ }
+
+ /* If initiated dedicated bonding, return the link key now, and initiate disconnect */
+ /* If dedicated bonding, and we now have a link key, we are all done */
+ if ( is_pairing_device
+ && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) ) {
+ if (p_dev_rec->link_key_not_sent) {
+ p_dev_rec->link_key_not_sent = FALSE;
+ btm_send_link_key_notif(p_dev_rec);
+ }
+
+ p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+
+ /* remember flag before it is initialized */
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) {
+ res = TRUE;
+ } else {
+ res = FALSE;
+ }
+
+ if (btm_cb.api.p_auth_complete_callback) {
+ sec_dev_rec_status = (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, HCI_SUCCESS);
+ if (sec_dev_rec_status == BTM_SEC_DEV_REC_REMOVED) {
+ p_dev_rec = NULL;
+ }
+ }
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+ if ( res ) {
+ /* Let l2cap start bond timer */
+ l2cu_update_lcb_4_bonding (p_dev_rec->bd_addr, TRUE);
+ }
+
+ return;
+ }
+
+ p_dev_rec->hci_handle = handle;
+
+ /* role may not be correct here, it will be updated by l2cap, but we need to */
+ /* notify btm_acl that link is up, so starting of rmt name request will not */
+ /* set paging flag up */
+ p_acl_cb = btm_bda_to_acl(bda, BT_TRANSPORT_BR_EDR);
+ if (p_acl_cb) {
+ /* whatever is in btm_establish_continue() without reporting the BTM_BL_CONN_EVT event */
+#if (!defined(BTM_BYPASS_EXTRA_ACL_SETUP) || BTM_BYPASS_EXTRA_ACL_SETUP == FALSE)
+ /* For now there are a some devices that do not like sending */
+ /* commands events and data at the same time. */
+ /* Set the packet types to the default allowed by the device */
+ btm_set_packet_types (p_acl_cb, btm_cb.btm_acl_pkt_types_supported);
+
+ if (btm_cb.btm_def_link_policy) {
+ BTM_SetLinkPolicy (p_acl_cb->remote_addr, &btm_cb.btm_def_link_policy);
+ }
+#endif
+ }
+ btm_acl_created (bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, handle, HCI_ROLE_SLAVE, BT_TRANSPORT_BR_EDR);
+
+ /* Initialize security flags. We need to do that because some */
+ /* authorization complete could have come after the connection is dropped */
+ /* and that would set wrong flag that link has been authorized already */
+ p_dev_rec->sec_flags &= ~((BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED |
+ BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED) << bit_shift);
+
+ if (enc_mode != HCI_ENCRYPT_MODE_DISABLED) {
+ p_dev_rec->sec_flags |= ((BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED) << bit_shift);
+ }
+
+ if (btm_cb.security_mode == BTM_SEC_MODE_LINK) {
+ p_dev_rec->sec_flags |= (BTM_SEC_AUTHENTICATED << bit_shift);
+ }
+
+ if (p_dev_rec->pin_code_length >= 16 ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) {
+ p_dev_rec->sec_flags |= (BTM_SEC_16_DIGIT_PIN_AUTHED << bit_shift);
+ }
+
+ p_dev_rec->link_key_changed = FALSE;
+
+ /* After connection is established we perform security if we do not know */
+ /* the name, or if we are originator because some procedure can have */
+ /* been scheduled while connection was down */
+ BTM_TRACE_DEBUG ("is_originator:%d \n", p_dev_rec->is_originator);
+ if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) || p_dev_rec->is_originator) {
+ if ((res = btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED) {
+ btm_sec_dev_rec_cback_event (p_dev_rec, res, FALSE);
+ }
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_disconnect
+**
+** Description This function is called to disconnect HCI link
+**
+** Returns btm status
+**
+*******************************************************************************/
+tBTM_STATUS btm_sec_disconnect (UINT16 handle, UINT8 reason)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
+
+ /* In some weird race condition we may not have a record */
+ if (!p_dev_rec) {
+ btsnd_hcic_disconnect (handle, reason);
+ return (BTM_SUCCESS);
+ }
+
+ /* If we are in the process of bonding we need to tell client that auth failed */
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (memcmp (btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0)
+ && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) ) {
+ /* we are currently doing bonding. Link will be disconnected when done */
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE;
+ return (BTM_BUSY);
+ }
+
+ return (btm_sec_send_hci_disconnect(p_dev_rec, reason, handle));
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_disconnected
+**
+** Description This function is when a connection to the peer device is
+** dropped
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_disconnected (UINT16 handle, UINT8 reason)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
+ UINT8 old_pairing_flags = btm_cb.pairing_flags;
+ int result = HCI_ERR_AUTH_FAILURE;
+ tBTM_SEC_CALLBACK *p_callback = NULL;
+ tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+
+ /* If page was delayed for disc complete, can do it now */
+ btm_cb.discing = FALSE;
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ btm_acl_resubmit_page();
+#endif
+
+ if (!p_dev_rec) {
+ return;
+ }
+ p_dev_rec->enc_init_by_we = FALSE;
+ transport = (handle == p_dev_rec->hci_handle) ? BT_TRANSPORT_BR_EDR : BT_TRANSPORT_LE;
+
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+
+#if BTM_DISC_DURING_RS == TRUE
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+#endif
+
+ /* clear unused flags */
+ p_dev_rec->sm4 &= BTM_SM4_TRUE;
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ uint8_t *bd_addr = (uint8_t *)p_dev_rec->bd_addr;
+ BTM_TRACE_EVENT("%s sec_req:x%x state:%s reason:%d bd_addr:%02x:%02x:%02x:%02x:%02x:%02x"
+ " remote_name:%s\n", __func__, p_dev_rec->security_required, btm_pair_state_descr(btm_cb.pairing_state),
+ reason, bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5], p_dev_rec->sec_bd_name);
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ BTM_TRACE_EVENT("%s before update sec_flags=0x%x\n", __func__, p_dev_rec->sec_flags);
+
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, p_dev_rec->bd_addr, HCI_SUCCESS);
+ /* see sec_flags processing in btm_acl_removed */
+
+ if (transport == BT_TRANSPORT_LE) {
+ p_dev_rec->ble_hci_handle = BTM_SEC_INVALID_HANDLE;
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LE_AUTHENTICATED | BTM_SEC_LE_ENCRYPTED);
+ p_dev_rec->enc_key_size = 0;
+ } else
+#endif
+ {
+ p_dev_rec->hci_handle = BTM_SEC_INVALID_HANDLE;
+ p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED
+ | BTM_SEC_ROLE_SWITCHED | BTM_SEC_16_DIGIT_PIN_AUTHED);
+ }
+
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING_BOTH) {
+ p_dev_rec->sec_state = (transport == BT_TRANSPORT_LE) ?
+ BTM_SEC_STATE_DISCONNECTING : BTM_SEC_STATE_DISCONNECTING_BLE;
+ return;
+ }
+#endif
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ p_dev_rec->security_required = BTM_SEC_NONE;
+
+ p_callback = p_dev_rec->p_callback;
+
+ /* if security is pending, send callback to clean up the security state */
+ if (p_callback) {
+ p_dev_rec->p_callback = NULL; /* when the peer device time out the authentication before
+ we do, this call back must be reset here */
+ (*p_callback) (p_dev_rec->bd_addr, transport, p_dev_rec->p_ref_data, BTM_ERR_PROCESSING);
+ }
+
+ BTM_TRACE_EVENT("%s after update sec_flags=0x%x\n", __func__, p_dev_rec->sec_flags);
+
+ /* If we are in the process of bonding we need to tell client that auth failed */
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (memcmp (btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0)) {
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN;
+ if (btm_cb.api.p_auth_complete_callback) {
+ /* If the disconnection reason is REPEATED_ATTEMPTS,
+ send this error message to complete callback function
+ to display the error message of Repeated attempts.
+ All others, send HCI_ERR_AUTH_FAILURE. */
+ if (reason == HCI_ERR_REPEATED_ATTEMPTS) {
+ result = HCI_ERR_REPEATED_ATTEMPTS;
+ } else if (old_pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) {
+ result = HCI_ERR_HOST_REJECT_SECURITY;
+ }
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, result);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_link_key_notification
+**
+** Description This function is called when a new connection link key is
+** generated
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+void btm_sec_link_key_notification (UINT8 *p_bda, UINT8 *p_link_key, UINT8 key_type)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_bda);
+ BOOLEAN we_are_bonding = FALSE;
+ BOOLEAN ltk_derived_lk = FALSE;
+ UINT8 res;
+
+ BTM_TRACE_EVENT ("btm_sec_link_key_notification() BDA:%04x%08x, TYPE: %d\n",
+ (p_bda[0] << 8) + p_bda[1], (p_bda[2] << 24) + (p_bda[3] << 16) + (p_bda[4] << 8) + p_bda[5],
+ key_type);
+
+ if ((key_type >= BTM_LTK_DERIVED_LKEY_OFFSET + BTM_LKEY_TYPE_COMBINATION) &&
+ (key_type <= BTM_LTK_DERIVED_LKEY_OFFSET + BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ ltk_derived_lk = TRUE;
+ key_type -= BTM_LTK_DERIVED_LKEY_OFFSET;
+ }
+ /* If connection was made to do bonding restore link security if changed */
+ btm_restore_mode();
+
+ /* Store the previous state of secure connection as current state. Since
+ * this is the first encounter with the remote device, whatever the remote
+ * device's SC state is, it cannot lower the SC level from this. */
+ p_dev_rec->remote_secure_connection_previous_state = p_dev_rec->remote_supports_secure_connections;
+ if (p_dev_rec->remote_supports_secure_connections) {
+ BTM_TRACE_EVENT ("Remote device supports Secure Connection");
+ } else {
+ BTM_TRACE_EVENT ("Remote device does not support Secure Connection");
+ }
+ if (key_type != BTM_LKEY_TYPE_CHANGED_COMB) {
+ p_dev_rec->link_key_type = key_type;
+ }
+
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ btm_sec_update_legacy_auth_state(btm_bda_to_acl(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR), BTM_ACL_LEGACY_AUTH_NONE);
+#endif
+ /*
+ * Until this point in time, we do not know if MITM was enabled, hence we
+ * add the extended security flag here.
+ */
+ if (p_dev_rec->pin_code_length >= 16 ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) {
+ p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+ }
+
+#if (BLE_INCLUDED == TRUE)
+ /* BR/EDR connection, update the encryption key size to be 16 as always */
+ p_dev_rec->enc_key_size = 16;
+#endif
+ memcpy (p_dev_rec->link_key, p_link_key, LINK_KEY_LEN);
+
+ if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ && (memcmp (btm_cb.pairing_bda, p_bda, BD_ADDR_LEN) == 0) ) {
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) {
+ we_are_bonding = TRUE;
+ } else {
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ }
+ }
+
+ /* save LTK derived LK no matter what */
+ if (ltk_derived_lk) {
+ if (btm_cb.api.p_link_key_callback) {
+ BTM_TRACE_DEBUG ("%s() Save LTK derived LK (key_type = %d)\n",
+ __FUNCTION__, p_dev_rec->link_key_type);
+ (*btm_cb.api.p_link_key_callback) (p_bda, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name,
+ p_link_key, p_dev_rec->link_key_type,
+ p_dev_rec->remote_supports_secure_connections);
+ }
+ } else {
+ if ((p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256) ||
+ (p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ p_dev_rec->new_encryption_key_is_p256 = TRUE;
+ BTM_TRACE_DEBUG ("%s set new_encr_key_256 to %d\n",
+ __func__, p_dev_rec->new_encryption_key_is_p256);
+ }
+ }
+
+ /* If name is not known at this point delay calling callback until the name is */
+ /* resolved. Unless it is a HID Device and we really need to send all link keys. */
+ if ((!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN)
+ && ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) != BTM_COD_MAJOR_PERIPHERAL))
+ && !ltk_derived_lk) {
+ BTM_TRACE_EVENT ("btm_sec_link_key_notification() Delayed BDA: %08x%04x Type:%d\n",
+ (p_bda[0] << 24) + (p_bda[1] << 16) + (p_bda[2] << 8) + p_bda[3],
+ (p_bda[4] << 8) + p_bda[5], key_type);
+
+ p_dev_rec->link_key_not_sent = TRUE;
+
+ /* If it is for bonding nothing else will follow, so we need to start name resolution */
+ if (we_are_bonding) {
+ if (!(btsnd_hcic_rmt_name_req (p_bda, HCI_PAGE_SCAN_REP_MODE_R1, HCI_MANDATARY_PAGE_SCAN_MODE, 0))) {
+ btm_inq_rmt_name_failed();
+ }
+ }
+
+ BTM_TRACE_EVENT ("rmt_io_caps:%d, sec_flags:x%x, dev_class[1]:x%02x\n", p_dev_rec->rmt_io_caps, p_dev_rec->sec_flags, p_dev_rec->dev_class[1])
+ return;
+ }
+
+ /* If its not us who perform authentication, we should tell stackserver */
+ /* that some authentication has been completed */
+ /* This is required when different entities receive link notification and auth complete */
+ if (!(p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE)
+ /* for derived key, always send authentication callback for BR channel */
+ || ltk_derived_lk) {
+ if (btm_cb.api.p_auth_complete_callback) {
+ res = (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, HCI_SUCCESS);
+ if (res == BTM_SEC_DEV_REC_REMOVED) {
+ p_dev_rec = NULL;
+ }
+ }
+ }
+
+ if(!p_dev_rec) {
+ return;
+ }
+
+ /* We will save link key only if the user authorized it - BTE report link key in all cases */
+#ifdef BRCM_NONE_BTE
+ if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)
+#endif
+ {
+ if (btm_cb.api.p_link_key_callback) {
+ if (ltk_derived_lk) {
+ BTM_TRACE_DEBUG ("btm_sec_link_key_notification() LTK derived LK is saved already"
+ " (key_type = %d)\n", p_dev_rec->link_key_type);
+ } else {
+ (*btm_cb.api.p_link_key_callback) (p_bda, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name,
+ p_link_key, p_dev_rec->link_key_type,
+ p_dev_rec->remote_supports_secure_connections);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_link_key_request
+**
+** Description This function is called when controller requests link key
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+void btm_sec_link_key_request (UINT8 *p_bda)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_bda);
+
+ BTM_TRACE_EVENT ("btm_sec_link_key_request() BDA: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
+
+ if ( (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ) &&
+ (btm_cb.collision_start_time != 0) &&
+ (memcmp (btm_cb.p_collided_dev_rec->bd_addr, p_bda, BD_ADDR_LEN) == 0) ) {
+ BTM_TRACE_EVENT ("btm_sec_link_key_request() rejecting link key req "
+ "State: %d START_TIMEOUT : %d\n",
+ btm_cb.pairing_state, btm_cb.collision_start_time);
+ btsnd_hcic_link_key_neg_reply (p_bda);
+ return;
+ }
+ if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) {
+ btsnd_hcic_link_key_req_reply (p_bda, p_dev_rec->link_key);
+ return;
+ }
+
+ /* Notify L2CAP to increase timeout */
+ l2c_pin_code_request (p_bda);
+
+ /* The link key is not in the database and it is not known to the manager */
+ btsnd_hcic_link_key_neg_reply (p_bda);
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_sec_pairing_timeout
+**
+** Description This function is called when host does not provide PIN
+** within requested time
+**
+** Returns Pointer to the TLE struct
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static void btm_sec_pairing_timeout (TIMER_LIST_ENT *p_tle)
+{
+ tBTM_CB *p_cb = &btm_cb;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+#if BTM_OOB_INCLUDED == TRUE
+#if (BTM_LOCAL_IO_CAPS == BTM_IO_CAP_NONE)
+ tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_NO;
+#else
+ tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_YES;
+#endif
+#endif
+ UINT8 name[2];
+ UNUSED(p_tle);
+
+ p_cb->pairing_tle.param = 0;
+ /* Coverity: FALSE-POSITIVE error from Coverity tool. Please do NOT remove following comment. */
+ /* coverity[UNUSED_VALUE] pointer p_dev_rec is actually used several times... This is a Coverity false-positive, i.e. a fake issue.
+ */
+ p_dev_rec = btm_find_dev (p_cb->pairing_bda);
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_EVENT ("btm_sec_pairing_timeout() State: %s Flags: %u\n",
+ btm_pair_state_descr(p_cb->pairing_state), p_cb->pairing_flags);
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ switch (p_cb->pairing_state) {
+ case BTM_PAIR_STATE_WAIT_PIN_REQ:
+ btm_sec_bond_cancel_complete();
+ break;
+
+ case BTM_PAIR_STATE_WAIT_LOCAL_PIN:
+ if ( (btm_cb.pairing_flags & BTM_PAIR_FLAGS_PRE_FETCH_PIN) == 0) {
+ btsnd_hcic_pin_code_neg_reply (p_cb->pairing_bda);
+ }
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ /* We need to notify the UI that no longer need the PIN */
+ if (btm_cb.api.p_auth_complete_callback) {
+ if (p_dev_rec == NULL) {
+ name[0] = '\0';
+ (*btm_cb.api.p_auth_complete_callback) (p_cb->pairing_bda,
+ NULL,
+ name, HCI_ERR_CONNECTION_TOUT);
+ } else {
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, HCI_ERR_CONNECTION_TOUT);
+ }
+ }
+ break;
+
+ case BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM:
+ btsnd_hcic_user_conf_reply (p_cb->pairing_bda, FALSE);
+ /* btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); */
+ break;
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ case BTM_PAIR_STATE_KEY_ENTRY:
+ btsnd_hcic_user_passkey_neg_reply(p_cb->pairing_bda);
+ /* btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); */
+ break;
+#endif /* (CLASSIC_BT_INCLUDED == TRUE) */
+
+#if BTM_OOB_INCLUDED == TRUE
+ case BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS:
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) {
+ auth_req |= BTM_AUTH_DD_BOND;
+ }
+
+ btsnd_hcic_io_cap_req_reply (p_cb->pairing_bda, btm_cb.devcb.loc_io_caps,
+ BTM_OOB_NONE, auth_req);
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ break;
+
+ case BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP:
+ btsnd_hcic_rem_oob_neg_reply (p_cb->pairing_bda);
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ break;
+#endif /* BTM_OOB_INCLUDED */
+
+ case BTM_PAIR_STATE_WAIT_DISCONNECT:
+ /* simple pairing failed. Started a 1-sec timer at simple pairing complete.
+ * now it's time to tear down the ACL link*/
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR ("btm_sec_pairing_timeout() BTM_PAIR_STATE_WAIT_DISCONNECT unknown BDA: %08x%04x\n",
+ (p_cb->pairing_bda[0] << 24) + (p_cb->pairing_bda[1] << 16) + (p_cb->pairing_bda[2] << 8) + p_cb->pairing_bda[3],
+ (p_cb->pairing_bda[4] << 8) + p_cb->pairing_bda[5]);
+ break;
+ }
+ btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE, p_dev_rec->hci_handle);
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ break;
+
+ case BTM_PAIR_STATE_WAIT_AUTH_COMPLETE:
+ case BTM_PAIR_STATE_GET_REM_NAME:
+ /* We need to notify the UI that timeout has happened while waiting for authentication*/
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ if (btm_cb.api.p_auth_complete_callback) {
+ if (p_dev_rec == NULL) {
+ name[0] = '\0';
+ (*btm_cb.api.p_auth_complete_callback) (p_cb->pairing_bda,
+ NULL,
+ name, HCI_ERR_CONNECTION_TOUT);
+ } else {
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, HCI_ERR_CONNECTION_TOUT);
+ }
+ }
+ break;
+
+ default:
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_WARNING ("btm_sec_pairing_timeout() not processed state: %s\n", btm_pair_state_descr(btm_cb.pairing_state));
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ break;
+ }
+}
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function btm_sec_pin_code_request
+**
+** Description This function is called when controller requests PIN code
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+void btm_sec_pin_code_request (UINT8 *p_bda)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_CB *p_cb = &btm_cb;
+
+#ifdef PORCHE_PAIRING_CONFLICT
+ UINT8 default_pin_code_len = 4;
+ PIN_CODE default_pin_code = {0x30, 0x30, 0x30, 0x30};
+#endif
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_EVENT ("btm_sec_pin_code_request() State: %s, BDA:%04x%08x\n",
+ btm_pair_state_descr(btm_cb.pairing_state),
+ (p_bda[0] << 8) + p_bda[1], (p_bda[2] << 24) + (p_bda[3] << 16) + (p_bda[4] << 8) + p_bda[5] );
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) {
+ if ( (memcmp (p_bda, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) &&
+ (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_AUTH_COMPLETE) ) {
+ /* fake this out - porshe carkit issue - */
+// btm_cb.pairing_state = BTM_PAIR_STATE_IDLE;
+ if (! btm_cb.pin_code_len_saved) {
+ btsnd_hcic_pin_code_neg_reply (p_bda);
+ return;
+ } else {
+ btsnd_hcic_pin_code_req_reply (p_bda, btm_cb.pin_code_len_saved, p_cb->pin_code);
+ return;
+ }
+ } else if ((btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_PIN_REQ)
+ || memcmp (p_bda, btm_cb.pairing_bda, BD_ADDR_LEN) != 0) {
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_WARNING ("btm_sec_pin_code_request() rejected - state: %s\n",
+ btm_pair_state_descr(btm_cb.pairing_state));
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+#ifdef PORCHE_PAIRING_CONFLICT
+ /* reply pin code again due to counter in_rand when local initiates pairing */
+ BTM_TRACE_EVENT ("btm_sec_pin_code_request from remote dev. for local initiated pairing\n");
+ if (! btm_cb.pin_code_len_saved) {
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ btsnd_hcic_pin_code_req_reply (p_bda, default_pin_code_len, default_pin_code);
+ } else {
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ btsnd_hcic_pin_code_req_reply (p_bda, btm_cb.pin_code_len_saved, p_cb->pin_code);
+ }
+#else
+ btsnd_hcic_pin_code_neg_reply (p_bda);
+#endif
+ return;
+ }
+ }
+
+ p_dev_rec = btm_find_or_alloc_dev (p_bda);
+ /* received PIN code request. must be non-sm4 */
+ p_dev_rec->sm4 = BTM_SM4_KNOWN;
+
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE) {
+ memcpy (btm_cb.pairing_bda, p_bda, BD_ADDR_LEN);
+
+ btm_cb.pairing_flags = BTM_PAIR_FLAGS_PEER_STARTED_DD;
+ /* Make sure we reset the trusted mask to help against attacks */
+ BTM_SEC_CLR_TRUSTED_DEVICE(p_dev_rec->trusted_mask);
+ }
+
+ if (!p_cb->pairing_disabled && (p_cb->cfg.pin_type == HCI_PIN_TYPE_FIXED)) {
+ BTM_TRACE_EVENT ("btm_sec_pin_code_request fixed pin replying\n");
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ btsnd_hcic_pin_code_req_reply (p_bda, p_cb->cfg.pin_code_len, p_cb->cfg.pin_code);
+ return;
+ }
+
+ /* Use the connecting device's CoD for the connection */
+ if ( (!memcmp (p_bda, p_cb->connecting_bda, BD_ADDR_LEN))
+ && (p_cb->connecting_dc[0] || p_cb->connecting_dc[1] || p_cb->connecting_dc[2]) ) {
+ memcpy (p_dev_rec->dev_class, p_cb->connecting_dc, DEV_CLASS_LEN);
+ }
+
+ /* We could have started connection after asking user for the PIN code */
+ if (btm_cb.pin_code_len != 0) {
+ BTM_TRACE_EVENT ("btm_sec_pin_code_request bonding sending reply\n");
+ btsnd_hcic_pin_code_req_reply (p_bda, btm_cb.pin_code_len, p_cb->pin_code);
+
+#ifdef PORCHE_PAIRING_CONFLICT
+ btm_cb.pin_code_len_saved = btm_cb.pin_code_len;
+#endif
+
+ /* Mark that we forwarded received from the user PIN code */
+ btm_cb.pin_code_len = 0;
+
+ /* We can change mode back right away, that other connection being established */
+ /* is not forced to be secure - found a FW issue, so we can not do this
+ btm_restore_mode(); */
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ }
+
+ /* If pairing disabled OR (no PIN callback and not bonding) */
+ /* OR we could not allocate entry in the database reject pairing request */
+ else if (p_cb->pairing_disabled
+ || (p_cb->api.p_pin_callback == NULL)
+
+ /* OR Microsoft keyboard can for some reason try to establish connection */
+ /* the only thing we can do here is to shut it up. Normally we will be originator */
+ /* for keyboard bonding */
+ || (!p_dev_rec->is_originator
+ && ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) == BTM_COD_MAJOR_PERIPHERAL)
+ && (p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD)) ) {
+ BTM_TRACE_WARNING("btm_sec_pin_code_request(): Pairing disabled:%d; PIN callback:%p, Dev Rec:%p!\n",
+ p_cb->pairing_disabled, p_cb->api.p_pin_callback, p_dev_rec);
+
+ btsnd_hcic_pin_code_neg_reply (p_bda);
+ }
+ /* Notify upper layer of PIN request and start expiration timer */
+ else {
+ btm_cb.pin_code_len_saved = 0;
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_LOCAL_PIN);
+ /* Pin code request can not come at the same time as connection request */
+ memcpy (p_cb->connecting_bda, p_bda, BD_ADDR_LEN);
+ memcpy (p_cb->connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+ BTM_TRACE_EVENT ("btm_sec_pin_code_request going for callback\n");
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD;
+ if (p_cb->api.p_pin_callback) {
+ (*p_cb->api.p_pin_callback) (p_bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
+ (p_dev_rec->p_cur_service == NULL) ? FALSE
+ : (p_dev_rec->p_cur_service->security_flags
+ & BTM_SEC_IN_MIN_16_DIGIT_PIN));
+ }
+ }
+ return;
+}
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+#endif ///SMP_INCLUDED == TRUE
+
+
+/*******************************************************************************
+**
+** Function btm_sec_update_clock_offset
+**
+** Description This function is called to update clock offset
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_update_clock_offset (UINT16 handle, UINT16 clock_offset)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_INQ_INFO *p_inq_info;
+
+ if ((p_dev_rec = btm_find_dev_by_handle (handle)) == NULL) {
+ return;
+ }
+
+ p_dev_rec->clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID;
+
+ if ((p_inq_info = BTM_InqDbRead(p_dev_rec->bd_addr)) == NULL) {
+ return;
+ }
+
+ p_inq_info->results.clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID;
+}
+
+
+/******************************************************************
+** S T A T I C F U N C T I O N S
+*******************************************************************/
+
+/*******************************************************************************
+**
+** Function btm_sec_execute_procedure
+**
+** Description This function is called to start required security
+** procedure. There is a case when multiplexing protocol
+** calls this function on the originating side, connection to
+** the peer will not be established. This function in this
+** case performs only authorization.
+**
+** Returns BTM_SUCCESS - permission is granted
+** BTM_CMD_STARTED - in process
+** BTM_NO_RESOURCES - permission declined
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static tBTM_STATUS btm_sec_execute_procedure (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ BTM_TRACE_EVENT ("btm_sec_execute_procedure: Required:0x%x Flags:0x%x State:%d\n",
+ p_dev_rec->security_required, p_dev_rec->sec_flags, p_dev_rec->sec_state);
+
+ /* There is a chance that we are getting name. Wait until done. */
+ if (p_dev_rec->sec_state != 0) {
+ return (BTM_CMD_STARTED);
+ }
+
+ /* If any security is required, get the name first */
+ if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN)
+ && (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)) {
+ BTM_TRACE_EVENT ("Security Manager: Start get name\n");
+ if (!btm_sec_start_get_name (p_dev_rec)) {
+ return (BTM_NO_RESOURCES);
+ }
+ return (BTM_CMD_STARTED);
+ }
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ tACL_CONN *p_acl_cb = btm_handle_to_acl(p_dev_rec->hci_handle);
+ /*
+ * To prevent a remote device from doing a Bluetooth Impersonation Attack, a suggested fix by SIG is:
+ *
+ * "Hosts performing legacy (non-mutual) authentication must ensure a remote device is authenticated
+ * prior to proceeding with encryption establishment, regardless of role."
+ *
+ * As an implementation, we enforce mutual authentication when devices use Legacy Authentication.
+ */
+ if ((p_acl_cb != NULL) && (BTM_BothEndsSupportSecureConnections(p_acl_cb->remote_addr) == 0) &&
+ ((p_acl_cb->legacy_auth_state & BTM_ACL_LEGACY_AUTH_SELF) == 0)) {
+ p_dev_rec->sec_flags &= ~BTM_SEC_AUTHENTICATED;
+ }
+#endif
+
+ /* If connection is not authenticated and authentication is required */
+ /* start authentication and return PENDING to the caller */
+ if ((((!(p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))
+ && (( p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE))
+ || (!p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_IN_AUTHENTICATE))))
+ || (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED)
+ && (!p_dev_rec->is_originator
+ && (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN))))
+ && (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)) {
+ /*
+ * We rely on BTM_SEC_16_DIGIT_PIN_AUTHED being set if MITM is in use,
+ * as 16 DIGIT is only needed if MITM is not used. Unfortunately, the
+ * BTM_SEC_AUTHENTICATED is used for both MITM and non-MITM
+ * authenticated connections, hence we cannot distinguish here.
+ */
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ /* if incoming UCD packet, discard it */
+ if ( !p_dev_rec->is_originator && (p_dev_rec->is_ucd == TRUE )) {
+ return (BTM_FAILED_ON_SECURITY);
+ }
+#endif
+
+ BTM_TRACE_EVENT ("Security Manager: Start authentication\n");
+
+ /*
+ * If we do have a link-key, but we end up here because we need an
+ * upgrade, then clear the link-key known and authenticated flag before
+ * restarting authentication.
+ * WARNING: If the controller has link-key, it is optional and
+ * recommended for the controller to send a Link_Key_Request.
+ * In case we need an upgrade, the only alternative would be to delete
+ * the existing link-key. That could lead to very bad user experience
+ * or even IOP issues, if a reconnect causes a new connection that
+ * requires an upgrade.
+ */
+ if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)
+ && (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED)
+ && (!p_dev_rec->is_originator && (p_dev_rec->security_required
+ & BTM_SEC_IN_MIN_16_DIGIT_PIN)))) {
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED
+ | BTM_SEC_AUTHENTICATED);
+ }
+
+ if (!btm_sec_start_authentication (p_dev_rec)) {
+ return (BTM_NO_RESOURCES);
+ }
+ return (BTM_CMD_STARTED);
+ }
+
+ /* If connection is not encrypted and encryption is required */
+ /* start encryption and return PENDING to the caller */
+ if (!(p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED)
+ && (( p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_OUT_ENCRYPT))
+ || (!p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_IN_ENCRYPT)))
+ && (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)) {
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ /* if incoming UCD packet, discard it */
+ if ( !p_dev_rec->is_originator && (p_dev_rec->is_ucd == TRUE )) {
+ return (BTM_FAILED_ON_SECURITY);
+ }
+#endif
+
+ BTM_TRACE_EVENT ("Security Manager: Start encryption\n");
+
+ if (!btm_sec_start_encryption (p_dev_rec)) {
+ return (BTM_NO_RESOURCES);
+ }
+ return (BTM_CMD_STARTED);
+ }
+
+ if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) &&
+ (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ BTM_TRACE_EVENT("%s: Security Manager: SC only service, but link key type is 0x%02x -"
+ "security failure\n", __FUNCTION__, p_dev_rec->link_key_type);
+ return (BTM_FAILED_ON_SECURITY);
+ }
+
+ /* If connection is not authorized and authorization is required */
+ /* start authorization and return PENDING to the caller */
+ if (!(p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED)
+ && (( p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_OUT_AUTHORIZE))
+ || (!p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_IN_AUTHORIZE)))) {
+ BTM_TRACE_EVENT ("service id:%d, is trusted:%d\n",
+ p_dev_rec->p_cur_service->service_id,
+ (BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask,
+ p_dev_rec->p_cur_service->service_id)));
+ if ((btm_sec_are_all_trusted(p_dev_rec->trusted_mask) == FALSE) &&
+ (p_dev_rec->p_cur_service->service_id < BTM_SEC_MAX_SERVICES) &&
+ (BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask,
+ p_dev_rec->p_cur_service->service_id) == FALSE)) {
+ BTM_TRACE_EVENT ("Security Manager: Start authorization\n");
+ return (btm_sec_start_authorization (p_dev_rec));
+ }
+ }
+
+ /* All required security procedures already established */
+ p_dev_rec->security_required &= ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_IN_AUTHORIZE |
+ BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_IN_AUTHENTICATE |
+ BTM_SEC_OUT_ENCRYPT | BTM_SEC_IN_ENCRYPT |
+ BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER |
+ BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
+
+ BTM_TRACE_EVENT ("Security Manager: trusted:0x%04x%04x\n", p_dev_rec->trusted_mask[1], p_dev_rec->trusted_mask[0]);
+ BTM_TRACE_EVENT ("Security Manager: access granted\n");
+
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_start_get_name
+**
+** Description This function is called to start get name procedure
+**
+** Returns TRUE if started
+**
+*******************************************************************************/
+static BOOLEAN btm_sec_start_get_name (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ UINT8 tempstate = p_dev_rec->sec_state;
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_GETTING_NAME;
+
+ /* Device should be connected, no need to provide correct page params */
+ /* 0 and NULL are as timeout and callback params because they are not used in security get name case */
+ if ((btm_initiate_rem_name (p_dev_rec->bd_addr, NULL, BTM_RMT_NAME_SEC,
+ 0, NULL)) != BTM_CMD_STARTED) {
+ p_dev_rec->sec_state = tempstate;
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_start_authentication
+**
+** Description This function is called to start authentication
+**
+** Returns TRUE if started
+**
+*******************************************************************************/
+static BOOLEAN btm_sec_start_authentication (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+
+ return (btsnd_hcic_auth_request (p_dev_rec->hci_handle));
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_start_encryption
+**
+** Description This function is called to start encryption
+**
+** Returns TRUE if started
+**
+*******************************************************************************/
+static BOOLEAN btm_sec_start_encryption (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ if (!btsnd_hcic_set_conn_encrypt (p_dev_rec->hci_handle, TRUE)) {
+ return (FALSE);
+ }
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_ENCRYPTING;
+ return (TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_sec_start_authorization
+**
+** Description This function is called to start authorization
+**
+** Returns TRUE if started
+**
+*******************************************************************************/
+static UINT8 btm_sec_start_authorization (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ UINT8 result;
+ UINT8 *p_service_name = NULL;
+ UINT8 service_id;
+
+ if ((p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN)
+ || (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE)) {
+ if (!btm_cb.api.p_authorize_callback) {
+ return (BTM_MODE_UNSUPPORTED);
+ }
+
+ if (p_dev_rec->p_cur_service) {
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ if (p_dev_rec->is_originator) {
+ p_service_name = p_dev_rec->p_cur_service->orig_service_name;
+ } else {
+ p_service_name = p_dev_rec->p_cur_service->term_service_name;
+ }
+#endif
+ service_id = p_dev_rec->p_cur_service->service_id;
+ } else {
+ service_id = 0;
+ }
+
+ /* Send authorization request if not already sent during this service connection */
+ if (p_dev_rec->last_author_service_id == BTM_SEC_NO_LAST_SERVICE_ID
+ || p_dev_rec->last_author_service_id != service_id) {
+ p_dev_rec->sec_state = BTM_SEC_STATE_AUTHORIZING;
+ result = (*btm_cb.api.p_authorize_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name,
+ p_service_name,
+ service_id,
+ p_dev_rec->is_originator);
+ }
+
+ else { /* Already authorized once for this L2CAP bringup */
+ BTM_TRACE_DEBUG ("btm_sec_start_authorization: (Ignoring extra Authorization prompt for service %d)\n", service_id);
+ return (BTM_SUCCESS);
+ }
+
+ if (result == BTM_SUCCESS) {
+ p_dev_rec->sec_flags |= BTM_SEC_AUTHORIZED;
+
+ /* Save the currently authorized service in case we are asked again by another multiplexer layer */
+ if (!p_dev_rec->is_originator) {
+ p_dev_rec->last_author_service_id = service_id;
+ }
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ }
+ return (result);
+ }
+ btm_sec_start_get_name (p_dev_rec);
+ return (BTM_CMD_STARTED);
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_sec_are_all_trusted
+**
+** Description This function is called check if all services are trusted
+**
+** Returns TRUE if all are trusted, otherwise FALSE
+**
+*******************************************************************************/
+BOOLEAN btm_sec_are_all_trusted(UINT32 p_mask[])
+{
+ UINT32 trusted_inx;
+ for (trusted_inx = 0; trusted_inx < BTM_SEC_SERVICE_ARRAY_SIZE; trusted_inx++) {
+ if (p_mask[trusted_inx] != BTM_SEC_TRUST_ALL) {
+ return (FALSE);
+ }
+ }
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_find_first_serv
+**
+** Description Look for the first record in the service database
+** with specified PSM
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+tBTM_SEC_SERV_REC *btm_sec_find_first_serv (CONNECTION_TYPE conn_type, UINT16 psm)
+{
+ tBTM_SEC_SERV_REC *p_serv_rec = &btm_cb.sec_serv_rec[0];
+ int i;
+ BOOLEAN is_originator;
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+
+ if ( conn_type & CONNECTION_TYPE_ORIG_MASK ) {
+ is_originator = TRUE;
+ } else {
+ is_originator = FALSE;
+ }
+#else
+ is_originator = conn_type;
+#endif
+
+ if (is_originator && btm_cb.p_out_serv && btm_cb.p_out_serv->psm == psm) {
+ /* If this is outgoing connection and the PSM matches p_out_serv,
+ * use it as the current service */
+ return btm_cb.p_out_serv;
+ }
+
+ /* otherwise, just find the first record with the specified PSM */
+ for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++) {
+ if ( (p_serv_rec->security_flags & BTM_SEC_IN_USE) && (p_serv_rec->psm == psm) ) {
+ return (p_serv_rec);
+ }
+ }
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_sec_find_next_serv
+**
+** Description Look for the next record in the service database
+** with specified PSM
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+static tBTM_SEC_SERV_REC *btm_sec_find_next_serv (tBTM_SEC_SERV_REC *p_cur)
+{
+ tBTM_SEC_SERV_REC *p_serv_rec = &btm_cb.sec_serv_rec[0];
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++) {
+ if ((p_serv_rec->security_flags & BTM_SEC_IN_USE)
+ && (p_serv_rec->psm == p_cur->psm) ) {
+ if (p_cur != p_serv_rec) {
+ return (p_serv_rec);
+ }
+ }
+ }
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_find_mx_serv
+**
+** Description Look for the record in the service database with specified
+** PSM and multiplexor channel information
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+static tBTM_SEC_SERV_REC *btm_sec_find_mx_serv (UINT8 is_originator, UINT16 psm,
+ UINT32 mx_proto_id, UINT32 mx_chan_id)
+{
+ tBTM_SEC_SERV_REC *p_out_serv = btm_cb.p_out_serv;
+ tBTM_SEC_SERV_REC *p_serv_rec = &btm_cb.sec_serv_rec[0];
+ int i;
+
+ BTM_TRACE_DEBUG ("%s()\n", __func__);
+ if (is_originator && p_out_serv && p_out_serv->psm == psm
+ && p_out_serv->mx_proto_id == mx_proto_id
+ && p_out_serv->orig_mx_chan_id == mx_chan_id) {
+ /* If this is outgoing connection and the parameters match p_out_serv,
+ * use it as the current service */
+ return btm_cb.p_out_serv;
+ }
+
+ /* otherwise, the old way */
+ for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++) {
+ if ((p_serv_rec->security_flags & BTM_SEC_IN_USE)
+ && (p_serv_rec->psm == psm)
+ && (p_serv_rec->mx_proto_id == mx_proto_id)
+ && (( is_originator && (p_serv_rec->orig_mx_chan_id == mx_chan_id))
+ || (!is_originator && (p_serv_rec->term_mx_chan_id == mx_chan_id)))) {
+ return (p_serv_rec);
+ }
+ }
+ return (NULL);
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_sec_collision_timeout
+**
+** Description Encryption could not start because of the collision
+** try to do it again
+**
+** Returns Pointer to the TLE struct
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static void btm_sec_collision_timeout (TIMER_LIST_ENT *p_tle)
+{
+ UNUSED(p_tle);
+
+ BTM_TRACE_EVENT ("%s()\n", __func__);
+ btm_cb.sec_collision_tle.param = 0;
+
+ tBTM_STATUS status = btm_sec_execute_procedure (btm_cb.p_collided_dev_rec);
+
+ /* If result is pending reply from the user or from the device is pending */
+ if (status != BTM_CMD_STARTED) {
+ /* There is no next procedure or start of procedure failed, notify the waiting layer */
+ btm_sec_dev_rec_cback_event (btm_cb.p_collided_dev_rec, status, FALSE);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_send_link_key_notif
+**
+** Description This function is called when controller requests link key
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+static void btm_send_link_key_notif (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ if (btm_cb.api.p_link_key_callback) {
+ (*btm_cb.api.p_link_key_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, p_dev_rec->link_key,
+ p_dev_rec->link_key_type,
+ p_dev_rec->remote_supports_secure_connections);
+
+ }
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function BTM_ReadTrustedMask
+**
+** Description Get trusted mask for the peer device
+**
+** Parameters: bd_addr - Address of the device
+**
+** Returns NULL, if the device record is not found.
+** otherwise, the trusted mask
+**
+*******************************************************************************/
+UINT32 *BTM_ReadTrustedMask (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+ if (p_dev_rec != NULL) {
+ return (p_dev_rec->trusted_mask);
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function btm_restore_mode
+**
+** Description This function returns the security mode to previous setting
+** if it was changed during bonding.
+**
+**
+** Parameters: void
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static void btm_restore_mode(void)
+{
+ if (btm_cb.security_mode_changed) {
+ btm_cb.security_mode_changed = FALSE;
+ BTM_TRACE_DEBUG("%s() Auth enable -> %d\n", __func__, (btm_cb.security_mode == BTM_SEC_MODE_LINK));
+ btsnd_hcic_write_auth_enable ((UINT8)(btm_cb.security_mode == BTM_SEC_MODE_LINK));
+ }
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ if (btm_cb.pin_type_changed) {
+ btm_cb.pin_type_changed = FALSE;
+ btsnd_hcic_write_pin_type (btm_cb.cfg.pin_type);
+ }
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_sec_find_dev_by_sec_state
+**
+** Description Look for the record in the device database for the device
+** which is being authenticated or encrypted
+**
+** Returns Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_sec_find_dev_by_sec_state (UINT8 state)
+{
+#if (SMP_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+ list_node_t *p_node = NULL;
+ for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
+ p_dev_rec = list_node(p_node);
+ if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE)
+ && (p_dev_rec->sec_state == state)) {
+ return (p_dev_rec);
+ }
+ }
+#endif ///SMP_INCLUDED == TRUE
+ return (NULL);
+}
+/*******************************************************************************
+**
+** Function btm_sec_change_pairing_state
+**
+** Description This function is called to change pairing state
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static void btm_sec_change_pairing_state (tBTM_PAIRING_STATE new_state)
+{
+ tBTM_PAIRING_STATE old_state = btm_cb.pairing_state;
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+ BTM_TRACE_EVENT ("%s() Old: %s\n", __func__, btm_pair_state_descr(btm_cb.pairing_state));
+ BTM_TRACE_EVENT ("%s() New: %s pairing_flags:0x%x\n\n", __func__,
+ btm_pair_state_descr(new_state), btm_cb.pairing_flags);
+#endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE
+
+ btm_cb.pairing_state = new_state;
+
+ if (new_state == BTM_PAIR_STATE_IDLE) {
+ btu_stop_timer (&btm_cb.pairing_tle);
+
+ btm_cb.pairing_flags = 0;
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ btm_cb.pin_code_len = 0;
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+
+ /* Make sure the the lcb shows we are not bonding */
+ l2cu_update_lcb_4_bonding (btm_cb.pairing_bda, FALSE);
+
+ btm_restore_mode();
+ btm_sec_check_pending_reqs();
+ btm_inq_clear_ssp();
+
+ memset (btm_cb.pairing_bda, 0xFF, BD_ADDR_LEN);
+ } else {
+ /* If transitionng out of idle, mark the lcb as bonding */
+ if (old_state == BTM_PAIR_STATE_IDLE) {
+ l2cu_update_lcb_4_bonding (btm_cb.pairing_bda, TRUE);
+ }
+
+ btm_cb.pairing_tle.param = (TIMER_PARAM_TYPE)btm_sec_pairing_timeout;
+
+ btu_start_timer (&btm_cb.pairing_tle, BTU_TTYPE_USER_FUNC, BTM_SEC_TIMEOUT_VALUE);
+ }
+}
+#endif ///SMP_INCLUDED == TRUE
+
+
+/*******************************************************************************
+**
+** Function btm_pair_state_descr
+**
+** Description Return state description for tracing
+**
+*******************************************************************************/
+#if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE)
+static char *btm_pair_state_descr (tBTM_PAIRING_STATE state)
+{
+#if (BT_TRACE_VERBOSE == TRUE)
+ switch (state) {
+ case BTM_PAIR_STATE_IDLE: return ("IDLE");
+ case BTM_PAIR_STATE_GET_REM_NAME: return ("GET_REM_NAME");
+ case BTM_PAIR_STATE_WAIT_PIN_REQ: return ("WAIT_PIN_REQ");
+ case BTM_PAIR_STATE_WAIT_LOCAL_PIN: return ("WAIT_LOCAL_PIN");
+ case BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM: return ("WAIT_NUM_CONFIRM");
+ case BTM_PAIR_STATE_KEY_ENTRY: return ("KEY_ENTRY");
+ case BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP: return ("WAIT_LOCAL_OOB_RSP");
+ case BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS: return ("WAIT_LOCAL_IOCAPS");
+ case BTM_PAIR_STATE_INCOMING_SSP: return ("INCOMING_SSP");
+ case BTM_PAIR_STATE_WAIT_AUTH_COMPLETE: return ("WAIT_AUTH_COMPLETE");
+ case BTM_PAIR_STATE_WAIT_DISCONNECT: return ("WAIT_DISCONNECT");
+ }
+
+ return ("???");
+#else
+ sprintf(btm_cb.state_temp_buffer, "%d", state);
+
+ return (btm_cb.state_temp_buffer);
+#endif
+}
+#endif
+
+/*******************************************************************************
+**
+** Function btm_sec_dev_rec_cback_event
+**
+** Description This function calls the callback function with the given
+** result and clear the callback function.
+**
+** Parameters: void
+**
+*******************************************************************************/
+void btm_sec_dev_rec_cback_event (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 res, BOOLEAN is_le_transport)
+{
+ tBTM_SEC_CALLBACK *p_callback;
+
+ if (p_dev_rec && p_dev_rec->p_callback) {
+ p_callback = p_dev_rec->p_callback;
+ p_dev_rec->p_callback = NULL;
+
+#if BLE_INCLUDED == TRUE
+ if (is_le_transport) {
+ (*p_callback) (p_dev_rec->ble.pseudo_addr, BT_TRANSPORT_LE, p_dev_rec->p_ref_data, res);
+ } else
+#endif
+ {
+ (*p_callback) (p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR, p_dev_rec->p_ref_data, res);
+ }
+ }
+#if (SMP_INCLUDED == TRUE)
+ btm_sec_check_pending_reqs();
+#endif ///SMP_INCLUDED == TRUE
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_queue_mx_request
+**
+** Description Return state description for tracing
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static BOOLEAN btm_sec_queue_mx_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_orig,
+ UINT32 mx_proto_id, UINT32 mx_chan_id,
+ tBTM_SEC_CALLBACK *p_callback, void *p_ref_data)
+{
+ tBTM_SEC_QUEUE_ENTRY *p_e = (tBTM_SEC_QUEUE_ENTRY *)osi_malloc (sizeof(tBTM_SEC_QUEUE_ENTRY));
+
+ if (p_e) {
+ p_e->psm = psm;
+ p_e->is_orig = is_orig;
+ p_e->p_callback = p_callback;
+ p_e->p_ref_data = p_ref_data;
+ p_e->mx_proto_id = mx_proto_id;
+ p_e->mx_chan_id = mx_chan_id;
+ p_e->transport = BT_TRANSPORT_BR_EDR;
+
+ memcpy (p_e->bd_addr, bd_addr, BD_ADDR_LEN);
+
+ BTM_TRACE_EVENT ("%s() PSM: 0x%04x Is_Orig: %u mx_proto_id: %u mx_chan_id: %u\n",
+ __func__, psm, is_orig, mx_proto_id, mx_chan_id);
+
+ fixed_queue_enqueue(btm_cb.sec_pending_q, p_e, FIXED_QUEUE_MAX_TIMEOUT);
+
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+static BOOLEAN btm_sec_check_prefetch_pin (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ BOOLEAN rv = FALSE;
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ UINT8 major = (UINT8)(p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK);
+ UINT8 minor = (UINT8)(p_dev_rec->dev_class[2] & BTM_COD_MINOR_CLASS_MASK);
+ rv = TRUE;
+
+ if ((major == BTM_COD_MAJOR_AUDIO)
+ && ((minor == BTM_COD_MINOR_CONFM_HANDSFREE) || (minor == BTM_COD_MINOR_CAR_AUDIO)) ) {
+ BTM_TRACE_EVENT ("%s() Skipping pre-fetch PIN for carkit COD Major: 0x%02x Minor: 0x%02x\n",
+ __func__, major, minor);
+
+ if (btm_cb.security_mode_changed == FALSE) {
+ btm_cb.security_mode_changed = TRUE;
+#ifdef APPL_AUTH_WRITE_EXCEPTION
+ if (!(APPL_AUTH_WRITE_EXCEPTION)(p_dev_rec->bd_addr))
+#endif
+ {
+ btsnd_hcic_write_auth_enable (TRUE);
+ }
+ }
+ } else {
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_LOCAL_PIN);
+
+ /* If we got a PIN, use that, else try to get one */
+ if (btm_cb.pin_code_len) {
+ BTM_PINCodeReply (p_dev_rec->bd_addr, BTM_SUCCESS, btm_cb.pin_code_len, btm_cb.pin_code, p_dev_rec->trusted_mask);
+ } else {
+ /* pin was not supplied - pre-fetch pin code now */
+ if (btm_cb.api.p_pin_callback && ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PIN_REQD) == 0)) {
+ BTM_TRACE_DEBUG("%s() PIN code callback called\n", __func__);
+ if (btm_bda_to_acl(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR) == NULL) {
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD;
+ }
+ (btm_cb.api.p_pin_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, (p_dev_rec->p_cur_service == NULL) ? FALSE
+ : (p_dev_rec->p_cur_service->security_flags
+ & BTM_SEC_IN_MIN_16_DIGIT_PIN));
+ }
+ }
+
+ rv = TRUE;
+ }
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+#
+ return rv;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_auth_payload_tout
+**
+** Description Processes the HCI Autheniticated Payload Timeout Event
+** indicating that a packet containing a valid MIC on the
+** connection handle was not received within the programmed
+** timeout value. (Spec Default is 30 secs, but can be
+** changed via the BTM_SecSetAuthPayloadTimeout() function.
+**
+*******************************************************************************/
+void btm_sec_auth_payload_tout (UINT8 *p, UINT16 hci_evt_len)
+{
+ UINT16 handle;
+
+ STREAM_TO_UINT16 (handle, p);
+ handle = HCID_GET_HANDLE (handle);
+
+ /* Will be exposed to upper layers in the future if/when determined necessary */
+ BTM_TRACE_ERROR ("%s on handle 0x%02x\n", __func__, handle);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_queue_encrypt_request
+**
+** Description encqueue encryption request when device has active security
+** process pending.
+**
+*******************************************************************************/
+static BOOLEAN btm_sec_queue_encrypt_request (BD_ADDR bd_addr, tBT_TRANSPORT transport,
+ tBTM_SEC_CALLBACK *p_callback, void *p_ref_data)
+{
+ tBTM_SEC_QUEUE_ENTRY *p_e;
+ p_e = (tBTM_SEC_QUEUE_ENTRY *)osi_malloc(sizeof(tBTM_SEC_QUEUE_ENTRY) + 1);
+
+ if (p_e) {
+ p_e->psm = 0; /* if PSM 0, encryption request */
+ p_e->p_callback = p_callback;
+ p_e->p_ref_data = (void *)(p_e + 1);
+ *(UINT8 *)p_e->p_ref_data = *(UINT8 *)(p_ref_data);
+ p_e->transport = transport;
+ memcpy(p_e->bd_addr, bd_addr, BD_ADDR_LEN);
+ fixed_queue_enqueue(btm_cb.sec_pending_q, p_e, FIXED_QUEUE_MAX_TIMEOUT);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_set_peer_sec_caps
+**
+** Description This function is called to set sm4 and rmt_sec_caps fields
+** based on the available peer device features.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_set_peer_sec_caps(tACL_CONN *p_acl_cb, tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ BD_ADDR rem_bd_addr;
+ UINT8 *p_rem_bd_addr;
+
+ if ((btm_cb.security_mode == BTM_SEC_MODE_SP ||
+ btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+ btm_cb.security_mode == BTM_SEC_MODE_SC) &&
+ HCI_SSP_HOST_SUPPORTED(p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_1])) {
+ p_dev_rec->sm4 = BTM_SM4_TRUE;
+ p_dev_rec->remote_supports_secure_connections =
+ (HCI_SC_HOST_SUPPORTED(p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_1]));
+ } else {
+ p_dev_rec->sm4 = BTM_SM4_KNOWN;
+ p_dev_rec->remote_supports_secure_connections = FALSE;
+ }
+
+ BTM_TRACE_API("%s: sm4: 0x%02x, rmt_support_for_secure_connections %d\n", __FUNCTION__,
+ p_dev_rec->sm4, p_dev_rec->remote_supports_secure_connections);
+
+ /* Store previous state of remote device to check if peer device downgraded
+ * it's secure connection state. */
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ if (p_dev_rec->remote_supports_secure_connections >= p_dev_rec->remote_secure_connection_previous_state) {
+ p_dev_rec->remote_secure_connection_previous_state = p_dev_rec->remote_supports_secure_connections;
+ } else {
+ BTM_TRACE_ERROR("Remote Device downgraded security from SC, deleting Link Key");
+
+ /* Mark in ACL packet that secure connection is downgraded. */
+ p_acl_cb->sc_downgrade = 1;
+ p_dev_rec->remote_secure_connection_previous_state = 0;
+
+ /* As peer device downgraded it's security, peer device is a suspicious
+ * device. Hence remove pairing information by removing link key
+ * information. */
+ memset(p_dev_rec->link_key, 0, LINK_KEY_LEN);
+ p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED
+ | BTM_SEC_ENCRYPTED | BTM_SEC_NAME_KNOWN
+ | BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED
+ | BTM_SEC_ROLE_SWITCHED | BTM_SEC_16_DIGIT_PIN_AUTHED);
+ return;
+ }
+#endif
+
+ if (p_dev_rec->remote_features_needed) {
+ BTM_TRACE_EVENT("%s: Now device in SC Only mode, waiting for peer remote features!\n",
+ __FUNCTION__);
+ p_rem_bd_addr = (UINT8 *) rem_bd_addr;
+ BDADDR_TO_STREAM(p_rem_bd_addr, p_dev_rec->bd_addr);
+ p_rem_bd_addr = (UINT8 *) rem_bd_addr;
+ btm_io_capabilities_req(p_rem_bd_addr);
+ p_dev_rec->remote_features_needed = FALSE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_is_serv_level0
+**
+** Description This function is called to check if the service corresponding
+** to PSM is security mode 4 level 0 service.
+**
+** Returns TRUE if the service is security mode 4 level 0 service
+**
+*******************************************************************************/
+static BOOLEAN btm_sec_is_serv_level0(UINT16 psm)
+{
+ if (psm == BT_PSM_SDP) {
+ BTM_TRACE_DEBUG("%s: PSM: 0x%04x -> mode 4 level 0 service\n", __FUNCTION__, psm);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_check_pending_enc_req
+**
+** Description This function is called to send pending encryption callback if
+** waiting
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_sec_check_pending_enc_req (tBTM_SEC_DEV_REC *p_dev_rec, tBT_TRANSPORT transport,
+ UINT8 encr_enable)
+{
+ if (fixed_queue_is_empty(btm_cb.sec_pending_q)) {
+ return;
+ }
+
+ UINT8 res = encr_enable ? BTM_SUCCESS : BTM_ERR_PROCESSING;
+ list_t *list = fixed_queue_get_list(btm_cb.sec_pending_q);
+ for (const list_node_t *node = list_begin(list); node != list_end(list); ) {
+ tBTM_SEC_QUEUE_ENTRY *p_e = (tBTM_SEC_QUEUE_ENTRY *)list_node(node);
+ node = list_next(node);
+
+ if (memcmp(p_e->bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0 && p_e->psm == 0
+#if BLE_INCLUDED == TRUE
+ && p_e->transport == transport
+#endif
+ ) {
+#if BLE_INCLUDED == TRUE
+ UINT8 sec_act = *(UINT8 *)(p_e->p_ref_data);
+#endif
+
+ if (encr_enable == 0 || transport == BT_TRANSPORT_BR_EDR
+#if BLE_INCLUDED == TRUE
+ || (sec_act == BTM_BLE_SEC_ENCRYPT || sec_act == BTM_BLE_SEC_ENCRYPT_NO_MITM)
+ || (sec_act == BTM_BLE_SEC_ENCRYPT_MITM && p_dev_rec->sec_flags
+ & BTM_SEC_LE_AUTHENTICATED)
+#endif
+ ) {
+ if (p_e->p_callback) {
+ (*p_e->p_callback) (p_dev_rec->bd_addr, transport, p_e->p_ref_data, res);
+ }
+
+ fixed_queue_try_remove_from_queue(btm_cb.sec_pending_q, (void *)p_e);
+ }
+ }
+ }
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_sec_set_serv_level4_flags
+**
+** Description This function is called to set security mode 4 level 4 flags.
+**
+** Returns service security requirements updated to include secure
+** connections only mode.
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static UINT16 btm_sec_set_serv_level4_flags(UINT16 cur_security, BOOLEAN is_originator)
+{
+ UINT16 sec_level4_flags = is_originator ? BTM_SEC_OUT_LEVEL4_FLAGS : BTM_SEC_IN_LEVEL4_FLAGS;
+
+ return cur_security | sec_level4_flags;
+}
+#endif ///SMP_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_sec_clear_ble_keys
+**
+** Description This function is called to clear out the BLE keys.
+** Typically when devices are removed in BTM_SecDeleteDevice,
+** or when a new BT Link key is generated.
+**
+** Returns void
+**
+*******************************************************************************/
+#if (BLE_INCLUDED == TRUE)
+void btm_sec_clear_ble_keys (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+
+ BTM_TRACE_DEBUG ("%s() Clearing BLE Keys\n", __func__);
+#if (SMP_INCLUDED== TRUE)
+ p_dev_rec->ble.key_type = BTM_LE_KEY_NONE;
+ memset (&p_dev_rec->ble.keys, 0, sizeof(tBTM_SEC_BLE_KEYS));
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ btm_ble_resolving_list_remove_dev(p_dev_rec);
+#endif
+#endif
+}
+#endif ///BLE_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function btm_sec_is_a_bonded_dev
+**
+** Description Is the specified device is a bonded device
+**
+** Returns TRUE - dev is bonded
+**
+*******************************************************************************/
+BOOLEAN btm_sec_is_a_bonded_dev (BD_ADDR bda)
+{
+
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda);
+ BOOLEAN is_bonded = FALSE;
+
+ if (p_dev_rec &&
+#if (SMP_INCLUDED == TRUE && BLE_INCLUDED == TRUE)
+ ((p_dev_rec->ble.key_type && (p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN)) ||
+#else
+ (
+#endif
+ (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN))) {
+ is_bonded = TRUE;
+ }
+ BTM_TRACE_DEBUG ("%s() is_bonded=%d\n", __func__, is_bonded);
+ return (is_bonded);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_is_le_capable_dev
+**
+** Description Is the specified device is dual mode or LE only device
+**
+** Returns TRUE - dev is a dual mode
+**
+*******************************************************************************/
+BOOLEAN btm_sec_is_le_capable_dev (BD_ADDR bda)
+{
+ BOOLEAN le_capable = FALSE;
+
+#if (BLE_INCLUDED== TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda);
+ if (p_dev_rec && (p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE) {
+ le_capable = TRUE;
+ }
+#endif
+ return le_capable;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_find_bonded_dev
+**
+** Description Find a bonded device starting from the specified index
+**
+** Returns TRUE - found a bonded device
+**
+*******************************************************************************/
+#if (BLE_INCLUDED == TRUE)
+BOOLEAN btm_sec_find_bonded_dev (UINT8 start_idx, UINT16 *p_found_handle, tBTM_SEC_DEV_REC **p_rec)
+{
+ BOOLEAN found = FALSE;
+
+#if (SMP_INCLUDED== TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ list_node_t *p_node = NULL;
+ for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
+ p_dev_rec = list_node(p_node);
+ if (p_dev_rec->ble.key_type || (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) {
+ *p_found_handle = p_dev_rec->hci_handle;
+ *p_rec = p_dev_rec;
+ break;
+ }
+ }
+ BTM_TRACE_DEBUG ("%s() found=%d\n", __func__, found);
+#endif
+ return (found);
+}
+#endif ///BLE_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function btm_sec_use_smp_br_chnl
+**
+** Description The function checks if SMP BR connection can be used with
+** the peer.
+** Is called when authentication for dedicated bonding is
+** successfully completed.
+**
+** Returns TRUE - if SMP BR connection can be used (the link key is
+** generated from P-256 and the peer supports Security
+** Manager over BR).
+**
+*******************************************************************************/
+#if (SMP_INCLUDED == TRUE)
+static BOOLEAN btm_sec_use_smp_br_chnl(tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ UINT32 ext_feat;
+ UINT8 chnl_mask[L2CAP_FIXED_CHNL_ARRAY_SIZE];
+
+ BTM_TRACE_DEBUG ("%s() link_key_type = 0x%x\n", __func__,
+ p_dev_rec->link_key_type);
+
+ if ((p_dev_rec->link_key_type != BTM_LKEY_TYPE_UNAUTH_COMB_P_256) &&
+ (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ return FALSE;
+ }
+
+ if (!L2CA_GetPeerFeatures (p_dev_rec->bd_addr, &ext_feat, chnl_mask)) {
+ return FALSE;
+ }
+
+ if (!(chnl_mask[0] & L2CAP_FIXED_CHNL_SMP_BR_BIT)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_is_master
+**
+** Description The function checks if the device is BR/EDR master after
+** pairing is completed.
+**
+** Returns TRUE - if the device is master.
+**
+*******************************************************************************/
+static BOOLEAN btm_sec_is_master(tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ tACL_CONN *p = btm_bda_to_acl(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR);
+ return (p && (p->link_role == BTM_ROLE_MASTER));
+}
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function btm_sec_legacy_authentication_mutual
+**
+** Description This function is called when legacy authentication is used
+** and only remote device has completed the authentication
+**
+** Returns TRUE if aunthentication command sent successfully
+**
+*******************************************************************************/
+BOOLEAN btm_sec_legacy_authentication_mutual (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ return (btm_sec_start_authentication (p_dev_rec));
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_update_legacy_auth_state
+**
+** Description This function updates the legacy authentication state
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_update_legacy_auth_state(tACL_CONN *p_acl_cb, UINT8 legacy_auth_state)
+{
+ if (p_acl_cb) {
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (p_acl_cb->hci_handle);
+ if (p_dev_rec) {
+ if ((BTM_BothEndsSupportSecureConnections(p_dev_rec->bd_addr) == 0) &&
+ (legacy_auth_state != BTM_ACL_LEGACY_AUTH_NONE)) {
+ p_acl_cb->legacy_auth_state |= legacy_auth_state;
+ } else {
+ p_acl_cb->legacy_auth_state = BTM_ACL_LEGACY_AUTH_NONE;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_handle_remote_legacy_auth_cmp
+**
+** Description This function updates the legacy authneticaiton state
+** to indicate that remote device has completed the authentication
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_handle_remote_legacy_auth_cmp(UINT16 handle)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
+ tACL_CONN *p_acl_cb = btm_bda_to_acl(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR);
+ btm_sec_update_legacy_auth_state(p_acl_cb, BTM_ACL_LEGACY_AUTH_REMOTE);
+}
+#endif /// (CLASSIC_BT_INCLUDED == TRUE)
+#endif ///SMP_INCLUDED == TRUE
+
+/******************************************************************************
+ **
+ ** Function btm_sec_dev_authorization
+ **
+ ** Description This function is used to authorize a specified device(BLE)
+ **
+ ******************************************************************************
+ */
+#if (BLE_INCLUDED == TRUE)
+BOOLEAN btm_sec_dev_authorization(BD_ADDR bd_addr, BOOLEAN authorized)
+{
+#if (SMP_INCLUDED == TRUE)
+ UINT8 sec_flag = 0;
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec) {
+ sec_flag = (UINT8)(p_dev_rec->sec_flags >> 8);
+ if (!(sec_flag & BTM_SEC_LINK_KEY_AUTHED)) {
+ BTM_TRACE_ERROR("Authorized should after successful Authentication(MITM protection)\n");
+ return FALSE;
+ }
+
+ if (authorized) {
+ p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHORIZATION;
+ } else {
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LE_AUTHORIZATION);
+ }
+ } else {
+ BTM_TRACE_ERROR("%s, can't find device\n", __func__);
+ return FALSE;
+ }
+ return TRUE;
+#endif ///SMP_INCLUDED == TRUE
+ return FALSE;
+}
+#endif /// BLE_INCLUDE == TRUE
diff --git a/lib/bt/host/bluedroid/stack/btm/include/btm_ble_int.h b/lib/bt/host/bluedroid/stack/btm/include/btm_ble_int.h
new file mode 100644
index 00000000..1f55289c
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/include/btm_ble_int.h
@@ -0,0 +1,548 @@
+/******************************************************************************
+ *
+ * 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 the main Bluetooth Manager (BTM) internal
+ * definitions.
+ *
+ ******************************************************************************/
+
+#ifndef BTM_BLE_INT_H
+#define BTM_BLE_INT_H
+
+#include "common/bt_target.h"
+#include "osi/fixed_queue.h"
+#include "osi/pkt_queue.h"
+#include "osi/thread.h"
+#include "stack/hcidefs.h"
+#include "stack/btm_ble_api.h"
+#include "btm_int.h"
+
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+#include "stack/smp_api.h"
+#endif
+
+
+/* scanning enable status */
+#define BTM_BLE_SCAN_ENABLE 0x01
+#define BTM_BLE_SCAN_DISABLE 0x00
+
+/* advertising enable status */
+#define BTM_BLE_ADV_ENABLE 0x01
+#define BTM_BLE_ADV_DISABLE 0x00
+
+/* use the high 4 bits unused by inquiry mode */
+#define BTM_BLE_SELECT_SCAN 0x20
+#define BTM_BLE_NAME_REQUEST 0x40
+#define BTM_BLE_OBSERVE 0x80
+
+#define BTM_BLE_MAX_WL_ENTRY 1
+#define BTM_BLE_AD_DATA_LEN 31
+
+#define BTM_BLE_ENC_MASK 0x03
+
+#define BTM_BLE_DUPLICATE_DISABLE 0
+#define BTM_BLE_DUPLICATE_ENABLE 1
+#define BTM_BLE_DUPLICATE_MAX BTM_BLE_DUPLICATE_ENABLE
+
+#define BTM_BLE_GAP_DISC_SCAN_INT 18 /* Interval(scan_int) = 11.25 ms= 0x0010 * 0.625 ms */
+#define BTM_BLE_GAP_DISC_SCAN_WIN 18 /* scan_window = 11.25 ms= 0x0010 * 0.625 ms */
+#define BTM_BLE_GAP_ADV_INT 512 /* Tgap(gen_disc) = 1.28 s= 512 * 0.625 ms */
+#define BTM_BLE_GAP_LIM_TOUT 180 /* Tgap(lim_timeout) = 180s max */
+#define BTM_BLE_LOW_LATENCY_SCAN_INT 8000 /* Interval(scan_int) = 5s= 8000 * 0.625 ms */
+#define BTM_BLE_LOW_LATENCY_SCAN_WIN 8000 /* scan_window = 5s= 8000 * 0.625 ms */
+
+
+#define BTM_BLE_GAP_ADV_FAST_INT_1 48 /* TGAP(adv_fast_interval1) = 30(used) ~ 60 ms = 48 *0.625 */
+#define BTM_BLE_GAP_ADV_FAST_INT_2 160 /* TGAP(adv_fast_interval2) = 100(used) ~ 150 ms = 160 * 0.625 ms */
+#define BTM_BLE_GAP_ADV_SLOW_INT 2048 /* Tgap(adv_slow_interval) = 1.28 s= 512 * 0.625 ms */
+#define BTM_BLE_GAP_ADV_DIR_MAX_INT 800 /* Tgap(dir_conn_adv_int_max) = 500 ms = 800 * 0.625 ms */
+#define BTM_BLE_GAP_ADV_DIR_MIN_INT 400 /* Tgap(dir_conn_adv_int_min) = 250 ms = 400 * 0.625 ms */
+
+#define BTM_BLE_GAP_FAST_ADV_TOUT 30
+
+#define BTM_BLE_SEC_REQ_ACT_NONE 0
+#define BTM_BLE_SEC_REQ_ACT_ENCRYPT 1 /* encrypt the link using current key or key refresh */
+#define BTM_BLE_SEC_REQ_ACT_PAIR 2
+#define BTM_BLE_SEC_REQ_ACT_DISCARD 3 /* discard the sec request while encryption is started but not completed */
+typedef UINT8 tBTM_BLE_SEC_REQ_ACT;
+
+#define BLE_STATIC_PRIVATE_MSB_MASK 0x3f
+#define BLE_NON_RESOLVE_ADDR_MSB 0x00 /* most significant bit, bit7, bit6 is 00 to be non-resolvable random */
+#define BLE_RESOLVE_ADDR_MSB 0x40 /* most significant bit, bit7, bit6 is 01 to be resolvable random */
+#define BLE_RESOLVE_ADDR_MASK 0xc0 /* bit 6, and bit7 */
+#define BTM_BLE_IS_NON_RESLVE_BDA(x) ((x[0] & BLE_RESOLVE_ADDR_MASK) == BLE_NON_RESOLVE_ADDR_MSB)
+#define BTM_BLE_IS_RESOLVE_BDA(x) ((x[0] & BLE_RESOLVE_ADDR_MASK) == BLE_RESOLVE_ADDR_MSB)
+
+/* LE scan activity bit mask, continue with LE inquiry bits */
+#define BTM_LE_SELECT_CONN_ACTIVE 0x0040 /* selection connection is in progress */
+#define BTM_LE_OBSERVE_ACTIVE 0x0080 /* observe is in progress */
+#define BTM_LE_DISCOVER_ACTIVE 0x0100 /* scan is in progress */
+
+/* BLE scan activity mask checking */
+#define BTM_BLE_IS_SCAN_ACTIVE(x) ((x) & BTM_BLE_SCAN_ACTIVE_MASK)
+#define BTM_BLE_IS_INQ_ACTIVE(x) ((x) & BTM_BLE_INQUIRY_MASK)
+#define BTM_BLE_IS_OBS_ACTIVE(x) ((x) & BTM_LE_OBSERVE_ACTIVE)
+#define BTM_BLE_IS_DISCO_ACTIVE(x) ((x) & BTM_LE_DISCOVER_ACTIVE)
+#define BTM_BLE_IS_SEL_CONN_ACTIVE(x) ((x) & BTM_LE_SELECT_CONN_ACTIVE)
+
+/* BLE ADDR type ID bit */
+#define BLE_ADDR_TYPE_ID_BIT 0x02
+
+#define BTM_VSC_CHIP_CAPABILITY_L_VERSION 55
+#define BTM_VSC_CHIP_CAPABILITY_M_VERSION 95
+
+typedef enum {
+ BTM_BLE_IDLE = 0,
+ BTM_BLE_SCANNING = 1,
+ BTM_BLE_ADVERTISING = 2,
+}tBTM_BLE_GAP_STATE;
+
+typedef struct {
+ UINT16 data_mask;
+ UINT8 *p_flags;
+ UINT8 ad_data[BTM_BLE_AD_DATA_LEN];
+ UINT8 *p_pad;
+} tBTM_BLE_LOCAL_ADV_DATA;
+
+typedef struct {
+ UINT32 inq_count; /* Used for determining if a response has already been */
+ /* received for the current inquiry operation. (We do not */
+ /* want to flood the caller with multiple responses from */
+ /* the same device. */
+ BOOLEAN scan_rsp;
+ tBLE_BD_ADDR le_bda;
+} tINQ_LE_BDADDR;
+
+#define BTM_BLE_ADV_DATA_LEN_MAX 31
+#define BTM_BLE_CACHE_ADV_DATA_MAX 62
+#if (BLE_50_FEATURE_SUPPORT == TRUE)
+#define BTM_BLE_EXT_ADV_DATA_LEN_MAX 251
+#define BTM_BLE_PERIODIC_ADV_DATA_LEN_MAX 252
+
+#define BTM_BLE_ADV_DATA_OP_INTERMEDIATE_FRAG 0
+#define BTM_BLE_ADV_DATA_OP_FIRST_FRAG 1
+#define BTM_BLE_ADV_DATA_OP_LAST_FRAG 2
+#define BTM_BLE_ADV_DATA_OP_COMPLETE 3
+#define BTM_BLE_ADV_DATA_OP_UNCHANGED_DATA 4
+#endif // #if (BLE_50_FEATURE_SUPPORT == TRUE)
+
+#define BTM_BLE_ISVALID_PARAM(x, min, max) (((x) >= (min) && (x) <= (max)) || ((x) == BTM_BLE_CONN_PARAM_UNDEF))
+
+typedef struct {
+ UINT16 discoverable_mode;
+ UINT16 connectable_mode;
+ BOOLEAN scan_params_set;
+ UINT32 scan_window;
+ UINT32 scan_interval;
+ UINT8 scan_type; /* current scan type: active or passive */
+ UINT8 scan_duplicate_filter; /* duplicate filter enabled for scan */
+ UINT16 adv_interval_min;
+ UINT16 adv_interval_max;
+ tBTM_BLE_AFP afp; /* advertising filter policy */
+ tBTM_BLE_SFP sfp; /* scanning filter policy */
+ tBTM_START_ADV_CMPL_CBACK *p_adv_cb;
+ tBTM_START_STOP_ADV_CMPL_CBACK *p_stop_adv_cb;
+ tBTM_CLEAR_ADV_CMPL_CBACK *p_clear_adv_cb;
+ tBLE_ADDR_TYPE adv_addr_type;
+ UINT8 evt_type;
+ UINT8 adv_mode;
+ tBLE_BD_ADDR direct_bda;
+ tBTM_BLE_EVT directed_conn;
+ BOOLEAN fast_adv_on;
+ TIMER_LIST_ENT fast_adv_timer;
+
+ UINT8 adv_len;
+ UINT8 adv_data_cache[BTM_BLE_CACHE_ADV_DATA_MAX];
+ BD_ADDR adv_addr;
+ /* inquiry BD addr database */
+ UINT8 num_bd_entries;
+ UINT8 max_bd_entries;
+ tBTM_BLE_LOCAL_ADV_DATA adv_data;
+ tBTM_BLE_ADV_CHNL_MAP adv_chnl_map;
+
+ TIMER_LIST_ENT inq_timer_ent;
+ BOOLEAN scan_rsp;
+ tBTM_BLE_GAP_STATE state; /* Current state that the adv or scan process is in */
+ INT8 tx_power;
+} tBTM_BLE_INQ_CB;
+
+
+/* random address resolving complete callback */
+typedef void (tBTM_BLE_RESOLVE_CBACK) (void *match_rec, void *p);
+
+typedef void (tBTM_BLE_ADDR_CBACK) (BD_ADDR_PTR static_random, void *p);
+
+#define BTM_BLE_GAP_ADDR_BIT_RANDOM (1<<0)
+#define BTM_BLE_GAP_ADDR_BIT_RESOLVABLE (1<<1)
+
+/* random address management control block */
+typedef struct {
+ tBLE_ADDR_TYPE own_addr_type; /* local device LE address type */
+ UINT8 exist_addr_bit;
+ BD_ADDR static_rand_addr;
+ BD_ADDR resolvale_addr;
+ BD_ADDR private_addr;
+ BD_ADDR random_bda;
+ BOOLEAN busy;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_BLE_RESOLVE_CBACK *p_resolve_cback;
+ tBTM_BLE_ADDR_CBACK *p_generate_cback;
+ void *p;
+ TIMER_LIST_ENT raddr_timer_ent;
+ tBTM_SET_LOCAL_PRIVACY_CBACK *set_local_privacy_cback;
+} tBTM_LE_RANDOM_CB;
+
+#define BTM_BLE_MAX_BG_CONN_DEV_NUM 10
+
+typedef struct {
+ UINT16 min_conn_int;
+ UINT16 max_conn_int;
+ UINT16 slave_latency;
+ UINT16 supervision_tout;
+
+} tBTM_LE_CONN_PRAMS;
+
+
+typedef struct {
+ BD_ADDR bd_addr;
+ UINT8 attr;
+ BOOLEAN is_connected;
+ BOOLEAN in_use;
+} tBTM_LE_BG_CONN_DEV;
+
+/* white list using state as a bit mask */
+#define BTM_BLE_WL_IDLE 0
+#define BTM_BLE_WL_INIT 1
+#define BTM_BLE_WL_SCAN 2
+#define BTM_BLE_WL_ADV 4
+typedef UINT8 tBTM_BLE_WL_STATE;
+
+/* resolving list using state as a bit mask */
+#define BTM_BLE_RL_IDLE 0
+#define BTM_BLE_RL_INIT 1
+#define BTM_BLE_RL_SCAN 2
+#define BTM_BLE_RL_ADV 4
+typedef UINT8 tBTM_BLE_RL_STATE;
+
+/* BLE connection state */
+#define BLE_CONN_IDLE 0
+#define BLE_DIR_CONN 1
+#define BLE_BG_CONN 2
+#define BLE_CONN_CANCEL 3
+typedef UINT8 tBTM_BLE_CONN_ST;
+
+typedef struct {
+ void *p_param;
+} tBTM_BLE_CONN_REQ;
+
+/* LE state request */
+#define BTM_BLE_STATE_INVALID 0
+#define BTM_BLE_STATE_CONN_ADV 1
+#define BTM_BLE_STATE_INIT 2
+#define BTM_BLE_STATE_MASTER 3
+#define BTM_BLE_STATE_SLAVE 4
+#define BTM_BLE_STATE_LO_DUTY_DIR_ADV 5
+#define BTM_BLE_STATE_HI_DUTY_DIR_ADV 6
+#define BTM_BLE_STATE_NON_CONN_ADV 7
+#define BTM_BLE_STATE_PASSIVE_SCAN 8
+#define BTM_BLE_STATE_ACTIVE_SCAN 9
+#define BTM_BLE_STATE_SCAN_ADV 10
+#define BTM_BLE_STATE_MAX 11
+typedef UINT8 tBTM_BLE_STATE;
+
+#define BTM_BLE_STATE_CONN_ADV_BIT 0x0001
+#define BTM_BLE_STATE_INIT_BIT 0x0002
+#define BTM_BLE_STATE_MASTER_BIT 0x0004
+#define BTM_BLE_STATE_SLAVE_BIT 0x0008
+#define BTM_BLE_STATE_LO_DUTY_DIR_ADV_BIT 0x0010
+#define BTM_BLE_STATE_HI_DUTY_DIR_ADV_BIT 0x0020
+#define BTM_BLE_STATE_NON_CONN_ADV_BIT 0x0040
+#define BTM_BLE_STATE_PASSIVE_SCAN_BIT 0x0080
+#define BTM_BLE_STATE_ACTIVE_SCAN_BIT 0x0100
+#define BTM_BLE_STATE_SCAN_ADV_BIT 0x0200
+typedef UINT16 tBTM_BLE_STATE_MASK;
+
+#define BTM_BLE_STATE_ALL_MASK 0x03ff
+#define BTM_BLE_STATE_ALL_ADV_MASK (BTM_BLE_STATE_CONN_ADV_BIT|BTM_BLE_STATE_LO_DUTY_DIR_ADV_BIT|BTM_BLE_STATE_HI_DUTY_DIR_ADV_BIT|BTM_BLE_STATE_SCAN_ADV_BIT)
+#define BTM_BLE_STATE_ALL_SCAN_MASK (BTM_BLE_STATE_PASSIVE_SCAN_BIT|BTM_BLE_STATE_ACTIVE_SCAN_BIT)
+#define BTM_BLE_STATE_ALL_CONN_MASK (BTM_BLE_STATE_MASTER_BIT|BTM_BLE_STATE_SLAVE_BIT)
+
+#ifndef BTM_LE_RESOLVING_LIST_MAX
+#define BTM_LE_RESOLVING_LIST_MAX 0x20
+#endif
+
+#define BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_ADV_ADDR 0
+#define BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_LINK_ID 1
+#define BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_BEACON_TYPE 2
+#define BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_PROV_SRV_ADV 3
+#define BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_PROXY_SRV_ADV 4
+
+typedef struct {
+ BD_ADDR *resolve_q_random_pseudo;
+ UINT8 *resolve_q_action;
+ UINT8 q_next;
+ UINT8 q_pending;
+} tBTM_BLE_RESOLVE_Q;
+
+typedef struct {
+ BOOLEAN in_use;
+ BOOLEAN to_add;
+ BD_ADDR bd_addr;
+ tBLE_ADDR_TYPE addr_type;
+ UINT8 attr;
+} tBTM_BLE_WL_OP;
+
+/* BLE privacy mode */
+#define BTM_PRIVACY_NONE 0 /* BLE no privacy */
+#define BTM_PRIVACY_1_1 1 /* BLE privacy 1.1, do not support privacy 1.0 */
+#define BTM_PRIVACY_1_2 2 /* BLE privacy 1.2 */
+#define BTM_PRIVACY_MIXED 3 /* BLE privacy mixed mode, broadcom propietary mode */
+typedef UINT8 tBTM_PRIVACY_MODE;
+
+/* data length change event callback */
+typedef void (tBTM_DATA_LENGTH_CHANGE_CBACK) (UINT16 max_tx_length, UINT16 max_rx_length);
+
+/* Define BLE Device Management control structure
+*/
+typedef struct {
+ UINT16 scan_activity; /* LE scan activity mask */
+
+ /*****************************************************
+ ** BLE Inquiry
+ *****************************************************/
+ tBTM_BLE_INQ_CB inq_var;
+
+ /* observer callback and timer */
+ tBTM_INQ_RESULTS_CB *p_obs_results_cb;
+ tBTM_CMPL_CB *p_obs_cmpl_cb;
+ tBTM_INQ_DIS_CB *p_obs_discard_cb;
+ TIMER_LIST_ENT obs_timer_ent;
+
+ /* scan callback and timer */
+ tBTM_INQ_RESULTS_CB *p_scan_results_cb;
+ tBTM_CMPL_CB *p_scan_cmpl_cb;
+ TIMER_LIST_ENT scan_timer_ent;
+
+ struct pkt_queue *adv_rpt_queue;
+ struct osi_event *adv_rpt_ready;
+
+ /* background connection procedure cb value */
+ tBTM_BLE_CONN_TYPE bg_conn_type;
+ UINT32 scan_int;
+ UINT32 scan_win;
+ tBTM_BLE_SEL_CBACK *p_select_cback;
+ /* white list information */
+ UINT8 white_list_avail_size;
+ tBTM_UPDATE_WHITELIST_CBACK *update_wl_cb;
+ tBTM_BLE_WL_STATE wl_state;
+
+ fixed_queue_t *conn_pending_q;
+ tBTM_BLE_CONN_ST conn_state;
+
+ /* random address management control block */
+ tBTM_LE_RANDOM_CB addr_mgnt_cb;
+
+ BOOLEAN enabled;
+
+#if BLE_PRIVACY_SPT == TRUE
+ BOOLEAN mixed_mode; /* privacy 1.2 mixed mode is on or not */
+ tBTM_PRIVACY_MODE privacy_mode; /* privacy mode */
+ UINT8 resolving_list_avail_size; /* resolving list available size */
+ tBTM_BLE_RESOLVE_Q resolving_list_pend_q; /* Resolving list queue */
+ tBTM_BLE_RL_STATE suspended_rl_state; /* Suspended resolving list state */
+ UINT8 *irk_list_mask; /* IRK list availability mask, up to max entry bits */
+ tBTM_BLE_RL_STATE rl_state; /* Resolving list state */
+#endif
+
+ tBTM_BLE_WL_OP wl_op_q[BTM_BLE_MAX_BG_CONN_DEV_NUM];
+
+ /* current BLE link state */
+ tBTM_BLE_STATE_MASK cur_states; /* bit mask of tBTM_BLE_STATE */
+ UINT8 link_count[2]; /* total link count master and slave*/
+ tBTM_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK *update_exceptional_list_cmp_cb;
+} tBTM_BLE_CB;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void btm_ble_timeout(TIMER_LIST_ENT *p_tle);
+void btm_ble_process_adv_pkt (UINT8 *p);
+void btm_ble_process_adv_discard_evt(UINT8 *p);
+void btm_ble_process_direct_adv_pkt (UINT8 *p);
+bool btm_ble_adv_pkt_ready(void);
+bool btm_ble_adv_pkt_post(pkt_linked_item_t *pkt);
+void btm_ble_proc_scan_rsp_rpt (UINT8 *p);
+tBTM_STATUS btm_ble_read_remote_name(BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur, tBTM_CMPL_CB *p_cb);
+BOOLEAN btm_ble_cancel_remote_name(BD_ADDR remote_bda);
+
+tBTM_STATUS btm_ble_set_discoverability(UINT16 combined_mode);
+tBTM_STATUS btm_ble_set_connectability(UINT16 combined_mode);
+tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8 duration);
+void btm_ble_stop_scan(void);
+void btm_clear_all_pending_le_entry(void);
+
+BOOLEAN btm_ble_send_extended_scan_params(UINT8 scan_type, UINT32 scan_int, UINT32 scan_win, UINT8 addr_type_own, UINT8 scan_filter_policy);
+void btm_ble_stop_inquiry(void);
+void btm_ble_init (void);
+void btm_ble_free (void);
+void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role, tBLE_ADDR_TYPE addr_type, BOOLEAN addr_matched);
+void btm_ble_read_remote_features_complete(UINT8 *p);
+void btm_ble_write_adv_enable_complete(UINT8 *p);
+void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced);
+void btm_read_ble_local_supported_states_complete(UINT8 *p, UINT16 evt_len);
+tBTM_BLE_CONN_ST btm_ble_get_conn_st(void);
+void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st);
+UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst, tBTM_BLE_ADV_DATA *p_data);
+tBTM_STATUS btm_ble_start_adv(void);
+tBTM_STATUS btm_ble_stop_adv(void);
+tBTM_STATUS btm_ble_start_scan(void);
+void btm_ble_create_ll_conn_complete (UINT8 status);
+void btm_ble_create_conn_cancel_complete (UINT8 *p);
+tBTM_STATUS btm_ble_set_random_addr(BD_ADDR random_bda);
+
+/* LE security function from btm_sec.c */
+#if SMP_INCLUDED == TRUE
+void btm_ble_link_sec_check(BD_ADDR bd_addr, tBTM_LE_AUTH_REQ auth_req, tBTM_BLE_SEC_REQ_ACT *p_sec_req_act);
+void btm_ble_ltk_request_reply(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk);
+UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data);
+tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, void *p_ref_data, UINT8 link_role);
+void btm_ble_ltk_request(UINT16 handle, UINT8 rand[8], UINT16 ediv);
+tBTM_STATUS btm_ble_start_encrypt(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk);
+void btm_ble_link_encrypted(BD_ADDR bd_addr, UINT8 encr_enable);
+#endif
+
+/* LE device management functions */
+void btm_ble_reset_id( void );
+
+/* security related functions */
+void btm_ble_increment_sign_ctr(BD_ADDR bd_addr, BOOLEAN is_local );
+BOOLEAN btm_get_local_div (BD_ADDR bd_addr, UINT16 *p_div);
+BOOLEAN btm_ble_get_enc_key_type(BD_ADDR bd_addr, UINT8 *p_key_types);
+
+void btm_ble_test_command_complete(UINT8 *p);
+void btm_ble_rand_enc_complete (UINT8 *p, UINT16 op_code, tBTM_RAND_ENC_CB *p_enc_cplt_cback);
+
+void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY_VALUE *p_keys, BOOLEAN pass_to_application);
+void btm_ble_update_sec_key_size(BD_ADDR bd_addr, UINT8 enc_key_size);
+UINT8 btm_ble_read_sec_key_size(BD_ADDR bd_addr);
+
+/* white list function */
+BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, tBTM_UPDATE_WHITELIST_CBACK *update_wl_cb);
+void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy);
+void btm_update_adv_filter_policy(tBTM_BLE_AFP adv_policy);
+void btm_ble_clear_white_list (tBTM_UPDATE_WHITELIST_CBACK *update_wl_cb);
+void btm_read_white_list_size_complete(UINT8 *p, UINT16 evt_len);
+void btm_ble_add_2_white_list_complete(UINT8 status);
+void btm_ble_remove_from_white_list_complete(UINT8 *p, UINT16 evt_len);
+void btm_ble_clear_white_list_complete(UINT8 *p, UINT16 evt_len);
+void btm_ble_white_list_init(UINT8 white_list_size);
+
+/* background connection function */
+BOOLEAN btm_ble_suspend_bg_conn(void);
+BOOLEAN btm_ble_resume_bg_conn(void);
+void btm_ble_initiate_select_conn(BD_ADDR bda);
+BOOLEAN btm_ble_start_auto_conn(BOOLEAN start);
+BOOLEAN btm_ble_start_select_conn(BOOLEAN start, tBTM_BLE_SEL_CBACK *p_select_cback);
+BOOLEAN btm_ble_renew_bg_conn_params(BOOLEAN add, BD_ADDR bd_addr);
+void btm_write_dir_conn_wl(BD_ADDR target_addr);
+BOOLEAN btm_ble_update_mode_operation(UINT8 link_role, BD_ADDR bda, UINT8 status);
+BOOLEAN btm_execute_wl_dev_operation(void);
+void btm_ble_update_link_topology_mask(UINT8 role, BOOLEAN increase);
+
+/* direct connection utility */
+BOOLEAN btm_send_pending_direct_conn(void);
+void btm_ble_enqueue_direct_conn_req(void *p_param);
+
+/* BLE address management */
+void btm_gen_resolvable_private_addr (void *p_cmd_cplt_cback);
+void btm_gen_non_resolvable_private_addr (tBTM_BLE_ADDR_CBACK *p_cback, void *p);
+void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK *p_cback, void *p);
+void btm_gen_resolve_paddr_low(tBTM_RAND_ENC *p);
+
+/* privacy function */
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
+/* BLE address mapping with CS feature */
+BOOLEAN btm_identity_addr_to_random_pseudo(BD_ADDR bd_addr, UINT8 *p_addr_type, BOOLEAN refresh);
+BOOLEAN btm_random_pseudo_to_identity_addr(BD_ADDR random_pseudo, UINT8 *p_static_addr_type);
+void btm_ble_refresh_peer_resolvable_private_addr(BD_ADDR pseudo_bda, BD_ADDR rra, UINT8 rra_type);
+void btm_ble_refresh_local_resolvable_private_addr(BD_ADDR pseudo_addr, BD_ADDR local_rpa);
+void btm_ble_read_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len) ;
+void btm_ble_set_addr_resolution_enable_complete(UINT8 *p, UINT16 evt_len) ;
+void btm_ble_remove_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len);
+void btm_ble_add_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len);
+void btm_ble_clear_resolving_list_complete(UINT8 *p, UINT16 evt_len);
+void btm_read_ble_resolving_list_size_complete (UINT8 *p, UINT16 evt_len);
+void btm_ble_enable_resolving_list(UINT8);
+BOOLEAN btm_ble_disable_resolving_list(UINT8 rl_mask, BOOLEAN to_resume);
+void btm_ble_enable_resolving_list_for_platform (UINT8 rl_mask);
+void btm_ble_resolving_list_init(UINT8 max_irk_list_sz);
+void btm_ble_resolving_list_cleanup(void);
+void btm_ble_add_default_entry_to_resolving_list(void);
+#endif
+
+void btm_ble_multi_adv_configure_rpa (tBTM_BLE_MULTI_ADV_INST *p_inst);
+void btm_ble_multi_adv_init(void);
+void *btm_ble_multi_adv_get_ref(UINT8 inst_id);
+void btm_ble_multi_adv_cleanup(void);
+void btm_ble_multi_adv_reenable(UINT8 inst_id);
+void btm_ble_multi_adv_enb_privacy(BOOLEAN enable);
+char btm_ble_map_adv_tx_power(int tx_power_index);
+void btm_ble_batchscan_init(void);
+void btm_ble_batchscan_cleanup(void);
+void btm_ble_adv_filter_init(void);
+void btm_ble_adv_filter_cleanup(void);
+BOOLEAN btm_ble_topology_check(tBTM_BLE_STATE_MASK request);
+BOOLEAN btm_ble_clear_topology_mask(tBTM_BLE_STATE_MASK request_state);
+BOOLEAN btm_ble_set_topology_mask(tBTM_BLE_STATE_MASK request_state);
+tBTM_BLE_STATE_MASK btm_ble_get_topology_mask(void);
+
+#if BTM_BLE_CONFORMANCE_TESTING == TRUE
+void btm_ble_set_no_disc_if_pair_fail (BOOLEAN disble_disc);
+void btm_ble_set_test_mac_value (BOOLEAN enable, UINT8 *p_test_mac_val);
+void btm_ble_set_test_local_sign_cntr_value(BOOLEAN enable, UINT32 test_local_sign_cntr);
+void btm_set_random_address(BD_ADDR random_bda);
+void btm_ble_set_keep_rfu_in_auth_req(BOOLEAN keep_rfu);
+#endif
+
+BOOLEAN btm_get_current_conn_params(BD_ADDR bda, UINT16 *interval, UINT16 *latency, UINT16 *timeout);
+
+#if (BLE_50_FEATURE_SUPPORT == TRUE)
+void btm_ble_update_phy_evt(tBTM_BLE_UPDATE_PHY *params);
+void btm_ble_scan_timeout_evt(void);
+void btm_ble_adv_set_terminated_evt(tBTM_BLE_ADV_TERMINAT *params);
+void btm_ble_ext_adv_report_evt(tBTM_BLE_EXT_ADV_REPORT *params);
+void btm_ble_scan_req_received_evt(tBTM_BLE_SCAN_REQ_RECEIVED *params);
+void btm_ble_channel_select_algorithm_evt(tBTM_BLE_CHANNEL_SEL_ALG *params);
+void btm_ble_periodic_adv_report_evt(tBTM_PERIOD_ADV_REPORT *params);
+void btm_ble_periodic_adv_sync_lost_evt(tBTM_BLE_PERIOD_ADV_SYNC_LOST *params);
+void btm_ble_periodic_adv_sync_establish_evt(tBTM_BLE_PERIOD_ADV_SYNC_ESTAB *params);
+#endif // #if (BLE_50_FEATURE_SUPPORT == TRUE)
+
+#if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE)
+void btm_ble_periodic_adv_sync_trans_recv_evt(tBTM_BLE_PERIOD_ADV_SYNC_TRANS_RECV *params);
+#endif // #if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE)
+
+/*
+#ifdef __cplusplus
+}
+#endif
+*/
+#endif
diff --git a/lib/bt/host/bluedroid/stack/btm/include/btm_int.h b/lib/bt/host/bluedroid/stack/btm/include/btm_int.h
new file mode 100644
index 00000000..c22423a1
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/btm/include/btm_int.h
@@ -0,0 +1,1258 @@
+/******************************************************************************
+ *
+ * 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 the main Bluetooth Manager (BTM) internal
+ * definitions.
+ *
+ ******************************************************************************/
+#ifndef BTM_INT_H
+#define BTM_INT_H
+
+typedef struct tBTM_SEC_DEV_REC tBTM_SEC_DEV_REC;
+
+#include "common/bt_defs.h"
+#include "common/bt_target.h"
+#include "stack/hcidefs.h"
+
+#include "stack/rfcdefs.h"
+
+#include "stack/btm_api.h"
+#include "osi/fixed_queue.h"
+
+#if (BLE_INCLUDED == TRUE)
+#include "btm_ble_int.h"
+#endif
+#if (SMP_INCLUDED == TRUE)
+#include "stack/smp_api.h"
+#endif
+
+#define ESP_VS_REM_LEGACY_AUTH_CMP 0x03
+
+#if BTM_MAX_LOC_BD_NAME_LEN > 0
+typedef char tBTM_LOC_BD_NAME[BTM_MAX_LOC_BD_NAME_LEN + 1];
+#endif
+
+#define BTM_ACL_IS_CONNECTED(bda) (btm_bda_to_acl (bda, BT_TRANSPORT_BR_EDR) != NULL)
+
+/* Definitions for Server Channel Number (SCN) management
+*/
+#define BTM_MAX_SCN PORT_MAX_RFC_PORTS
+
+/* Define masks for supported and exception 2.0 ACL packet types
+*/
+#define BTM_ACL_SUPPORTED_PKTS_MASK (HCI_PKT_TYPES_MASK_DM1 | \
+ HCI_PKT_TYPES_MASK_DH1 | \
+ HCI_PKT_TYPES_MASK_DM3 | \
+ HCI_PKT_TYPES_MASK_DH3 | \
+ HCI_PKT_TYPES_MASK_DM5 | \
+ HCI_PKT_TYPES_MASK_DH5)
+
+#define BTM_ACL_EXCEPTION_PKTS_MASK (HCI_PKT_TYPES_MASK_NO_2_DH1 | \
+ HCI_PKT_TYPES_MASK_NO_3_DH1 | \
+ HCI_PKT_TYPES_MASK_NO_2_DH3 | \
+ HCI_PKT_TYPES_MASK_NO_3_DH3 | \
+ HCI_PKT_TYPES_MASK_NO_2_DH5 | \
+ HCI_PKT_TYPES_MASK_NO_3_DH5)
+
+#define BTM_EPR_AVAILABLE(p) ((HCI_ATOMIC_ENCRYPT_SUPPORTED((p)->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]) && \
+ HCI_ATOMIC_ENCRYPT_SUPPORTED(controller_get_interface()->get_features_classic(0)->as_array)) \
+ ? TRUE : FALSE)
+
+#define BTM_IS_BRCM_CONTROLLER() (controller_get_interface()->get_bt_version()->manufacturer == LMP_COMPID_BROADCOM)
+
+typedef struct t_acl_db_param{
+#define ACL_DB_HANDLE 0x00
+#define ACL_DB_BDA 0x01
+ UINT8 type;
+ void *p_data1;
+ void *p_data2;
+}tACL_DB_PARAM;
+
+enum {
+ BTM_PM_ST_ACTIVE = BTM_PM_STS_ACTIVE,
+ BTM_PM_ST_HOLD = BTM_PM_STS_HOLD,
+ BTM_PM_ST_SNIFF = BTM_PM_STS_SNIFF,
+ BTM_PM_ST_PARK = BTM_PM_STS_PARK,
+ BTM_PM_ST_PENDING = BTM_PM_STS_PENDING
+};
+typedef UINT8 tBTM_PM_STATE;
+
+typedef struct {
+ tBTM_PM_PWR_MD req_mode[BTM_MAX_PM_RECORDS + 1]; /* the desired mode and parameters of the connection*/
+ tBTM_PM_PWR_MD set_mode; /* the mode and parameters sent down to the host controller. */
+ UINT16 interval; /* the interval from last mode change event. */
+#if (BTM_SSR_INCLUDED == TRUE)
+ UINT16 max_lat; /* stored SSR maximum latency */
+ UINT16 min_rmt_to;/* stored SSR minimum remote timeout */
+ UINT16 min_loc_to;/* stored SSR minimum local timeout */
+#endif
+ tBTM_PM_STATE state; /* contains the current mode of the connection */
+ BOOLEAN chg_ind; /* a request change indication */
+} tBTM_PM_MCB;
+
+/* Define the ACL Management control structure
+*/
+typedef struct {
+UINT16 hci_handle;
+UINT16 pkt_types_mask;
+UINT16 clock_offset;
+BD_ADDR remote_addr;
+DEV_CLASS remote_dc;
+BD_NAME remote_name;
+
+UINT16 manufacturer;
+UINT16 lmp_subversion;
+UINT16 link_super_tout;
+BD_FEATURES peer_lmp_features[HCI_EXT_FEATURES_PAGE_MAX + 1]; /* Peer LMP Extended features mask table for the device */
+UINT8 num_read_pages;
+UINT8 lmp_version;
+
+BOOLEAN in_use;
+UINT8 link_role;
+BOOLEAN link_up_issued; /* True if busy_level link up has been issued */
+BOOLEAN sc_downgrade; /* Store if security is downgraded or not. */
+
+#define BTM_ACL_LEGACY_AUTH_NONE (0)
+#define BTM_ACL_LEGACY_AUTH_SELF (1<<0)
+#define BTM_ACL_LEGACY_AUTH_REMOTE (1<<1)
+#define BTM_ACL_LEGACY_AUTH_MUTUAL (1<<2)
+UINT8 legacy_auth_state;
+
+#define BTM_ACL_SWKEY_STATE_IDLE 0
+#define BTM_ACL_SWKEY_STATE_MODE_CHANGE 1
+#define BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF 2
+#define BTM_ACL_SWKEY_STATE_SWITCHING 3
+#define BTM_ACL_SWKEY_STATE_ENCRYPTION_ON 4
+#define BTM_ACL_SWKEY_STATE_IN_PROGRESS 5
+UINT8 switch_role_state;
+
+#define BTM_ACL_ENCRYPT_STATE_IDLE 0
+#define BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF 1 /* encryption turning off */
+#define BTM_ACL_ENCRYPT_STATE_TEMP_FUNC 2 /* temporarily off for change link key or role switch */
+#define BTM_ACL_ENCRYPT_STATE_ENCRYPT_ON 3 /* encryption turning on */
+UINT8 encrypt_state; /* overall BTM encryption state */
+
+#if BLE_INCLUDED == TRUE
+tBT_TRANSPORT transport;
+BD_ADDR conn_addr; /* local device address used for this connection */
+UINT8 conn_addr_type; /* local device address type for this connection */
+BD_ADDR active_remote_addr; /* remote address used on this connection */
+UINT8 active_remote_addr_type; /* local device address type for this connection */
+BD_FEATURES peer_le_features; /* Peer LE Used features mask for the device */
+tBTM_SET_PKT_DATA_LENGTH_CBACK *p_set_pkt_data_cback;
+tBTM_LE_SET_PKT_DATA_LENGTH_PARAMS data_length_params;
+BOOLEAN data_len_updating;
+// data len update cmd cache
+BOOLEAN data_len_waiting;
+tBTM_SET_PKT_DATA_LENGTH_CBACK *p_set_data_len_cback_waiting;
+UINT16 tx_len_waiting;
+#endif
+tBTM_PM_MCB *p_pm_mode_db; /* Pointer to PM mode control block per ACL link */
+
+} tACL_CONN;
+
+/*****************************************************
+** TIMER Definitions
+******************************************************/
+#define TT_DEV_RESET 1
+#define TT_DEV_RLN 2
+#define TT_DEV_RLNKP 4 /* Read Link Policy Settings */
+
+/* Define the Device Management control structure
+*/
+typedef struct {
+tBTM_DEV_STATUS_CB *p_dev_status_cb; /* Device status change callback */
+tBTM_VS_EVT_CB *p_vend_spec_cb[BTM_MAX_VSE_CALLBACKS]; /* Register for vendor specific events */
+
+tBTM_CMPL_CB *p_stored_link_key_cmpl_cb; /* Read/Write/Delete stored link key */
+
+TIMER_LIST_ENT reset_timer;
+tBTM_CMPL_CB *p_reset_cmpl_cb;
+
+TIMER_LIST_ENT rln_timer;
+tBTM_CMPL_CB *p_rln_cmpl_cb; /* Callback function to be called when */
+/* read local name function complete */
+TIMER_LIST_ENT rssi_timer;
+tBTM_CMPL_CB *p_rssi_cmpl_cb; /* Callback function to be called when */
+/* read rssi function completes */
+TIMER_LIST_ENT lnk_quality_timer;
+tBTM_CMPL_CB *p_lnk_qual_cmpl_cb;/* Callback function to be called when */
+/* read link quality function completes */
+TIMER_LIST_ENT txpwer_timer;
+tBTM_CMPL_CB *p_txpwer_cmpl_cb; /* Callback function to be called when */
+/* read inq tx power function completes */
+
+TIMER_LIST_ENT qossu_timer;
+tBTM_CMPL_CB *p_qossu_cmpl_cb; /* Callback function to be called when */
+/* qos setup function completes */
+
+tBTM_ROLE_SWITCH_CMPL switch_role_ref_data;
+tBTM_CMPL_CB *p_switch_role_cb; /* Callback function to be called when */
+/* requested switch role is completed */
+
+TIMER_LIST_ENT tx_power_timer;
+tBTM_CMPL_CB *p_tx_power_cmpl_cb;/* Callback function to be called */
+
+#if CLASSIC_BT_INCLUDED == TRUE
+TIMER_LIST_ENT afh_channels_timer;
+tBTM_CMPL_CB *p_afh_channels_cmpl_cb; /* Callback function to be called When */
+/* set AFH channels is completed */
+
+TIMER_LIST_ENT page_timeout_set_timer;
+tBTM_CMPL_CB *p_page_to_set_cmpl_cb; /* Callback function to be called when */
+/* set page timeout is completed */
+TIMER_LIST_ENT set_acl_pkt_types_timer;
+tBTM_CMPL_CB *p_set_acl_pkt_types_cmpl_cb; /* Callback function to be called when */
+/* set ACL packet types is completed */
+#endif
+
+DEV_CLASS dev_class; /* Local device class */
+
+#if BLE_INCLUDED == TRUE
+
+TIMER_LIST_ENT ble_channels_timer;
+tBTM_CMPL_CB *p_ble_channels_cmpl_cb; /* Callback function to be called When
+ ble set host channels is completed */
+
+tBTM_CMPL_CB *p_le_test_cmd_cmpl_cb; /* Callback function to be called when
+ LE test mode command has been sent successfully */
+
+BD_ADDR read_tx_pwr_addr; /* read TX power target address */
+
+#define BTM_LE_SUPPORT_STATE_SIZE 8
+UINT8 le_supported_states[BTM_LE_SUPPORT_STATE_SIZE];
+
+tBTM_BLE_LOCAL_ID_KEYS id_keys; /* local BLE ID keys */
+BT_OCTET16 ble_encryption_key_value; /* BLE encryption key */
+
+#if BTM_BLE_CONFORMANCE_TESTING == TRUE
+BOOLEAN no_disc_if_pair_fail;
+BOOLEAN enable_test_mac_val;
+BT_OCTET8 test_mac;
+BOOLEAN enable_test_local_sign_cntr;
+UINT32 test_local_sign_cntr;
+#endif
+
+#endif /* BLE_INCLUDED */
+
+tBTM_IO_CAP loc_io_caps; /* IO capability of the local device */
+tBTM_AUTH_REQ loc_auth_req; /* the auth_req flag */
+BOOLEAN secure_connections_only; /* Rejects service level 0 connections if */
+/* itself or peer device doesn't support */
+/* secure connections */
+} tBTM_DEVCB;
+
+
+/* Define the structures and constants used for inquiry
+*/
+
+/* Definitions of limits for inquiries */
+#define BTM_PER_INQ_MIN_MAX_PERIOD HCI_PER_INQ_MIN_MAX_PERIOD
+#define BTM_PER_INQ_MAX_MAX_PERIOD HCI_PER_INQ_MAX_MAX_PERIOD
+#define BTM_PER_INQ_MIN_MIN_PERIOD HCI_PER_INQ_MIN_MIN_PERIOD
+#define BTM_PER_INQ_MAX_MIN_PERIOD HCI_PER_INQ_MAX_MIN_PERIOD
+#define BTM_MAX_INQUIRY_LENGTH HCI_MAX_INQUIRY_LENGTH
+#define BTM_MIN_INQUIRY_LEN 0x01
+
+#define BTM_MIN_INQ_TX_POWER -70
+#define BTM_MAX_INQ_TX_POWER 20
+
+typedef struct {
+UINT32 inq_count; /* Used for determining if a response has already been */
+/* received for the current inquiry operation. (We do not */
+/* want to flood the caller with multiple responses from */
+/* the same device. */
+BD_ADDR bd_addr;
+} tINQ_BDADDR;
+
+typedef struct {
+UINT32 time_of_resp;
+UINT32 inq_count; /* "timestamps" the entry with a particular inquiry count */
+/* Used for determining if a response has already been */
+/* received for the current inquiry operation. (We do not */
+/* want to flood the caller with multiple responses from */
+/* the same device. */
+tBTM_INQ_INFO inq_info;
+BOOLEAN in_use;
+
+#if (BLE_INCLUDED == TRUE)
+BOOLEAN scan_rsp;
+#endif
+} tINQ_DB_ENT;
+
+
+enum {
+INQ_NONE,
+INQ_LE_OBSERVE,
+INQ_GENERAL
+};
+typedef UINT8 tBTM_INQ_TYPE;
+
+typedef struct {
+ tBTM_CMPL_CB *p_remname_cmpl_cb;
+
+#define BTM_EXT_RMT_NAME_TIMEOUT 40
+
+
+ TIMER_LIST_ENT rmt_name_timer_ent;
+
+ UINT16 discoverable_mode;
+ UINT16 connectable_mode;
+ UINT16 page_scan_window;
+ UINT16 page_scan_period;
+ UINT16 inq_scan_window;
+ UINT16 inq_scan_period;
+ UINT16 inq_scan_type;
+ UINT16 page_scan_type; /* current page scan type */
+ tBTM_INQ_TYPE scan_type;
+ UINT16 page_timeout;
+
+ BD_ADDR remname_bda; /* Name of bd addr for active remote name request */
+#define BTM_RMT_NAME_INACTIVE 0
+#define BTM_RMT_NAME_EXT 0x1 /* Initiated through API */
+#define BTM_RMT_NAME_SEC 0x2 /* Initiated internally by security manager */
+#define BTM_RMT_NAME_INQ 0x4 /* Remote name initiated internally by inquiry */
+ BOOLEAN remname_active; /* State of a remote name request by external API */
+
+ tBTM_CMPL_CB *p_inq_cmpl_cb;
+ tBTM_INQ_RESULTS_CB *p_inq_results_cb;
+ tBTM_CMPL_CB *p_inq_ble_cmpl_cb; /*completion callback exclusively for LE Observe*/
+ tBTM_INQ_RESULTS_CB *p_inq_ble_results_cb;/*results callback exclusively for LE observe*/
+ tBTM_CMPL_CB *p_inqfilter_cmpl_cb; /* Called (if not NULL) after inquiry filter completed */
+ UINT32 inq_counter; /* Counter incremented each time an inquiry completes */
+ /* Used for determining whether or not duplicate devices */
+ /* have responded to the same inquiry */
+ TIMER_LIST_ENT inq_timer_ent;
+ tINQ_BDADDR *p_bd_db; /* Pointer to memory that holds bdaddrs */
+ UINT16 num_bd_entries; /* Number of entries in database */
+ UINT16 max_bd_entries; /* Maximum number of entries that can be stored */
+ tINQ_DB_ENT inq_db[BTM_INQ_DB_SIZE];
+ tBTM_INQ_PARMS inqparms; /* Contains the parameters for the current inquiry */
+ tBTM_INQUIRY_CMPL inq_cmpl_info; /* Status and number of responses from the last inquiry */
+
+ UINT16 per_min_delay; /* Current periodic minimum delay */
+ UINT16 per_max_delay; /* Current periodic maximum delay */
+ BOOLEAN inqfilt_active;
+ UINT8 pending_filt_complete_event; /* to take care of btm_event_filter_complete corresponding to */
+ /* inquiry that has been cancelled*/
+ UINT8 inqfilt_type; /* Contains the inquiry filter type (BD ADDR, COD, or Clear) */
+
+#define BTM_INQ_INACTIVE_STATE 0
+#define BTM_INQ_CLR_FILT_STATE 1 /* Currently clearing the inquiry filter preceeding the inquiry request */
+ /* (bypassed if filtering is not used) */
+#define BTM_INQ_SET_FILT_STATE 2 /* Sets the new filter (or turns off filtering) in this state */
+#define BTM_INQ_ACTIVE_STATE 3 /* Actual inquiry or periodic inquiry is in progress */
+#define BTM_INQ_REMNAME_STATE 4 /* Remote name requests are active */
+
+ UINT8 state; /* Current state that the inquiry process is in */
+ UINT8 inq_active; /* Bit Mask indicating type of inquiry is active */
+ BOOLEAN no_inc_ssp; /* TRUE, to stop inquiry on incoming SSP */
+#if (defined(BTA_HOST_INTERLEAVE_SEARCH) && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ btm_inq_state next_state; /*interleaving state to determine next mode to be inquired*/
+#endif
+} tBTM_INQUIRY_VAR_ST;
+
+/* The MSB of the clock offset field indicates that the offset is valid if TRUE */
+#define BTM_CLOCK_OFFSET_VALID 0x8000
+
+/* Define the structures needed by security management
+*/
+
+#define BTM_SEC_INVALID_HANDLE 0xFFFF
+
+typedef UINT8 *BTM_BD_NAME_PTR; /* Pointer to Device name */
+
+/* Security callback is called by this unit when security
+** procedures are completed. Parameters are
+** BD Address of remote
+** Result of the operation
+*/
+typedef tBTM_SEC_CBACK tBTM_SEC_CALLBACK;
+
+#define BTM_DATA_HANDLE_MASK 0x0FFF
+
+#define BTMD_GET_HANDLE(u16) (UINT16)((u16) & BTM_DATA_HANDLE_MASK)
+
+typedef void (tBTM_SCO_IND_CBACK) (UINT16 sco_inx) ;
+
+/* MACROs to convert from SCO packet types mask to ESCO and back */
+#define BTM_SCO_PKT_TYPE_MASK ( HCI_PKT_TYPES_MASK_HV1 \
+ | HCI_PKT_TYPES_MASK_HV2 \
+ | HCI_PKT_TYPES_MASK_HV3)
+
+/* Mask defining only the SCO types of an esco packet type */
+#define BTM_ESCO_PKT_TYPE_MASK ( HCI_ESCO_PKT_TYPES_MASK_HV1 \
+ | HCI_ESCO_PKT_TYPES_MASK_HV2 \
+ | HCI_ESCO_PKT_TYPES_MASK_HV3)
+
+#define BTM_SCO_2_ESCO(scotype) ((UINT16)(((scotype) & BTM_SCO_PKT_TYPE_MASK) >> 5))
+#define BTM_ESCO_2_SCO(escotype) ((UINT16)(((escotype) & BTM_ESCO_PKT_TYPE_MASK) << 5))
+
+/* Define masks for supported and exception 2.0 SCO packet types
+*/
+#define BTM_SCO_SUPPORTED_PKTS_MASK (HCI_ESCO_PKT_TYPES_MASK_HV1 | \
+ HCI_ESCO_PKT_TYPES_MASK_HV2 | \
+ HCI_ESCO_PKT_TYPES_MASK_HV3 | \
+ HCI_ESCO_PKT_TYPES_MASK_EV3 | \
+ HCI_ESCO_PKT_TYPES_MASK_EV4 | \
+ HCI_ESCO_PKT_TYPES_MASK_EV5)
+
+#define BTM_SCO_EXCEPTION_PKTS_MASK (HCI_ESCO_PKT_TYPES_MASK_NO_2_EV3 | \
+ HCI_ESCO_PKT_TYPES_MASK_NO_3_EV3 | \
+ HCI_ESCO_PKT_TYPES_MASK_NO_2_EV5 | \
+ HCI_ESCO_PKT_TYPES_MASK_NO_3_EV5)
+
+
+#define BTM_SCO_ROUTE_UNKNOWN 0xff
+
+/* Define the structure that contains (e)SCO data */
+typedef struct {
+ tBTM_ESCO_CBACK *p_esco_cback; /* Callback for eSCO events */
+ tBTM_ESCO_PARAMS setup;
+ tBTM_ESCO_DATA data; /* Connection complete information */
+ UINT8 hci_status;
+} tBTM_ESCO_INFO;
+
+/* Define the structure used for SCO Management
+*/
+typedef struct {
+ tBTM_ESCO_INFO esco; /* Current settings */
+#if BTM_SCO_HCI_INCLUDED == TRUE
+#define BTM_SCO_XMIT_QUEUE_THRS 30
+#define BTM_SCO_XMIT_QUEUE_HIGH_WM 20
+ fixed_queue_t *xmit_data_q; /* SCO data transmitting queue */
+ INT16 sent_not_acked;
+ tBTM_SCO_PKT_STAT_NUMS pkt_stat_nums;
+#endif
+ tBTM_SCO_CB *p_conn_cb; /* Callback for when connected */
+ tBTM_SCO_CB *p_disc_cb; /* Callback for when disconnect */
+ UINT16 state; /* The state of the SCO link */
+ UINT16 hci_handle; /* HCI Handle */
+ BOOLEAN is_orig; /* TRUE if the originator */
+ BOOLEAN rem_bd_known; /* TRUE if remote BD addr known */
+} tSCO_CONN;
+
+/* SCO Management control block */
+typedef struct {
+ tBTM_SCO_IND_CBACK *app_sco_ind_cb;
+#if BTM_SCO_HCI_INCLUDED == TRUE
+ tBTM_SCO_DATA_CB *p_data_cb; /* Callback for SCO data over HCI */
+ UINT32 xmit_window_size; /* Total SCO window in bytes */
+ UINT16 num_lm_sco_bufs;
+#endif
+ tSCO_CONN sco_db[BTM_MAX_SCO_LINKS];
+ tBTM_ESCO_PARAMS def_esco_parms;
+ BD_ADDR xfer_addr;
+ UINT16 sco_disc_reason;
+ BOOLEAN esco_supported; /* TRUE if 1.2 cntlr AND supports eSCO links */
+ tBTM_SCO_TYPE desired_sco_mode;
+ tBTM_SCO_TYPE xfer_sco_type;
+ tBTM_SCO_PCM_PARAM sco_pcm_param;
+ tBTM_SCO_CODEC_TYPE codec_in_use; /* None, CVSD, MSBC, etc. */
+#if BTM_SCO_HCI_INCLUDED == TRUE
+ tBTM_SCO_ROUTE_TYPE sco_path;
+#endif
+
+} tSCO_CB;
+
+
+#if BTM_SCO_INCLUDED == TRUE
+void btm_set_sco_ind_cback( tBTM_SCO_IND_CBACK *sco_ind_cb );
+void btm_accept_sco_link(UINT16 sco_inx, tBTM_ESCO_PARAMS *p_setup,
+ tBTM_SCO_CB *p_conn_cb, tBTM_SCO_CB *p_disc_cb);
+void btm_reject_sco_link(UINT16 sco_inx );
+void btm_sco_chk_pend_rolechange (UINT16 hci_handle);
+#else
+#define btm_accept_sco_link(sco_inx, p_setup, p_conn_cb, p_disc_cb)
+#define btm_reject_sco_link(sco_inx)
+#define btm_set_sco_ind_cback(sco_ind_cb)
+#define btm_sco_chk_pend_rolechange(hci_handle)
+#endif /* BTM_SCO_INCLUDED */
+
+/*
+** Define structure for Security Service Record.
+** A record exists for each service registered with the Security Manager
+*/
+#define BTM_SEC_OUT_FLAGS (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHORIZE)
+#define BTM_SEC_IN_FLAGS (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHORIZE)
+
+#define BTM_SEC_OUT_LEVEL4_FLAGS (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | \
+ BTM_SEC_OUT_MITM | BTM_SEC_MODE4_LEVEL4)
+
+#define BTM_SEC_IN_LEVEL4_FLAGS (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | \
+ BTM_SEC_IN_MITM | BTM_SEC_MODE4_LEVEL4)
+
+typedef struct {
+ UINT32 mx_proto_id; /* Service runs over this multiplexer protocol */
+ UINT32 orig_mx_chan_id; /* Channel on the multiplexer protocol */
+ UINT32 term_mx_chan_id; /* Channel on the multiplexer protocol */
+ UINT16 psm; /* L2CAP PSM value */
+ UINT16 security_flags; /* Bitmap of required security features */
+ UINT8 service_id; /* Passed in authorization callback */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ UINT16 ucd_security_flags; /* Bitmap of required security features for UCD */
+#endif
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ UINT8 orig_service_name[BTM_SEC_SERVICE_NAME_LEN + 1];
+ UINT8 term_service_name[BTM_SEC_SERVICE_NAME_LEN + 1];
+#endif
+} tBTM_SEC_SERV_REC;
+
+#if BLE_INCLUDED == TRUE
+/* LE Security information of device in Slave Role */
+typedef struct {
+ BT_OCTET16 irk; /* peer diverified identity root */
+ BT_OCTET16 pltk; /* peer long term key */
+ BT_OCTET16 pcsrk; /* peer SRK peer device used to secured sign local data */
+
+ BT_OCTET16 lltk; /* local long term key */
+ BT_OCTET16 lcsrk; /* local SRK peer device used to secured sign local data */
+
+ BT_OCTET8 rand; /* random vector for LTK generation */
+ UINT16 ediv; /* LTK diversifier of this slave device */
+ UINT16 div; /* local DIV to generate local LTK=d1(ER,DIV,0) and CSRK=d1(ER,DIV,1) */
+ UINT8 sec_level; /* local pairing security level */
+ UINT8 key_size; /* key size of the LTK delivered to peer device */
+ UINT8 srk_sec_level; /* security property of peer SRK for this device */
+ UINT8 local_csrk_sec_level; /* security property of local CSRK for this device */
+
+ UINT32 counter; /* peer sign counter for verifying rcv signed cmd */
+ UINT32 local_counter; /* local sign counter for sending signed write cmd*/
+} tBTM_SEC_BLE_KEYS;
+
+typedef struct {
+ BD_ADDR pseudo_addr; /* LE pseudo address of the device if different from device address */
+ tBLE_ADDR_TYPE ble_addr_type; /* LE device type: public or random address */
+ tBLE_ADDR_TYPE static_addr_type; /* static address type */
+ BD_ADDR static_addr; /* static address */
+
+#define BTM_WHITE_LIST_BIT 0x01
+#define BTM_RESOLVING_LIST_BIT 0x02
+ UINT8 in_controller_list; /* in controller resolving list or not */
+ UINT8 resolving_list_index;
+#if BLE_PRIVACY_SPT == TRUE
+ BD_ADDR cur_rand_addr; /* current random address */
+
+#define BTM_BLE_ADDR_PSEUDO 0 /* address index device record */
+#define BTM_BLE_ADDR_RRA 1 /* cur_rand_addr */
+#define BTM_BLE_ADDR_STATIC 2 /* static_addr */
+ UINT8 active_addr_type;
+#endif
+
+#if SMP_INCLUDED == TRUE
+ tBTM_LE_KEY_TYPE key_type; /* bit mask of valid key types in record */
+ tBTM_SEC_BLE_KEYS keys; /* LE device security info in slave rode */
+#if (SMP_SLAVE_CON_PARAMS_UPD_ENABLE == TRUE)
+ bool skip_update_conn_param; /* skip update connection paraams or not*/
+#endif
+ UINT16 auth_mode; /* Authentication mode */
+#endif
+#if (BLE_PRIVACY_SPT == TRUE && (!CONTROLLER_RPA_LIST_ENABLE))
+ tBLE_ADDR_TYPE current_addr_type; /* current adv addr type*/
+ BD_ADDR current_addr; /* current adv addr*/
+ bool current_addr_valid; /* current addr info is valid or not*/
+#endif
+} tBTM_SEC_BLE;
+
+
+#endif /* BLE_INCLUDED */
+
+/* Peering bond type */
+enum {
+ BOND_TYPE_UNKNOWN,
+ BOND_TYPE_PERSISTENT,
+ BOND_TYPE_TEMPORARY
+};
+typedef UINT8 tBTM_BOND_TYPE;
+
+/*
+** Define structure for Security Device Record.
+** A record exists for each device authenticated with this device
+*/
+struct tBTM_SEC_DEV_REC{
+ tBTM_SEC_SERV_REC *p_cur_service;
+ tBTM_SEC_CALLBACK *p_callback;
+ void *p_ref_data;
+ UINT32 timestamp; /* Timestamp of the last connection */
+ UINT32 trusted_mask[BTM_SEC_SERVICE_ARRAY_SIZE]; /* Bitwise OR of trusted services */
+ UINT16 hci_handle; /* Handle to connection when exists */
+ UINT16 clock_offset; /* Latest known clock offset */
+ BD_ADDR bd_addr; /* BD_ADDR of the device */
+ DEV_CLASS dev_class; /* DEV_CLASS of the device */
+ LINK_KEY link_key; /* Device link key */
+ UINT8 pin_code_length; /* Length of the pin_code used for paring */
+
+#define BTM_SEC_AUTHORIZED BTM_SEC_FLAG_AUTHORIZED /* 0x01 */
+#define BTM_SEC_AUTHENTICATED BTM_SEC_FLAG_AUTHENTICATED /* 0x02 */
+#define BTM_SEC_ENCRYPTED BTM_SEC_FLAG_ENCRYPTED /* 0x04 */
+#define BTM_SEC_NAME_KNOWN 0x08
+#define BTM_SEC_LINK_KEY_KNOWN BTM_SEC_FLAG_LKEY_KNOWN /* 0x10 */
+#define BTM_SEC_LINK_KEY_AUTHED BTM_SEC_FLAG_LKEY_AUTHED /* 0x20 */
+#define BTM_SEC_ROLE_SWITCHED 0x40
+#define BTM_SEC_IN_USE 0x80
+ /* LE link security flag */
+#define BTM_SEC_LE_AUTHORIZATION 0x0100 /* LE link is authorized */
+#define BTM_SEC_LE_AUTHENTICATED 0x0200 /* LE link is encrypted after pairing with MITM */
+#define BTM_SEC_LE_ENCRYPTED 0x0400 /* LE link is encrypted */
+#define BTM_SEC_LE_NAME_KNOWN 0x0800 /* not used */
+#define BTM_SEC_LE_LINK_KEY_KNOWN 0x1000 /* bonded with peer (peer LTK and/or SRK is saved) */
+#define BTM_SEC_LE_LINK_KEY_AUTHED 0x2000 /* pairing is done with MITM */
+#define BTM_SEC_16_DIGIT_PIN_AUTHED 0x4000 /* pairing is done with 16 digit pin */
+
+ UINT16 sec_flags; /* Current device security state */
+
+ tBTM_BD_NAME sec_bd_name; /* User friendly name of the device. (may be truncated to save space in dev_rec table) */
+ BD_FEATURES features[HCI_EXT_FEATURES_PAGE_MAX + 1]; /* Features supported by the device */
+ UINT8 num_read_pages;
+
+#define BTM_SEC_STATE_IDLE 0
+#define BTM_SEC_STATE_AUTHENTICATING 1
+#define BTM_SEC_STATE_ENCRYPTING 2
+#define BTM_SEC_STATE_GETTING_NAME 3
+#define BTM_SEC_STATE_AUTHORIZING 4
+#define BTM_SEC_STATE_SWITCHING_ROLE 5
+#define BTM_SEC_STATE_DISCONNECTING 6 /* disconnecting BR/EDR */
+#define BTM_SEC_STATE_DELAY_FOR_ENC 7 /* delay to check for encryption to work around */
+ /* controller problems */
+#define BTM_SEC_STATE_DISCONNECTING_BLE 8 /* disconnecting BLE */
+#define BTM_SEC_STATE_DISCONNECTING_BOTH 9 /* disconnecting BR/EDR and BLE */
+
+ UINT8 sec_state; /* Operating state */
+ BOOLEAN is_originator; /* TRUE if device is originating connection */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ BOOLEAN is_ucd; /* TRUE if device is sending or receiving UCD */
+ /* if incoming security failed, received UCD will be discarded */
+#endif
+ BOOLEAN role_master; /* TRUE if current mode is master */
+ UINT16 security_required; /* Security required for connection */
+ BOOLEAN link_key_not_sent; /* link key notification has not been sent waiting for name */
+ UINT8 link_key_type; /* Type of key used in pairing */
+ BOOLEAN link_key_changed; /* Changed link key during current connection */
+
+#define BTM_MAX_PRE_SM4_LKEY_TYPE BTM_LKEY_TYPE_REMOTE_UNIT /* the link key type used by legacy pairing */
+
+#define BTM_SM4_UNKNOWN 0x00
+#define BTM_SM4_KNOWN 0x10
+#define BTM_SM4_TRUE 0x11
+#define BTM_SM4_REQ_PEND 0x08 /* set this bit when getting remote features */
+#define BTM_SM4_UPGRADE 0x04 /* set this bit when upgrading link key */
+#define BTM_SM4_RETRY 0x02 /* set this bit to retry on HCI_ERR_KEY_MISSING or HCI_ERR_LMP_ERR_TRANS_COLLISION */
+#define BTM_SM4_DD_ACP 0x20 /* set this bit to indicate peer initiated dedicated bonding */
+#define BTM_SM4_CONN_PEND 0x40 /* set this bit to indicate accepting acl conn; to be cleared on btm_acl_created */
+ UINT8 sm4; /* BTM_SM4_TRUE, if the peer supports SM4 */
+ tBTM_IO_CAP rmt_io_caps; /* IO capability of the peer device */
+ tBTM_AUTH_REQ rmt_auth_req; /* the auth_req flag as in the IO caps rsp evt */
+ BOOLEAN remote_supports_secure_connections;
+ BOOLEAN remote_features_needed; /* set to true if the local device is in */
+ /* "Secure Connections Only" mode and it receives */
+ /* HCI_IO_CAPABILITY_REQUEST_EVT from the peer before */
+ /* it knows peer's support for Secure Connections */
+ BOOLEAN remote_secure_connection_previous_state; /* Stores if peer ever supported
+ secure connection. This will be helpful to know when peer device downgrades it's security. */
+
+ UINT16 ble_hci_handle; /* use in DUMO connection */
+
+#define BTM_ENC_MODE_UNKNOWN 0xff
+ UINT8 enc_mode; /* encryption mode of current link */
+ UINT8 enc_key_size; /* current link encryption key size */
+ tBT_DEVICE_TYPE device_type;
+ BOOLEAN new_encryption_key_is_p256; /* Set to TRUE when the newly generated LK
+ ** is generated from P-256.
+ ** Link encrypted with such LK can be used
+ ** for SM over BR/EDR.
+ */
+ BOOLEAN no_smp_on_br; /* if set to TRUE then SMP on BR/EDR doesn't */
+ /* work, i.e. link keys crosspairing */
+ /* SC BR/EDR->SC LE doesn't happen */
+ tBTM_BOND_TYPE bond_type; /* peering bond type */
+
+#if BLE_INCLUDED == TRUE
+ tBTM_SEC_BLE ble;
+ tBTM_LE_CONN_PRAMS conn_params;
+#if (BLE_50_FEATURE_SUPPORT == TRUE)
+ tBTM_EXT_CONN_PARAMS ext_conn_params;
+#endif // #if (BLE_50_FEATURE_SUPPORT == TRUE)
+#endif
+
+// btla-specific ++
+#if BTM_DISC_DURING_RS == TRUE
+#define BTM_SEC_RS_NOT_PENDING 0 /* Role Switch not in progress */
+#define BTM_SEC_RS_PENDING 1 /* Role Switch in progress */
+#define BTM_SEC_DISC_PENDING 2 /* Disconnect is pending */
+ UINT8 rs_disc_pending;
+#endif
+// btla-specific --
+#define BTM_SEC_NO_LAST_SERVICE_ID 0
+ UINT8 last_author_service_id; /* ID of last serviced authorized: Reset after each l2cap connection */
+ BOOLEAN enc_init_by_we;
+};
+
+#define BTM_SEC_IS_SM4(sm) ((BOOLEAN)(BTM_SM4_TRUE == ((sm)&BTM_SM4_TRUE)))
+#define BTM_SEC_IS_SM4_LEGACY(sm) ((BOOLEAN)(BTM_SM4_KNOWN == ((sm)&BTM_SM4_TRUE)))
+#define BTM_SEC_IS_SM4_UNKNOWN(sm) ((BOOLEAN)(BTM_SM4_UNKNOWN == ((sm)&BTM_SM4_TRUE)))
+
+#define BTM_SEC_LE_MASK (BTM_SEC_LE_AUTHENTICATED|BTM_SEC_LE_ENCRYPTED|BTM_SEC_LE_LINK_KEY_KNOWN|BTM_SEC_LE_LINK_KEY_AUTHED)
+
+/*
+** Define device configuration structure
+*/
+typedef struct {
+#if BTM_MAX_LOC_BD_NAME_LEN > 0
+ tBTM_LOC_BD_NAME bd_name; /* local Bluetooth device name */
+#endif
+ BOOLEAN pin_type; /* TRUE if PIN type is fixed */
+ UINT8 pin_code_len; /* Bonding information */
+ PIN_CODE pin_code; /* PIN CODE if pin type is fixed */
+ BOOLEAN connectable; /* If TRUE page scan should be enabled */
+ UINT8 def_inq_scan_mode; /* ??? limited/general/none */
+} tBTM_CFG;
+
+enum {
+ BTM_PM_SET_MODE_EVT, /* Set power mode API is called. */
+ BTM_PM_UPDATE_EVT,
+ BTM_PM_RD_MODE_EVT /* Read power mode API is called. */
+};
+typedef UINT8 tBTM_PM_EVENT;
+
+typedef struct {
+ UINT16 event;
+ UINT16 len;
+ UINT8 link_ind;
+} tBTM_PM_MSG_DATA;
+
+typedef struct {
+ UINT8 hci_status;
+ UINT8 mode;
+ UINT16 interval;
+} tBTM_PM_MD_CHG_DATA;
+
+typedef struct {
+ UINT8 pm_id; /* the entity that calls SetPowerMode API */
+ tBTM_PM_PWR_MD *p_pmd;
+} tBTM_PM_SET_MD_DATA;
+
+typedef struct {
+ void *p_data;
+ UINT8 link_ind;
+} tBTM_PM_SM_DATA;
+
+#define BTM_PM_REC_NOT_USED 0
+typedef struct {
+ tBTM_PM_STATUS_CBACK *cback;/* to notify the registered party of mode change event */
+ UINT8 mask; /* registered request mask. 0, if this entry is not used */
+} tBTM_PM_RCB;
+
+enum {
+ BTM_BLI_ACL_UP_EVT,
+ BTM_BLI_ACL_DOWN_EVT,
+ BTM_BLI_PAGE_EVT,
+ BTM_BLI_PAGE_DONE_EVT,
+ BTM_BLI_INQ_EVT,
+ BTM_BLI_INQ_CANCEL_EVT,
+ BTM_BLI_INQ_DONE_EVT
+};
+typedef UINT8 tBTM_BLI_EVENT;
+
+/* Pairing State */
+enum {
+ BTM_PAIR_STATE_IDLE, /* Idle */
+ BTM_PAIR_STATE_GET_REM_NAME, /* Getting the remote name (to check for SM4) */
+ BTM_PAIR_STATE_WAIT_PIN_REQ, /* Started authentication, waiting for PIN req (PIN is pre-fetched) */
+ BTM_PAIR_STATE_WAIT_LOCAL_PIN, /* Waiting for local PIN code */
+ BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM, /* Waiting user 'yes' to numeric confirmation */
+ BTM_PAIR_STATE_KEY_ENTRY, /* Key entry state (we are a keyboard) */
+ BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP, /* Waiting for local response to peer OOB data */
+ BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS, /* Waiting for local IO capabilities and OOB data */
+ BTM_PAIR_STATE_INCOMING_SSP, /* Incoming SSP (got peer IO caps when idle) */
+ BTM_PAIR_STATE_WAIT_AUTH_COMPLETE, /* All done, waiting authentication complete */
+ BTM_PAIR_STATE_WAIT_DISCONNECT /* Waiting to disconnect the ACL */
+};
+typedef UINT8 tBTM_PAIRING_STATE;
+
+#define BTM_PAIR_FLAGS_WE_STARTED_DD 0x01 /* We want to do dedicated bonding */
+#define BTM_PAIR_FLAGS_PEER_STARTED_DD 0x02 /* Peer initiated dedicated bonding */
+#define BTM_PAIR_FLAGS_DISC_WHEN_DONE 0x04 /* Disconnect when done */
+#define BTM_PAIR_FLAGS_PIN_REQD 0x08 /* set this bit when pin_callback is called */
+#define BTM_PAIR_FLAGS_PRE_FETCH_PIN 0x10 /* set this bit when pre-fetch pin */
+#define BTM_PAIR_FLAGS_REJECTED_CONNECT 0x20 /* set this bit when rejected incoming connection */
+#define BTM_PAIR_FLAGS_WE_CANCEL_DD 0x40 /* set this bit when cancelling a bonding procedure */
+#define BTM_PAIR_FLAGS_LE_ACTIVE 0x80 /* use this bit when SMP pairing is active */
+
+
+typedef struct {
+ BOOLEAN is_mux;
+ BD_ADDR bd_addr;
+ UINT16 psm;
+ BOOLEAN is_orig;
+ tBTM_SEC_CALLBACK *p_callback;
+ void *p_ref_data;
+ UINT32 mx_proto_id;
+ UINT32 mx_chan_id;
+ tBT_TRANSPORT transport;
+} tBTM_SEC_QUEUE_ENTRY;
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+
+#define CONN_ORIENT_TERM 0x00 /* incoming connection oriented */
+#define CONN_ORIENT_ORIG 0x01 /* outgoing connection oriented */
+#define CONNLESS_TERM 0x02 /* incoming connectionless */
+#define CONNLESS_ORIG 0x03 /* outgoing connectionless */
+#define CONNECTION_TYPE_ORIG_MASK 0x01 /* mask for direction */
+#define CONNECTION_TYPE_CONNLESS_MASK 0x02 /* mask for connectionless or not */
+typedef UINT8 CONNECTION_TYPE;
+
+#else
+
+#define CONN_ORIENT_TERM FALSE
+#define CONN_ORIENT_ORIG TRUE
+typedef BOOLEAN CONNECTION_TYPE;
+
+#endif /* (L2CAP_UCD_INCLUDED == TRUE) */
+
+/* Define a structure to hold all the BTM data
+*/
+
+#define BTM_STATE_BUFFER_SIZE 5 /* size of state buffer */
+
+#define BTM_INVALID_HANDLE 0xFFFF
+
+typedef struct {
+ tBTM_CFG cfg; /* Device configuration */
+
+ /****************************************************
+ ** ACL Management
+ ****************************************************/
+ list_t *p_acl_db_list;
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ UINT8 btm_scn[BTM_MAX_SCN]; /* current SCNs: TRUE if SCN is in use */
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+ UINT16 btm_def_link_policy;
+ UINT16 btm_def_link_super_tout;
+
+ tBTM_ACL_LINK_STAT_CB *p_acl_link_stat_cb; /* Callback for when ACL link related events came */
+
+ tBTM_BL_EVENT_MASK bl_evt_mask;
+ tBTM_BL_CHANGE_CB *p_bl_changed_cb; /* Callback for when Busy Level changed */
+
+ /****************************************************
+ ** Power Management
+ ****************************************************/
+ list_t *p_pm_mode_db_list;
+ tBTM_PM_RCB pm_reg_db[BTM_MAX_PM_RECORDS + 1]; /* per application/module */
+ UINT16 pm_pend_link_hdl; /* the index of acl_db, which has a pending PM cmd */
+ UINT8 pm_pend_id; /* the id pf the module, which has a pending PM cmd */
+
+ /*****************************************************
+ ** Device control
+ *****************************************************/
+ tBTM_DEVCB devcb;
+
+ /*****************************************************
+ ** BLE Device controllers
+ *****************************************************/
+#if (BLE_INCLUDED == TRUE)
+ tBTM_BLE_CB ble_ctr_cb;
+
+ UINT16 enc_handle;
+ BT_OCTET8 enc_rand; /* received rand value from LTK request*/
+ UINT16 ediv; /* received ediv value from LTK request */
+ UINT8 key_size;
+ tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+#endif
+
+ /* Packet types supported by the local device */
+ UINT16 btm_acl_pkt_types_supported;
+ UINT16 btm_sco_pkt_types_supported;
+
+
+ /*****************************************************
+ ** Inquiry
+ *****************************************************/
+ tBTM_INQUIRY_VAR_ST btm_inq_vars;
+
+ /*****************************************************
+ ** SCO Management
+ *****************************************************/
+#if BTM_SCO_INCLUDED == TRUE
+ tSCO_CB sco_cb;
+#endif
+
+ /*****************************************************
+ ** Security Management
+ *****************************************************/
+ tBTM_APPL_INFO api;
+
+#define BTM_SEC_MAX_RMT_NAME_CALLBACKS 2
+
+ tBTM_RMT_NAME_CALLBACK *p_rmt_name_callback[BTM_SEC_MAX_RMT_NAME_CALLBACKS];
+#if (SMP_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_collided_dev_rec;
+#endif ///SMP_INCLUDED == TRUE
+ TIMER_LIST_ENT sec_collision_tle;
+ UINT32 collision_start_time;
+ UINT32 max_collision_delay;
+ UINT32 dev_rec_count; /* Counter used for device record timestamp */
+ UINT8 security_mode;
+ BOOLEAN pairing_disabled;
+ BOOLEAN connect_only_paired;
+ BOOLEAN security_mode_changed; /* mode changed during bonding */
+ BOOLEAN sec_req_pending; /* TRUE if a request is pending */
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ BOOLEAN pin_type_changed; /* pin type changed during bonding */
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+#if (SMP_INCLUDED == TRUE)
+#if (CLASSIC_BT_INCLUDED == TRUE)
+// btla-specific ++
+#ifdef PORCHE_PAIRING_CONFLICT
+ UINT8 pin_code_len_saved; /* for legacy devices */
+#endif
+// btla-specific --
+
+ UINT8 pin_code_len; /* for legacy devices */
+ PIN_CODE pin_code; /* for legacy devices */
+ UINT8 disc_reason; /* for legacy devices */
+ UINT16 disc_handle; /* for legacy devices */
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+ tBTM_PAIRING_STATE pairing_state; /* The current pairing state */
+ UINT8 pairing_flags; /* The current pairing flags */
+ BD_ADDR pairing_bda; /* The device currently pairing */
+ TIMER_LIST_ENT pairing_tle; /* Timer for pairing process */
+
+#endif ///SMP_INCLUDED == TRUE
+#if SMP_INCLUDED == TRUE || CLASSIC_BT_INCLUDED == TRUE
+ tBTM_SEC_SERV_REC sec_serv_rec[BTM_SEC_MAX_SERVICE_RECORDS];
+#endif // SMP_INCLUDED == TRUE || BT_CLASSIC_ENABLED == TRUE
+ list_t *p_sec_dev_rec_list;
+ tBTM_SEC_SERV_REC *p_out_serv;
+ tBTM_MKEY_CALLBACK *mkey_cback;
+
+ BD_ADDR connecting_bda;
+ DEV_CLASS connecting_dc;
+
+ UINT8 acl_disc_reason;
+ UINT8 trace_level;
+ UINT8 busy_level; /* the current busy level */
+ BOOLEAN is_paging; /* TRUE, if paging is in progess */
+ BOOLEAN is_inquiry; /* TRUE, if inquiry is in progess */
+ fixed_queue_t *page_queue;
+ BOOLEAN paging;
+ BOOLEAN discing;
+ fixed_queue_t *sec_pending_q; /* pending sequrity requests in tBTM_SEC_QUEUE_ENTRY format */
+#if (!defined(BT_TRACE_VERBOSE) || (BT_TRACE_VERBOSE == FALSE))
+ char state_temp_buffer[BTM_STATE_BUFFER_SIZE];
+#endif
+} tBTM_CB;
+
+typedef struct{
+ //connection parameters update callback
+ tBTM_UPDATE_CONN_PARAM_CBACK *update_conn_param_cb;
+}tBTM_CallbackFunc;
+
+extern tBTM_CallbackFunc conn_param_update_cb;
+/* security action for L2CAP COC channels */
+#define BTM_SEC_OK 1
+#define BTM_SEC_ENCRYPT 2 /* encrypt the link with current key */
+#define BTM_SEC_ENCRYPT_NO_MITM 3 /* unauthenticated encryption or better */
+#define BTM_SEC_ENCRYPT_MITM 4 /* authenticated encryption */
+#define BTM_SEC_ENC_PENDING 5 /* wait for link encryption pending */
+
+typedef UINT8 tBTM_SEC_ACTION;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if BTM_DYNAMIC_MEMORY == FALSE
+extern tBTM_CB btm_cb;
+#else
+extern tBTM_CB *btm_cb_ptr;
+#define btm_cb (*btm_cb_ptr)
+#endif
+
+typedef struct tSecDevContext {
+#define SEC_DEV_BTDM_BDA 0x01
+#define SEC_DEV_BDA 0x02
+#define SEC_DEV_HDL 0x03
+#define SEC_DEV_ID_ADDR 0x04
+ UINT8 type;
+ BOOLEAN free_check;
+ union {
+ BD_ADDR_PTR p_bd_addr;
+ UINT16 handle;
+ }context;
+}tSecDevContext;
+
+/* Internal functions provided by btm_main.c
+********************************************
+*/
+void btm_init (void);
+void btm_free (void);
+
+/* Internal functions provided by btm_inq.c
+*******************************************
+*/
+tBTM_STATUS btm_initiate_rem_name (BD_ADDR remote_bda,
+ tBTM_INQ_INFO *p_cur,
+ UINT8 origin, UINT32 timeout,
+ tBTM_CMPL_CB *p_cb);
+
+void btm_process_remote_name (BD_ADDR bda, BD_NAME name, UINT16 evt_len,
+ UINT8 hci_status);
+void btm_inq_rmt_name_failed(void);
+
+/* Inquiry related functions */
+void btm_clr_inq_db (BD_ADDR p_bda);
+void btm_inq_db_init (void);
+void btm_process_inq_results (UINT8 *p, UINT8 inq_res_mode);
+void btm_process_inq_complete (UINT8 status, UINT8 mode);
+void btm_process_cancel_complete(UINT8 status, UINT8 mode);
+void btm_event_filter_complete (UINT8 *p);
+void btm_inq_stop_on_ssp(void);
+void btm_inq_clear_ssp(void);
+tINQ_DB_ENT *btm_inq_db_find (BD_ADDR p_bda);
+BOOLEAN btm_inq_find_bdaddr (BD_ADDR p_bda);
+
+BOOLEAN btm_lookup_eir(BD_ADDR_PTR p_rem_addr);
+
+/* Internal functions provided by btm_acl.c
+********************************************
+*/
+void btm_acl_free(void);
+void btm_acl_init (void);
+void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, UINT8 bdn[BTM_MAX_REM_BD_NAME_LEN],
+ UINT16 hci_handle, UINT8 link_role, tBT_TRANSPORT transport);
+void btm_acl_removed (BD_ADDR bda, tBT_TRANSPORT transport);
+void btm_acl_device_down (void);
+void btm_acl_update_busy_level (tBTM_BLI_EVENT event);
+void btm_acl_link_stat_report(tBTM_ACL_LINK_STAT_EVENT_DATA *p_data);
+
+void btm_cont_rswitch (tACL_CONN *p,
+ tBTM_SEC_DEV_REC *p_dev_rec,
+ UINT8 hci_status);
+
+tACL_CONN *btm_handle_to_acl (UINT16 hci_handle);
+void btm_read_link_policy_complete (UINT8 *p);
+void btm_read_rssi_complete (UINT8 *p);
+void btm_read_tx_power_complete (UINT8 *p, BOOLEAN is_ble);
+void btm_acl_pkt_types_changed(UINT8 status, UINT16 handle, UINT16 pkt_types);
+void btm_read_link_quality_complete (UINT8 *p);
+tBTM_STATUS btm_set_packet_types (tACL_CONN *p, UINT16 pkt_types);
+void btm_process_clk_off_comp_evt (UINT16 hci_handle, UINT16 clock_offset);
+void btm_acl_role_changed (UINT8 hci_status, BD_ADDR bd_addr, UINT8 new_role);
+void btm_acl_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable);
+UINT16 btm_get_acl_disc_reason_code (void);
+tBTM_STATUS btm_remove_acl (BD_ADDR bd_addr, tBT_TRANSPORT transport);
+void btm_read_remote_features_complete (UINT8 *p);
+void btm_read_remote_ext_features_complete (UINT8 *p);
+void btm_read_remote_ext_features_failed (UINT8 status, UINT16 handle);
+void btm_read_remote_version_complete (UINT8 *p);
+void btm_establish_continue (tACL_CONN *p_acl_cb);
+
+// btla-specific ++
+void btm_acl_chk_peer_pkt_type_support (tACL_CONN *p, UINT16 *p_pkt_type);
+// btla-specific --
+/* Read maximum data packet that can be sent over current connection */
+UINT16 btm_get_max_packet_size (BD_ADDR addr);
+tACL_CONN *btm_bda_to_acl (BD_ADDR bda, tBT_TRANSPORT transport);
+BOOLEAN btm_acl_notif_conn_collision (BD_ADDR bda);
+
+void btm_pm_reset(void);
+tBTM_PM_MCB *btm_pm_sm_alloc(void);
+void btm_pm_proc_cmd_status(UINT8 status);
+void btm_pm_proc_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode,
+ UINT16 interval);
+void btm_pm_proc_ssr_evt (UINT8 *p, UINT16 evt_len);
+#if BTM_SCO_INCLUDED == TRUE
+void btm_sco_chk_pend_unpark (UINT8 hci_status, UINT16 hci_handle);
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+void btm_sco_process_num_bufs (UINT16 num_lm_sco_bufs);
+void btm_sco_process_num_completed_pkts (UINT8 *p);
+#endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */
+#else
+#define btm_sco_chk_pend_unpark(hci_status, hci_handle)
+#endif /* BTM_SCO_INCLUDED */
+void btm_qos_setup_complete (UINT8 status, UINT16 handle, FLOW_SPEC *p_flow);
+void btm_qos_setup_timeout (void *p_tle);
+
+
+#if (BLE_50_FEATURE_SUPPORT == TRUE)
+void btm_create_sync_callback(UINT8 status);
+void btm_set_phy_callback(UINT8 status);
+void btm_read_phy_callback(uint8_t hci_status, uint16_t conn_handle, uint8_t tx_phy, uint8_t rx_phy);
+#endif
+#if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE)
+void btm_ble_periodic_adv_sync_trans_complete(UINT16 op_code, UINT8 hci_status, UINT16 conn_handle);
+#endif
+/* Internal functions provided by btm_sco.c
+********************************************
+*/
+void btm_sco_init (void);
+void btm_sco_connected (UINT8 hci_status, BD_ADDR bda, UINT16 hci_handle,
+ tBTM_ESCO_DATA *p_esco_data);
+void btm_esco_proc_conn_chg (UINT8 status, UINT16 handle, UINT8 tx_interval,
+ UINT8 retrans_window, UINT16 rx_pkt_len,
+ UINT16 tx_pkt_len);
+void btm_sco_conn_req (BD_ADDR bda, DEV_CLASS dev_class, UINT8 link_type);
+void btm_sco_removed (UINT16 hci_handle, UINT8 reason);
+void btm_sco_acl_removed (BD_ADDR bda);
+void btm_route_sco_data (BT_HDR *p_msg);
+BOOLEAN btm_is_sco_active (UINT16 handle);
+void btm_remove_sco_links (BD_ADDR bda);
+BOOLEAN btm_is_sco_active_by_bdaddr (BD_ADDR remote_bda);
+
+tBTM_SCO_TYPE btm_read_def_esco_mode (tBTM_ESCO_PARAMS *p_parms);
+UINT16 btm_find_scb_by_handle (UINT16 handle);
+void btm_sco_flush_sco_data(UINT16 sco_inx);
+
+/* Internal functions provided by btm_devctl.c
+**********************************************
+*/
+void btm_dev_init (void);
+void btm_dev_timeout (TIMER_LIST_ENT *p_tle);
+void btm_read_local_name_complete (UINT8 *p, UINT16 evt_len);
+
+#if (BLE_INCLUDED == TRUE)
+void btm_ble_add_2_white_list_complete(UINT8 status);
+void btm_ble_remove_from_white_list_complete(UINT8 *p, UINT16 evt_len);
+void btm_ble_clear_white_list_complete(UINT8 *p, UINT16 evt_len);
+BOOLEAN btm_ble_addr_resolvable(BD_ADDR rpa, tBTM_SEC_DEV_REC *p_dev_rec);
+tBTM_STATUS btm_ble_read_resolving_list_entry(tBTM_SEC_DEV_REC *p_dev_rec);
+BOOLEAN btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC *p_dev_rec);
+void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC *p_dev_rec);
+#endif /* BLE_INCLUDED */
+
+/* Vendor Specific Command complete evt handler */
+void btm_vsc_complete (UINT8 *p, UINT16 cc_opcode, UINT16 evt_len,
+ tBTM_CMPL_CB *p_vsc_cplt_cback);
+void btm_inq_db_reset (void);
+void btm_vendor_specific_evt (UINT8 *p, UINT8 evt_len);
+void btm_delete_stored_link_key_complete (UINT8 *p);
+void btm_report_device_status (tBTM_DEV_STATUS status);
+void btm_set_afh_channels_complete (UINT8 *p);
+void btm_ble_set_channels_complete (UINT8 *p);
+void btm_set_page_timeout_complete (const UINT8 *p);
+void btm_page_to_setup_timeout (void *p_tle);
+
+/* Internal functions provided by btm_dev.c
+**********************************************
+*/
+BOOLEAN btm_dev_support_switch (BD_ADDR bd_addr);
+
+tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr);
+void btm_sec_free_dev (tBTM_SEC_DEV_REC *p_dev_rec, tBT_TRANSPORT transport);
+tBTM_SEC_DEV_REC *btm_find_dev (BD_ADDR bd_addr);
+tBTM_SEC_DEV_REC *btm_find_or_alloc_dev (BD_ADDR bd_addr);
+tBTM_SEC_DEV_REC *btm_find_dev_by_handle (UINT16 handle);
+tBTM_BOND_TYPE btm_get_bond_type_dev(BD_ADDR bd_addr);
+BOOLEAN btm_set_bond_type_dev(BD_ADDR bd_addr,
+ tBTM_BOND_TYPE bond_type);
+void btm_sec_dev_init(void);
+void btm_sec_dev_free(void);
+
+/* Internal functions provided by btm_sec.c
+**********************************************
+*/
+BOOLEAN btm_dev_support_switch (BD_ADDR bd_addr);
+tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm,
+ UINT16 handle, CONNECTION_TYPE conn_type,
+ tBTM_SEC_CALLBACK *p_callback, void *p_ref_data);
+tBTM_STATUS btm_sec_mx_access_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_originator,
+ UINT32 mx_proto_id, UINT32 mx_chan_id,
+ tBTM_SEC_CALLBACK *p_callback, void *p_ref_data);
+void btm_sec_conn_req (UINT8 *bda, UINT8 *dc);
+void btm_create_conn_cancel_complete (UINT8 *p);
+void btm_read_linq_tx_power_complete (UINT8 *p);
+
+void btm_sec_init (UINT8 sec_mode);
+void btm_sec_dev_reset (void);
+void btm_sec_abort_access_req (BD_ADDR bd_addr);
+void btm_sec_auth_complete (UINT16 handle, UINT8 status);
+void btm_sec_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable);
+void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode);
+tBTM_STATUS btm_sec_disconnect (UINT16 handle, UINT8 reason);
+void btm_sec_disconnected (UINT16 handle, UINT8 reason);
+void btm_sec_rmt_name_request_complete (UINT8 *bd_addr, UINT8 *bd_name, UINT8 status);
+void btm_sec_rmt_host_support_feat_evt (UINT8 *p);
+void btm_io_capabilities_req (UINT8 *p);
+void btm_io_capabilities_rsp (UINT8 *p);
+#if (CLASSIC_BT_INCLUDED == TRUE)
+void btm_proc_sp_req_evt (tBTM_SP_EVT event, UINT8 *p);
+void btm_keypress_notif_evt (UINT8 *p);
+void btm_simple_pair_complete (UINT8 *p);
+#endif /* (CLASSIC_BT_INCLUDED == TRUE) */
+void btm_sec_link_key_notification (UINT8 *p_bda, UINT8 *p_link_key, UINT8 key_type);
+void btm_sec_link_key_request (UINT8 *p_bda);
+void btm_sec_pin_code_request (UINT8 *p_bda);
+void btm_sec_update_clock_offset (UINT16 handle, UINT16 clock_offset);
+void btm_sec_dev_rec_cback_event (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 res, BOOLEAN is_le_transport);
+void btm_sec_set_peer_sec_caps (tACL_CONN *p_acl_cb, tBTM_SEC_DEV_REC *p_dev_rec);
+
+#if BLE_INCLUDED == TRUE
+void btm_sec_clear_ble_keys (tBTM_SEC_DEV_REC *p_dev_rec);
+BOOLEAN btm_sec_find_bonded_dev (UINT8 start_idx, UINT16 *p_found_handle, tBTM_SEC_DEV_REC **p_rec);
+BOOLEAN btm_sec_is_a_bonded_dev (BD_ADDR bda);
+void btm_consolidate_dev(tBTM_SEC_DEV_REC *p_target_rec);
+BOOLEAN btm_sec_is_le_capable_dev (BD_ADDR bda);
+BOOLEAN btm_ble_init_pseudo_addr (tBTM_SEC_DEV_REC *p_dev_rec, BD_ADDR new_pseudo_addr);
+extern BOOLEAN btm_ble_start_sec_check(BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_originator,
+ tBTM_SEC_CALLBACK *p_callback, void *p_ref_data);
+#endif /* BLE_INCLUDED */
+
+extern tBTM_SEC_SERV_REC *btm_sec_find_first_serv (CONNECTION_TYPE conn_type, UINT16 psm);
+
+tINQ_DB_ENT *btm_inq_db_new (BD_ADDR p_bda);
+
+#if BTM_OOB_INCLUDED == TRUE
+void btm_rem_oob_req (UINT8 *p);
+void btm_read_local_oob_complete (UINT8 *p);
+#else
+#define btm_rem_oob_req(p)
+#define btm_read_local_oob_complete(p)
+#endif
+
+void btm_acl_resubmit_page (void);
+void btm_acl_reset_paging (void);
+void btm_acl_paging (BT_HDR *p, BD_ADDR dest);
+UINT8 btm_sec_clr_service_by_psm (UINT16 psm);
+void btm_sec_clr_temp_auth_service (BD_ADDR bda);
+
+void btm_ble_lock_init(void);
+
+void btm_ble_sem_init(void);
+
+void btm_ble_sem_free(void);
+
+void btm_ble_lock_free(void);
+
+void btm_sec_handle_remote_legacy_auth_cmp(UINT16 handle);
+void btm_sec_update_legacy_auth_state(tACL_CONN *p_acl_cb, UINT8 legacy_auth_state);
+BOOLEAN btm_sec_legacy_authentication_mutual (tBTM_SEC_DEV_REC *p_dev_rec);
+BOOLEAN btm_find_sec_dev_in_list (void *p_node_data, void *context);
+
+BOOLEAN btm_sec_dev_authorization(BD_ADDR bd_addr, BOOLEAN authorized);
+
+/*
+#ifdef __cplusplus
+}
+#endif
+*/
+
+#endif