summaryrefslogtreecommitdiffstats
path: root/stack/btm
diff options
context:
space:
mode:
Diffstat (limited to 'stack/btm')
-rw-r--r--stack/btm/btm_acl.c3141
-rw-r--r--stack/btm/btm_ble.c1900
-rw-r--r--stack/btm/btm_ble_addr.c383
-rw-r--r--stack/btm/btm_ble_bgconn.c616
-rw-r--r--stack/btm/btm_ble_gap.c2084
-rw-r--r--stack/btm/btm_ble_int.h299
-rw-r--r--stack/btm/btm_dev.c464
-rw-r--r--stack/btm/btm_devctl.c1953
-rw-r--r--stack/btm/btm_inq.c3265
-rw-r--r--stack/btm/btm_int.h1114
-rw-r--r--stack/btm/btm_main.c70
-rw-r--r--stack/btm/btm_pm.c998
-rw-r--r--stack/btm/btm_sco.c1750
-rw-r--r--stack/btm/btm_sec.c5649
14 files changed, 23686 insertions, 0 deletions
diff --git a/stack/btm/btm_acl.c b/stack/btm/btm_acl.c
new file mode 100644
index 0000000..e3ac11b
--- /dev/null
+++ b/stack/btm/btm_acl.c
@@ -0,0 +1,3141 @@
+/******************************************************************************
+ *
+ * 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 ACL connections. This includes
+ * operations such as hold and sniff modes, supported packet types.
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "bt_types.h"
+#include "bt_target.h"
+#include "gki.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "l2c_int.h"
+#include "hcidefs.h"
+static void btm_establish_continue (tACL_CONN *p_acl_cb);
+
+#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_DEBUG0 ("btm_acl_init");
+#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));
+#if RFCOMM_INCLUDED == TRUE
+ memset (btm_cb.btm_scn, 0, BTM_MAX_SCN); /* Initialize the SCN usage to FALSE */
+#endif
+ btm_cb.btm_def_link_policy = 0;
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ btm_cb.p_bl_changed_cb = NULL;
+#else
+ btm_cb.p_acl_changed_cb = NULL;
+#endif
+#endif
+
+ /* 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.
+**
+** Returns Returns pointer to the ACL DB for the requested BDA if found.
+** NULL if not found.
+**
+*******************************************************************************/
+tACL_CONN *btm_bda_to_acl (BD_ADDR bda)
+{
+ tACL_CONN *p = &btm_cb.acl_db[0];
+ UINT16 xx;
+ if (bda)
+ {
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++)
+ {
+ if ((p->in_use) && (!memcmp (p->remote_addr, bda, BD_ADDR_LEN)))
+ {
+ BTM_TRACE_DEBUG0 ("btm_bda_to_acl found");
+ return(p);
+ }
+ }
+ }
+ BTM_TRACE_DEBUG0 ("btm_bda_to_acl Not found");
+
+ /* If here, no BD Addr found */
+ return((tACL_CONN *)NULL);
+}
+
+/*******************************************************************************
+**
+** Function btm_handle_to_acl_index
+**
+** Description This function returns the FIRST acl_db entry for the passed hci_handle.
+**
+** Returns index to the acl_db or MAX_L2CAP_LINKS.
+**
+*******************************************************************************/
+UINT8 btm_handle_to_acl_index (UINT16 hci_handle)
+{
+ tACL_CONN *p = &btm_cb.acl_db[0];
+ UINT8 xx;
+ BTM_TRACE_DEBUG0 ("btm_handle_to_acl_index");
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++)
+ {
+ if ((p->in_use) && (p->hci_handle == hci_handle))
+ {
+ break;
+ }
+ }
+
+ /* If here, no BD Addr found */
+ return(xx);
+}
+
+
+/*******************************************************************************
+**
+** 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, BD_NAME bdn,
+ UINT16 hci_handle, UINT8 link_role, UINT8 is_le_link)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ UINT8 yy;
+ tACL_CONN *p;
+ UINT8 xx;
+
+ BTM_TRACE_DEBUG3 ("btm_acl_created hci_handle=%d link_role=%d is_le_link=%d",
+ hci_handle,link_role, is_le_link);
+ /* Ensure we don't have duplicates */
+ p = btm_bda_to_acl(bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ p->hci_handle = hci_handle;
+ p->link_role = link_role;
+#if BLE_INCLUDED == TRUE
+ p->is_le_link = is_le_link;
+#endif
+ BTM_TRACE_DEBUG6 ("Duplicate btm_acl_created: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ 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 */
+ for (xx = 0, p = &btm_cb.acl_db[0]; xx < MAX_L2CAP_LINKS; xx++, p++)
+ {
+ if (!p->in_use)
+ {
+ p->in_use = TRUE;
+ p->hci_handle = hci_handle;
+ p->link_role = link_role;
+ p->link_up_issued = FALSE;
+#if BLE_INCLUDED == TRUE
+ p->is_le_link = is_le_link;
+#endif
+ p->restore_pkt_types = 0; /* Only exists while SCO is active */
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+
+#if BTM_PWR_MGR_INCLUDED == FALSE
+ p->mode = BTM_ACL_MODE_NORMAL;
+#else
+ btm_pm_sm_alloc(xx);
+#endif /* BTM_PWR_MGR_INCLUDED == FALSE */
+
+ memcpy (p->remote_addr, bda, BD_ADDR_LEN);
+
+ if (dc)
+ memcpy (p->remote_dc, dc, DEV_CLASS_LEN);
+
+ if (bdn)
+ memcpy (p->remote_name, bdn, BTM_MAX_REM_BD_NAME_LEN);
+
+
+ /* Check if we already know features for this device */
+ p_dev_rec = btm_find_dev_by_handle (hci_handle);
+
+#if (BLE_INCLUDED == TRUE)
+ if (p_dev_rec )
+ {
+ BTM_TRACE_DEBUG1 ("device_type=0x%x", p_dev_rec->device_type);
+ }
+#endif
+
+
+ if (p_dev_rec
+#if (BLE_INCLUDED == TRUE)
+ && p_dev_rec->device_type != BT_DEVICE_TYPE_BLE
+#endif
+ )
+ {
+
+ /* if BR/EDR do something more */
+ btsnd_hcic_read_rmt_clk_offset (p->hci_handle);
+ btsnd_hcic_rmt_ver_req (p->hci_handle);
+
+ for (yy = 0; yy < BD_FEATURES_LEN; yy++)
+ {
+ if (p_dev_rec->features[yy])
+ {
+ memcpy (p->features, p_dev_rec->features, BD_FEATURES_LEN);
+ if (BTM_SEC_MODE_SP == btm_cb.security_mode &&
+ HCI_SIMPLE_PAIRING_SUPPORTED(p->features))
+ {
+ /* if SM4 supported, check peer support for SM4
+ * The remote controller supports SSP according to saved remote features
+ * read the extended feature page 1 for the host support for SSP */
+ if (btsnd_hcic_rmt_ext_features (p_dev_rec->hci_handle, 1))
+ return;
+ }
+ /* peer does not support SSP */
+ p_dev_rec->sm4 |= BTM_SM4_KNOWN;
+
+ btm_establish_continue (p);
+ return;
+ }
+ }
+ }
+#if (BLE_INCLUDED == TRUE)
+ /* If here, features are not known yet */
+ if (p_dev_rec && p_dev_rec->device_type == BT_DEVICE_TYPE_BLE)
+ {
+ btm_establish_continue(p);
+
+ if (link_role == HCI_ROLE_MASTER)
+ {
+ btm_ble_update_bg_state();
+ btm_ble_resume_bg_conn (NULL, FALSE);
+
+ btsnd_hcic_ble_read_remote_feat(p->hci_handle);
+ }
+ }
+ else
+#endif
+ {
+ btsnd_hcic_rmt_features_req (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_DEBUG0 ("btm_acl_report_role_change");
+ 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))))
+ {
+ memset (&btm_cb.devcb.switch_role_ref_data, 0, sizeof(tBTM_ROLE_SWITCH_CMPL));
+ ref_data.hci_status = hci_status;
+ memcpy (&ref_data, &btm_cb.devcb.switch_role_ref_data, sizeof(tBTM_ROLE_SWITCH_CMPL));
+ (*btm_cb.devcb.p_switch_role_cb)(&ref_data);
+ 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)
+{
+ tACL_CONN *p;
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ tBTM_BL_EVENT_DATA evt_data;
+#endif
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec=NULL;
+ UINT16 combined_mode;
+#endif
+
+ BTM_TRACE_DEBUG0 ("btm_acl_removed");
+ p = btm_bda_to_acl(bda);
+ 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 (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ if (btm_cb.p_bl_changed_cb)
+ {
+ evt_data.event = BTM_BL_DISCN_EVT;
+ evt_data.discn.p_bda = bda;
+
+ (*btm_cb.p_bl_changed_cb)(&evt_data);
+ }
+
+ btm_acl_update_busy_level (BTM_BLI_ACL_DOWN_EVT);
+#else
+ if (btm_cb.p_acl_changed_cb)
+ (*btm_cb.p_acl_changed_cb) (bda, NULL, NULL, NULL, FALSE);
+#endif
+ }
+
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+
+ BTM_TRACE_DEBUG4 ("acl hci_handle=%d is_le_link=%d connectable_mode=0x%0x link_role=%d",
+ p->hci_handle,
+ p->is_le_link,
+ btm_cb.ble_ctr_cb.inq_var.connectable_mode,
+ p->link_role);
+
+
+ /* If we are LE connectable, check if we need to start advertising again */
+ if ( p->is_le_link && (btm_cb.ble_ctr_cb.inq_var.connectable_mode != BTM_BLE_NON_CONNECTABLE) )
+ {
+ tACL_CONN *pa = &btm_cb.acl_db[0];
+ UINT16 xx;
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, pa++)
+ {
+ /* If any other LE link is up, we are still not connectable */
+ if (pa->in_use && pa->is_le_link)
+ return;
+ }
+ combined_mode = (btm_cb.ble_ctr_cb.inq_var.connectable_mode | btm_cb.btm_inq_vars.connectable_mode);
+ btm_ble_set_connectability ( combined_mode );
+ }
+
+ p_dev_rec = btm_find_dev(bda);
+ if ( p_dev_rec)
+ {
+ BTM_TRACE_DEBUG1("before update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags);
+ if (p->is_le_link)
+ {
+ BTM_TRACE_DEBUG0("LE link down");
+ p_dev_rec->sec_flags &= ~(BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED);
+ if ( (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) == 0)
+ {
+ BTM_TRACE_DEBUG0("Not Bonded");
+ p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHENTICATED | BTM_SEC_LINK_KEY_AUTHED);
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0("Bonded");
+ }
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0("Bletooth link down");
+ p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED);
+ }
+ BTM_TRACE_DEBUG1("after update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags);
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("Device not found");
+
+ }
+#endif
+
+ return;
+ }
+}
+
+
+/*******************************************************************************
+**
+** 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 = &btm_cb.acl_db[0];
+ UINT16 xx;
+ BTM_TRACE_DEBUG0 ("btm_acl_device_down");
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++)
+ {
+ if (p->in_use)
+ {
+ BTM_TRACE_DEBUG1 ("hci_handle=%d HCI_ERR_HW_FAILURE ",p->hci_handle );
+ l2c_link_hci_disc_comp (p->hci_handle, HCI_ERR_HW_FAILURE);
+ }
+ }
+}
+
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** 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_DEBUG0 ("btm_acl_update_busy_level");
+ switch (event)
+ {
+ case BTM_BLI_ACL_UP_EVT:
+ BTM_TRACE_DEBUG0 ("BTM_BLI_ACL_UP_EVT");
+ btm_cb.num_acl++;
+ busy_level = (UINT8)btm_cb.num_acl;
+ break;
+ case BTM_BLI_ACL_DOWN_EVT:
+ if (btm_cb.num_acl)
+ {
+ btm_cb.num_acl--;
+ BTM_TRACE_DEBUG1 ("BTM_BLI_ACL_DOWN_EVT", btm_cb.num_acl);
+ }
+ else
+ {
+ BTM_TRACE_ERROR0 ("BTM_BLI_ACL_DOWN_EVT issued, but num_acl already zero !!!");
+ }
+ busy_level = (UINT8)btm_cb.num_acl;
+ break;
+ case BTM_BLI_PAGE_EVT:
+ BTM_TRACE_DEBUG0 ("BTM_BLI_PAGE_EVT");
+ btm_cb.is_paging = TRUE;
+ busy_level = BTM_BL_PAGING_STARTED;
+ break;
+ case BTM_BLI_PAGE_DONE_EVT:
+ BTM_TRACE_DEBUG0 ("BTM_BLI_PAGE_DONE_EVT");
+ btm_cb.is_paging = FALSE;
+ busy_level = BTM_BL_PAGING_COMPLETE;
+ break;
+ case BTM_BLI_INQ_EVT:
+ BTM_TRACE_DEBUG0 ("BTM_BLI_INQ_EVT");
+ btm_cb.is_inquiry = TRUE;
+ busy_level = BTM_BL_INQUIRY_STARTED;
+ break;
+ case BTM_BLI_INQ_CANCEL_EVT:
+ BTM_TRACE_DEBUG0 ("BTM_BLI_INQ_CANCEL_EVT");
+ btm_cb.is_inquiry = FALSE;
+ busy_level = BTM_BL_INQUIRY_CANCELLED;
+ break;
+ case BTM_BLI_INQ_DONE_EVT:
+ BTM_TRACE_DEBUG0 ("BTM_BLI_INQ_DONE_EVT");
+ btm_cb.is_inquiry = FALSE;
+ busy_level = BTM_BL_INQUIRY_COMPLETE;
+ break;
+ }
+
+ if (busy_level != btm_cb.busy_level)
+ {
+ 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);
+ }
+ }
+}
+#endif
+
+
+/*******************************************************************************
+**
+** 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_DEBUG0 ("BTM_GetRole");
+ if ((p = btm_bda_to_acl(remote_bd_addr)) == 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
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ tBTM_STATUS status;
+ tBTM_PM_MODE pwr_mode;
+ tBTM_PM_PWR_MD settings;
+#endif
+#if (BT_USE_TRACES == TRUE)
+ BD_ADDR_PTR p_bda;
+#endif
+ BTM_TRACE_API6 ("BTM_SwitchRole BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+ 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 (!(HCI_SWITCH_SUPPORTED(btm_cb.devcb.local_features)))
+ 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_DEBUG6 ("Role switch on other device is in progress 0x%02x%02x%02x%02x%02x%02x",
+ 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)) == 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_DEBUG1 ("BTM_SwitchRole busy: %d",
+ p->switch_role_state);
+ return(BTM_BUSY);
+ }
+
+ /* Cannot switch role while parked or sniffing */
+#if BTM_PWR_MGR_INCLUDED == FALSE
+ if (p->mode == HCI_MODE_PARK)
+ {
+ if (!btsnd_hcic_exit_park_mode (p->hci_handle))
+ return(BTM_NO_RESOURCES);
+
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_MODE_CHANGE;
+ }
+ else if (p->mode == HCI_MODE_SNIFF)
+ {
+ if (!btsnd_hcic_exit_sniff_mode (p->hci_handle))
+ return(BTM_NO_RESOURCES);
+
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_MODE_CHANGE;
+ }
+#else /* power manager is in use */
+
+ 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)
+ {
+/* Coverity FALSE-POSITIVE error from Coverity tool. Please do NOT remove following comment. */
+/* coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode
+ the other data members of tBTM_PM_PWR_MD are ignored
+*/
+ 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;
+ }
+#endif
+ /* some devices do not support switch while encryption is on */
+ else
+ {
+ if (((p_dev_rec = btm_find_dev (remote_bd_addr)) != 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_ChangeLinkKey
+**
+** Description This function is called to change the link key of the
+** connection.
+**
+** Returns 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_BUSY if the previous command is not completed
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ChangeLinkKey (BD_ADDR remote_bd_addr, tBTM_CMPL_CB *p_cb)
+{
+ tACL_CONN *p;
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ tBTM_STATUS status;
+ tBTM_PM_MODE pwr_mode;
+ tBTM_PM_PWR_MD settings;
+#endif
+ BTM_TRACE_DEBUG0 ("BTM_ChangeLinkKey");
+ if ((p = btm_bda_to_acl(remote_bd_addr)) == NULL)
+ return(BTM_UNKNOWN_ADDR);
+
+ /* Ignore change link key request if the previsous request has not completed */
+ if (p->change_key_state != BTM_ACL_SWKEY_STATE_IDLE)
+ {
+ BTM_TRACE_DEBUG0 ("Link key change request declined since the previous request for this device has not completed ");
+ return(BTM_BUSY);
+ }
+
+ memset (&btm_cb.devcb.chg_link_key_ref_data, 0, sizeof(tBTM_CHANGE_KEY_CMPL));
+
+ /* Cannot change key while parked */
+#if BTM_PWR_MGR_INCLUDED == FALSE
+ if (p->mode == HCI_MODE_PARK)
+ {
+ if (!btsnd_hcic_exit_park_mode (p->hci_handle))
+ return(BTM_NO_RESOURCES);
+
+ p->change_key_state = BTM_ACL_SWKEY_STATE_MODE_CHANGE;
+ }
+#else /* power manager is in use */
+
+
+ if ((status = BTM_ReadPowerMode(p->remote_addr, &pwr_mode)) != BTM_SUCCESS)
+ return(status);
+
+ /* Wake up the link if in park before attempting to change link keys */
+ if (pwr_mode == BTM_PM_MD_PARK)
+ {
+/* Coverity: FALSE-POSITIVE error from Coverity tool. Please do NOT remove following comment. */
+/* coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode
+ the other data members of tBTM_PM_PWR_MD are ignored
+*/
+ 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->change_key_state = BTM_ACL_SWKEY_STATE_MODE_CHANGE;
+ }
+#endif
+ /* some devices do not support change of link key while encryption is on */
+ else if (((p_dev_rec = btm_find_dev (remote_bd_addr)) != NULL)
+ && ((p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) != 0) && !BTM_EPR_AVAILABLE(p))
+ {
+ /* bypass turning off encryption if switch role 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->change_key_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF;
+ }
+ else /* Ok to initiate change of link key */
+ {
+ if (!btsnd_hcic_change_link_key (p->hci_handle))
+ return(BTM_NO_RESOURCES);
+
+ p->change_key_state = BTM_ACL_SWKEY_STATE_IN_PROGRESS;
+ }
+
+ /* Initialize return structure in case request fails */
+ memcpy (btm_cb.devcb.chg_link_key_ref_data.remote_bd_addr, remote_bd_addr,
+ BD_ADDR_LEN);
+ btm_cb.devcb.p_chg_link_key_cb = p_cb;
+ return(BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_link_key_change
+**
+** Description This function is called to when a change link key event
+** is received.
+**
+*******************************************************************************/
+void btm_acl_link_key_change (UINT16 handle, UINT8 status)
+{
+ tBTM_CHANGE_KEY_CMPL *p_data;
+ tACL_CONN *p;
+ UINT8 xx;
+ BTM_TRACE_DEBUG0 ("btm_acl_link_key_change");
+ /* Look up the connection by handle and set the current mode */
+ xx = btm_handle_to_acl_index(handle);
+
+ /* don't assume that we can never get a bad hci_handle */
+ if (xx >= MAX_L2CAP_LINKS)
+ return;
+
+ p_data = &btm_cb.devcb.chg_link_key_ref_data;
+ p = &btm_cb.acl_db[xx];
+ p_data->hci_status = status;
+
+ /* if switching state is switching we need to turn encryption on */
+ /* if idle, we did not change encryption */
+ if (p->change_key_state == BTM_ACL_SWKEY_STATE_SWITCHING)
+ {
+ /* Make sure there's not also a role switch going on before re-enabling */
+ 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->change_key_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_ON;
+ return;
+ }
+ }
+ else /* Set the state and wait for change link key */
+ {
+ p->change_key_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->change_key_state == BTM_ACL_SWKEY_STATE_IN_PROGRESS)
+ {
+ p->change_key_state = BTM_ACL_SWKEY_STATE_IDLE;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ }
+
+ if (btm_cb.devcb.p_chg_link_key_cb)
+ {
+ (*btm_cb.devcb.p_chg_link_key_cb)((void *)p_data);
+ btm_cb.devcb.p_chg_link_key_cb = NULL;
+ }
+
+ BTM_TRACE_ERROR2("Change Link Key Complete Event: Handle 0x%02x, HCI Status 0x%02x",
+ handle, p_data->hci_status);
+}
+
+/*******************************************************************************
+**
+** 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;
+ UINT8 xx;
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ tBTM_BL_ROLE_CHG_DATA evt;
+#endif
+#if BTM_DISC_DURING_RS == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec;
+#endif
+ BTM_TRACE_DEBUG3 ("btm_acl_encrypt_change handle=%d status=%d encr_enabl=%d", handle, status, encr_enable);
+ xx = btm_handle_to_acl_index(handle);
+ /* don't assume that we can never get a bad hci_handle */
+ if (xx < MAX_L2CAP_LINKS)
+ p = &btm_cb.acl_db[xx];
+ else
+ 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 (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ /* 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_DEBUG3("Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, rs_st:%d",
+ evt.new_role, evt.hci_status, p->switch_role_state);
+ }
+#endif
+
+#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_WARNING0("btm_acl_encrypt_change -> Issuing delayed HCI_Disconnect!!!");
+ btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER);
+ }
+ BTM_TRACE_ERROR2("btm_acl_encrypt_change: tBTM_SEC_DEV:0x%x rs_disc_pending=%d",
+ (UINT32)p_dev_rec, p_dev_rec->rs_disc_pending);
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+ }
+#endif
+ }
+
+
+ /* Process Change Link Key if active */
+ if (p->change_key_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF)
+ {
+ /* if encryption turn off failed we still will try to change link key */
+ if (encr_enable)
+ {
+ p->change_key_state = BTM_ACL_SWKEY_STATE_IDLE;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ }
+ else
+ {
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_TEMP_FUNC;
+ p->change_key_state = BTM_ACL_SWKEY_STATE_SWITCHING;
+ }
+
+ if (!btsnd_hcic_change_link_key (p->hci_handle))
+ {
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ p->change_key_state = BTM_ACL_SWKEY_STATE_IDLE;
+ if (btm_cb.devcb.p_chg_link_key_cb)
+ {
+ (*btm_cb.devcb.p_chg_link_key_cb)(&btm_cb.devcb.chg_link_key_ref_data);
+ btm_cb.devcb.p_chg_link_key_cb = NULL;
+ }
+ }
+ }
+ /* Finished enabling Encryption after changing link key */
+ else if (p->change_key_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_ON)
+ {
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ p->change_key_state = BTM_ACL_SWKEY_STATE_IDLE;
+ if (btm_cb.devcb.p_chg_link_key_cb)
+ {
+ (*btm_cb.devcb.p_chg_link_key_cb)(&btm_cb.devcb.chg_link_key_ref_data);
+ btm_cb.devcb.p_chg_link_key_cb = NULL;
+ }
+ }
+}
+/*******************************************************************************
+**
+** 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_DEBUG0 ("BTM_SetLinkPolicy");
+/* BTM_TRACE_API1 ("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_API1 ("BTM_SetLinkPolicy switch not supported (settings: 0x%04x)", *settings );
+ }
+ if ( (*settings & HCI_ENABLE_HOLD_MODE) && (!HCI_HOLD_MODE_SUPPORTED(localFeatures)) )
+ {
+ *settings &= (~HCI_ENABLE_HOLD_MODE);
+ BTM_TRACE_API1 ("BTM_SetLinkPolicy hold not supported (settings: 0x%04x)", *settings );
+ }
+ if ( (*settings & HCI_ENABLE_SNIFF_MODE) && (!HCI_SNIFF_MODE_SUPPORTED(localFeatures)) )
+ {
+ *settings &= (~HCI_ENABLE_SNIFF_MODE);
+ BTM_TRACE_API1 ("BTM_SetLinkPolicy sniff not supported (settings: 0x%04x)", *settings );
+ }
+ if ( (*settings & HCI_ENABLE_PARK_MODE) && (!HCI_PARK_MODE_SUPPORTED(localFeatures)) )
+ {
+ *settings &= (~HCI_ENABLE_PARK_MODE);
+ BTM_TRACE_API1 ("BTM_SetLinkPolicy park not supported (settings: 0x%04x)", *settings );
+ }
+ }
+
+ if ((p = btm_bda_to_acl(remote_bda)) != 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)
+{
+ BTM_TRACE_DEBUG0 ("BTM_SetDefaultLinkPolicy");
+ btm_cb.btm_def_link_policy = settings;
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadLinkPolicy
+**
+** Description This function is called to read the link policy settings.
+** The address of link policy results are returned in the callback.
+** (tBTM_LNK_POLICY_RESULTS)
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadLinkPolicy (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_API6 ("BTM_ReadLinkPolicy: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ 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_rlinkp_cmpl_cb)
+ return(BTM_BUSY);
+
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ btu_start_timer (&btm_cb.devcb.rlinkp_timer, BTU_TTYPE_BTM_ACL, BTM_DEV_REPLY_TIMEOUT);
+ btm_cb.devcb.p_rlinkp_cmpl_cb = p_cb;
+
+ if (!btsnd_hcic_read_policy_set (p->hci_handle))
+ {
+ btu_stop_timer (&btm_cb.devcb.rlinkp_timer);
+ btm_cb.devcb.p_rlinkp_cmpl_cb = NULL;
+ return(BTM_NO_RESOURCES);
+ }
+
+ return(BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_read_link_policy_complete
+**
+** 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_read_link_policy_complete (UINT8 *p)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_rlinkp_cmpl_cb;
+ tBTM_LNK_POLICY_RESULTS lnkpol;
+ UINT16 handle;
+ tACL_CONN *p_acl_cb = &btm_cb.acl_db[0];
+ UINT16 index;
+ BTM_TRACE_DEBUG0 ("btm_read_link_policy_complete");
+ btu_stop_timer (&btm_cb.devcb.rlinkp_timer);
+
+ /* If there was a callback address for read local version, call it */
+ btm_cb.devcb.p_rlinkp_cmpl_cb = NULL;
+
+ if (p_cb)
+ {
+ STREAM_TO_UINT8 (lnkpol.hci_status, p);
+
+ if (lnkpol.hci_status == HCI_SUCCESS)
+ {
+ lnkpol.status = BTM_SUCCESS;
+
+ STREAM_TO_UINT16 (handle, p);
+
+ STREAM_TO_UINT16 (lnkpol.settings, p);
+
+ /* Search through the list of active channels for the correct BD Addr */
+ for (index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++)
+ {
+ if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle))
+ {
+ memcpy (lnkpol.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN);
+ break;
+ }
+ }
+ }
+ else
+ lnkpol.status = BTM_ERR_PROCESSING;
+
+ (*p_cb)(&lnkpol);
+ }
+}
+
+
+/*******************************************************************************
+**
+** 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 = &btm_cb.acl_db[0];
+ UINT8 status;
+ UINT16 handle;
+ int xx;
+ BTM_TRACE_DEBUG0 ("btm_read_remote_version_complete");
+ STREAM_TO_UINT8 (status, p);
+ if (status == HCI_SUCCESS)
+ {
+ STREAM_TO_UINT16 (handle, p);
+
+ /* Look up the connection by handle and copy features */
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_acl_cb++)
+ {
+ if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle))
+ {
+ 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);
+ break;
+ }
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_read_remote_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_features_complete (UINT8 *p)
+{
+ tACL_CONN *p_acl_cb = &btm_cb.acl_db[0];
+ UINT8 status;
+ UINT16 handle;
+ int xx, yy;
+ UINT8 req_pend;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BTM_TRACE_DEBUG0 ("btm_read_remote_features_complete");
+ STREAM_TO_UINT8 (status, p);
+ if (status == HCI_SUCCESS)
+ {
+ STREAM_TO_UINT16 (handle, p);
+
+ /* Look up the connection by handle and copy features */
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_acl_cb++)
+ {
+ if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle))
+ {
+ for (yy = 0; yy < BD_FEATURES_LEN; yy++)
+ STREAM_TO_UINT8 (p_acl_cb->features[yy], p);
+
+ p_dev_rec = btm_find_dev_by_handle (handle);
+ if (!p_dev_rec)
+ {
+ /* Get a new device; might be doing dedicated bonding */
+ p_dev_rec = btm_find_or_alloc_dev (p_acl_cb->remote_addr);
+ }
+
+ memcpy (p_dev_rec->features, p_acl_cb->features, BD_FEATURES_LEN);
+
+ if (BTM_SEC_MODE_SP == btm_cb.security_mode &&
+ HCI_SIMPLE_PAIRING_SUPPORTED(p_acl_cb->features))
+ {
+ /* if SM4 supported, check peer support for SM4
+ * The remote controller supports SSP
+ * read the extended feature page 1 for the host support for SSP */
+ if (btsnd_hcic_rmt_ext_features (handle, 1))
+ break;
+ }
+ else
+ {
+ req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND);
+ p_dev_rec->sm4 = BTM_SM4_KNOWN;
+ if (req_pend)
+ {
+ l2cu_resubmit_pending_sec_req (p_dev_rec->bd_addr);
+ }
+ }
+
+ btm_establish_continue (p_acl_cb);
+ break;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** 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 = &btm_cb.acl_db[0];
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ UINT8 status, page_num, max_page;
+ UINT16 handle;
+ int xx;
+ BD_FEATURES ext_features; /* extended Features suported by the device */
+ UINT8 req_pend;
+ BTM_TRACE_DEBUG0 ("btm_read_remote_ext_features_complete");
+ STREAM_TO_UINT8 (status, p);
+ if (status == HCI_SUCCESS)
+ {
+ STREAM_TO_UINT16 (handle, p);
+
+ /* Look up the connection by handle and copy features */
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_acl_cb++)
+ {
+ if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle))
+ {
+ STREAM_TO_UINT8 (page_num, p);
+ STREAM_TO_UINT8 (max_page, p);
+ p_dev_rec = btm_find_dev_by_handle (handle);
+ if (!p_dev_rec)
+ p_dev_rec = btm_find_or_alloc_dev (p_acl_cb->remote_addr);
+
+ req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND);
+
+ if (page_num == 1 && max_page >= 1)
+ {
+ /* only the byte 0 of page 1 is used right now */
+ STREAM_TO_UINT8 (ext_features[0], p);
+
+ if (HCI_SSP_HOST_SUPPORTED(ext_features))
+ {
+ p_dev_rec->sm4 = BTM_SM4_TRUE;
+ }
+ }
+
+ BTM_TRACE_API5 ("ext_features_complt page_num:%d max_page:%d f[0]:x%02x, sm4:%x, pend:%d",
+ page_num, max_page, *p, p_dev_rec->sm4, req_pend);
+
+ if (!BTM_SEC_IS_SM4(p_dev_rec->sm4))
+ {
+ p_dev_rec->sm4 = BTM_SM4_KNOWN;
+ }
+
+ if (req_pend)
+ l2cu_resubmit_pending_sec_req (p_dev_rec->bd_addr);
+
+ btm_establish_continue (p_acl_cb);
+
+ break;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+ BTM_TRACE_ERROR1 ("btm_read_remote_ext_features_failed (status 0x%02x)", status);
+}
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+static void btm_establish_continue (tACL_CONN *p_acl_cb)
+{
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ tBTM_BL_EVENT_DATA evt_data;
+#endif
+ BTM_TRACE_DEBUG0 ("btm_establish_continue");
+#if (!defined(BTM_BYPASS_EXTRA_ACL_SETUP) || BTM_BYPASS_EXTRA_ACL_SETUP == FALSE)
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+ if (!p_acl_cb->is_le_link)
+#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);
+
+ BTM_SetLinkSuperTout (p_acl_cb->remote_addr, btm_cb.btm_def_link_super_tout);
+ }
+#endif
+ p_acl_cb->link_up_issued = TRUE;
+
+ /* If anyone cares, tell him database changed */
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ 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->features;
+
+
+ (*btm_cb.p_bl_changed_cb)(&evt_data);
+ }
+ btm_acl_update_busy_level (BTM_BLI_ACL_UP_EVT);
+#else
+ if (btm_cb.p_acl_changed_cb)
+ (*btm_cb.p_acl_changed_cb) (p_acl_cb->remote_addr,
+ p_acl_cb->remote_dc,
+ p_acl_cb->remote_name,
+ p_acl_cb->features,
+ TRUE);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** 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_DEBUG0 ("BTM_SetDefaultLinkSuperTout");
+ btm_cb.btm_def_link_super_tout = timeout;
+}
+
+/*******************************************************************************
+**
+** 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);
+
+ BTM_TRACE_DEBUG0 ("BTM_SetLinkSuperTout");
+ 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_RegForLstoEvt
+**
+** Description register for the HCI "Link Supervision Timeout Change" event
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_RegForLstoEvt (tBTM_LSTO_CBACK *p_cback)
+{
+ BTM_TRACE_DEBUG0 ("BTM_RegForLstoEvt");
+ btm_cb.p_lsto_cback = p_cback;
+}
+
+/*******************************************************************************
+**
+** Function btm_proc_lsto_evt
+**
+** Description process the HCI "Link Supervision Timeout Change" event
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_proc_lsto_evt(UINT16 handle, UINT16 timeout)
+{
+ UINT8 xx;
+
+ BTM_TRACE_DEBUG0 ("btm_proc_lsto_evt");
+ if (btm_cb.p_lsto_cback)
+ {
+ /* Look up the connection by handle and set the current mode */
+ xx = btm_handle_to_acl_index(handle);
+
+ /* don't assume that we can never get a bad hci_handle */
+ if (xx < MAX_L2CAP_LINKS)
+ {
+ (*btm_cb.p_lsto_cback)(btm_cb.acl_db[xx].remote_addr, timeout);
+ }
+ }
+}
+
+#if BTM_PWR_MGR_INCLUDED == FALSE
+/*******************************************************************************
+**
+** Function BTM_SetHoldMode
+**
+** Description This function is called to set a connection into hold mode.
+** A check is made if the connection is in sniff or park mode,
+** and if yes, the hold mode is ignored.
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetHoldMode (BD_ADDR remote_bda, UINT16 min_interval, UINT16 max_interval)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_DEBUG0 ("BTM_SetHoldMode");
+ /* First, check if hold mode is supported */
+ if (!HCI_HOLD_MODE_SUPPORTED(BTM_ReadLocalFeatures()))
+ return(BTM_MODE_UNSUPPORTED);
+
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ /* If the connection is in park or sniff mode, forget about holding it */
+ if (p->mode != BTM_ACL_MODE_NORMAL)
+ return(BTM_SUCCESS);
+
+ if (!btsnd_hcic_hold_mode (p->hci_handle, max_interval, min_interval))
+ return(BTM_NO_RESOURCES);
+
+ return(BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetSniffMode
+**
+** Description This function is called to set a connection into sniff mode.
+** A check is made if the connection is already in sniff or park
+** mode, and if yes, the sniff mode is ignored.
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetSniffMode (BD_ADDR remote_bda, UINT16 min_period, UINT16 max_period,
+ UINT16 attempt, UINT16 timeout)
+{
+ tACL_CONN *p;
+ BTM_TRACE_DEBUG0 ("BTM_SetSniffMode");
+ /* First, check if sniff mode is supported */
+ if (!HCI_SNIFF_MODE_SUPPORTED(BTM_ReadLocalFeatures()))
+ return(BTM_MODE_UNSUPPORTED);
+
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ /* If the connection is in park mode, forget about sniffing it */
+ if (p->mode != BTM_ACL_MODE_NORMAL)
+ return(BTM_WRONG_MODE);
+
+ if (!btsnd_hcic_sniff_mode (p->hci_handle, max_period,
+ min_period, attempt, timeout))
+ return(BTM_NO_RESOURCES);
+
+ return(BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function BTM_CancelSniffMode
+**
+** Description This function is called to put a connection out of sniff mode.
+** A check is made if the connection is already in sniff mode,
+** and if not, the cancel sniff mode is ignored.
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_CancelSniffMode (BD_ADDR remote_bda)
+{
+ tACL_CONN *p = btm_bda_to_acl(remote_bda);
+ BTM_TRACE_DEBUG0 ("BTM_CancelSniffMode ");
+ if (p == (tACL_CONN *)NULL)
+ return(BTM_UNKNOWN_ADDR);
+
+ /* If the connection is not in sniff mode, cannot cancel */
+ if (p->mode != BTM_ACL_MODE_SNIFF)
+ return(BTM_WRONG_MODE);
+
+ if (!btsnd_hcic_exit_sniff_mode (p->hci_handle))
+ return(BTM_NO_RESOURCES);
+
+ return(BTM_CMD_STARTED);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetParkMode
+**
+** Description This function is called to set a connection into park mode.
+** A check is made if the connection is already in sniff or park
+** mode, and if yes, the park mode is ignored.
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetParkMode (BD_ADDR remote_bda, UINT16 beacon_min_period, UINT16 beacon_max_period)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_DEBUG0 ("BTM_SetParkMode");
+ /* First, check if park mode is supported */
+ if (!HCI_PARK_MODE_SUPPORTED(BTM_ReadLocalFeatures()))
+ return(BTM_MODE_UNSUPPORTED);
+
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ /* If the connection is in sniff mode, forget about parking it */
+ if (p->mode != BTM_ACL_MODE_NORMAL)
+ return(BTM_WRONG_MODE);
+
+ /* no park mode if SCO exists -- CR#1982, 1.1 errata 1124
+ command status event should be returned /w error code 0x0C "Command Disallowed"
+ Let LM do this.
+ */
+ if (!btsnd_hcic_park_mode (p->hci_handle,
+ beacon_max_period, beacon_min_period))
+ return(BTM_NO_RESOURCES);
+
+ return(BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** Function BTM_CancelParkMode
+**
+** Description This function is called to put a connection out of park mode.
+** A check is made if the connection is already in park mode,
+** and if not, the cancel sniff mode is ignored.
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_CancelParkMode (BD_ADDR remote_bda)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_DEBUG0 ("BTM_CancelParkMode");
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ /* If the connection is not in park mode, cannot cancel */
+ if (p->mode != BTM_ACL_MODE_PARK)
+ return(BTM_WRONG_MODE);
+
+ if (!btsnd_hcic_exit_park_mode (p->hci_handle))
+ return(BTM_NO_RESOURCES);
+
+ return(BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+#endif /* BTM_PWR_MGR_INCLUDED == FALSE */
+
+
+/*******************************************************************************
+**
+** Function BTM_SetPacketTypes
+**
+** Description This function is set the packet types used for a specific
+** ACL connection,
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetPacketTypes (BD_ADDR remote_bda, UINT16 pkt_types)
+{
+ tACL_CONN *p;
+ BTM_TRACE_DEBUG0 ("BTM_SetPacketTypes");
+
+ if ((p = btm_bda_to_acl(remote_bda)) != NULL)
+ return(btm_set_packet_types (p, pkt_types));
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadPacketTypes
+**
+** Description This function is set the packet types used for a specific
+** ACL connection,
+**
+** Returns packet types supported for the connection, or 0 if no BD address
+**
+*******************************************************************************/
+UINT16 BTM_ReadPacketTypes (BD_ADDR remote_bda)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_DEBUG0 ("BTM_ReadPacketTypes");
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ return(p->pkt_types_mask);
+ }
+
+ /* If here, no BD Addr found */
+ return(0);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadAclMode
+**
+** 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
+**
+*******************************************************************************/
+#if BTM_PWR_MGR_INCLUDED == FALSE
+tBTM_STATUS BTM_ReadAclMode (BD_ADDR remote_bda, UINT8 *p_mode)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_API6 ("BTM_ReadAclMode: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ 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);
+ if (p != (tACL_CONN *)NULL)
+ {
+ *p_mode = p->mode;
+ return(BTM_SUCCESS);
+ }
+
+ /* If here, no BD Addr found */
+ return(BTM_UNKNOWN_ADDR);
+}
+#endif /* BTM_PWR_MGR_INCLUDED == FALSE */
+
+/*******************************************************************************
+**
+** Function BTM_ReadClockOffset
+**
+** Description This returns the clock offset for a specific
+** ACL connection.
+**
+** Input Param remote_bda - device address of desired ACL connection
+**
+** Returns clock-offset or 0 if unknown
+**
+*******************************************************************************/
+UINT16 BTM_ReadClockOffset (BD_ADDR remote_bda)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_API6 ("BTM_ReadClockOffset: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ remote_bda[0], remote_bda[1], remote_bda[2],
+ remote_bda[3], remote_bda[4], remote_bda[5]);
+
+ if ( (p = btm_bda_to_acl(remote_bda)) != NULL)
+ return(p->clock_offset);
+
+ /* If here, no BD Addr found */
+ return(0);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_API6 ("BTM_ReadClockOffset: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ 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);
+ 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)
+{
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ return(UINT16)btm_cb.num_acl;
+#else
+ tACL_CONN *p = &btm_cb.acl_db[0];
+ UINT16 xx, yy;
+ BTM_TRACE_DEBUG0 ("BTM_GetNumAclLinks");
+ for (xx = yy = 0; xx < MAX_L2CAP_LINKS; xx++, p++)
+ {
+ if (p->in_use)
+ yy++;
+ }
+
+ return(yy);
+#endif
+}
+
+/*******************************************************************************
+**
+** 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_DEBUG0 ("btm_get_acl_disc_reason_code");
+ 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)
+{
+ tACL_CONN *p;
+ BTM_TRACE_DEBUG0 ("BTM_GetHCIConnHandle");
+ p = btm_bda_to_acl(remote_bda);
+ if (p != (tACL_CONN *)NULL)
+ {
+ return(p->hci_handle);
+ }
+
+ /* If here, no BD Addr found */
+ return(0xFFFF);
+}
+
+#if BTM_PWR_MGR_INCLUDED == FALSE
+/*******************************************************************************
+**
+** 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 void
+**
+*******************************************************************************/
+void btm_process_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode, UINT16 interval)
+{
+ tACL_CONN *p;
+ UINT8 xx;
+ BTM_TRACE_DEBUG0 ("btm_process_mode_change");
+ if (hci_status != HCI_SUCCESS)
+ {
+ BTM_TRACE_WARNING1 ("BTM: HCI Mode Change Error Status: 0x%02x", hci_status);
+ }
+
+ /* Look up the connection by handle and set the current mode */
+ xx = btm_handle_to_acl_index(hci_handle);
+
+ /* don't assume that we can never get a bad hci_handle */
+ if (xx >= MAX_L2CAP_LINKS)
+ return;
+
+ p = &btm_cb.acl_db[xx];
+
+ /* If status is not success mode does not mean anything */
+ if (hci_status == HCI_SUCCESS)
+ p->mode = mode;
+
+ /* If mode change was because of an active role switch or change link key */
+ btm_cont_rswitch_or_chglinkkey(p, btm_find_dev(p->remote_addr), hci_status);
+}
+#endif /* BTM_PWR_MGR_INCLUDED == FALSE */
+
+/*******************************************************************************
+**
+** 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)
+{
+ UINT8 xx;
+ BTM_TRACE_DEBUG0 ("btm_process_clk_off_comp_evt");
+ /* Look up the connection by handle and set the current mode */
+ if ((xx = btm_handle_to_acl_index(hci_handle)) < MAX_L2CAP_LINKS)
+ btm_cb.acl_db[xx].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);
+ tBTM_ROLE_SWITCH_CMPL *p_data = &btm_cb.devcb.switch_role_ref_data;
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ tBTM_BL_ROLE_CHG_DATA evt;
+#endif
+#if BTM_DISC_DURING_RS == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec;
+#endif
+ BTM_TRACE_DEBUG0 ("btm_acl_role_changed");
+ /* 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)
+ {
+ /* Make sure there's not also a change link key going on before re-enabling */
+ if (p->change_key_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;
+ }
+ }
+ else /* Set the state and wait for change link key */
+ {
+ 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 (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ /* 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_DEBUG3("Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, rs_st:%d",
+ p_data->role, p_data->hci_status, p->switch_role_state);
+#endif
+
+#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_WARNING0("btm_acl_role_changed -> Issuing delayed HCI_Disconnect!!!");
+ btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER);
+ }
+ BTM_TRACE_ERROR2("tBTM_SEC_DEV:0x%x rs_disc_pending=%d", (UINT32)p_dev_rec, p_dev_rec->rs_disc_pending);
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+ }
+
+#endif
+
+}
+
+#if (RFCOMM_INCLUDED==TRUE)
+/*******************************************************************************
+**
+** Function BTM_AllocateSCN
+**
+** Description Look through the Server Channel Numbers for a free one.
+**
+** Returns Allocated SCN number or 0 if none.
+**
+*******************************************************************************/
+
+UINT8 BTM_AllocateSCN(void)
+{
+ UINT8 x;
+ BTM_TRACE_DEBUG0 ("BTM_AllocateSCN");
+
+ // stack reserves scn 1 for HFP, HSP we still do the correct way
+ for (x = 1; x < BTM_MAX_SCN; x++)
+ {
+ if (!btm_cb.btm_scn[x])
+ {
+ btm_cb.btm_scn[x] = TRUE;
+ return(x+1);
+ }
+ }
+
+ return(0); /* No free ports */
+}
+
+/*******************************************************************************
+**
+** Function BTM_TryAllocateSCN
+**
+** Description Try to allocate a fixed server channel
+**
+** Returns Returns TRUE if server channel was available
+**
+*******************************************************************************/
+
+BOOLEAN BTM_TryAllocateSCN(UINT8 scn)
+{
+ UINT8 x;
+
+ /* Make sure we don't exceed max port range.
+ * Stack reserves scn 1 for HFP, HSP we still do the correct way.
+ */
+ if ( (scn>=BTM_MAX_SCN) || (scn == 1) )
+ 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_DEBUG0 ("BTM_FreeSCN ");
+ if (scn <= BTM_MAX_SCN)
+ {
+ btm_cb.btm_scn[scn-1] = FALSE;
+ return(TRUE);
+ }
+ else
+ return(FALSE); /* Illegal SCN passed in */
+}
+
+#else
+
+/* Make dummy functions for the RPC to link against */
+UINT8 BTM_AllocateSCN(void)
+{
+ return(0);
+}
+
+BOOLEAN BTM_FreeSCN(UINT8 scn)
+{
+ return(FALSE);
+}
+
+#endif
+
+
+/*******************************************************************************
+**
+** Function btm_acl_timeout
+**
+** Description This function is called when a timer list entry expires.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_acl_timeout (TIMER_LIST_ENT *p_tle)
+{
+ UINT32 timer_type = p_tle->param;
+
+ BTM_TRACE_DEBUG0 ("btm_acl_timeout");
+ if (timer_type == TT_DEV_RLNKP)
+ {
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_rlinkp_cmpl_cb;
+ tBTM_LNK_POLICY_RESULTS lnkpol;
+
+ lnkpol.status = BTM_ERR_PROCESSING;
+ lnkpol.settings = 0;
+
+ btm_cb.devcb.p_rlinkp_cmpl_cb = NULL;
+
+ if (p_cb)
+ (*p_cb)(&lnkpol);
+ }
+}
+
+/*******************************************************************************
+**
+** 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_DEBUG0 ("btm_set_packet_types");
+ /* 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 */
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+ temp_pkt_types |= ((pkt_types & BTM_ACL_EXCEPTION_PKTS_MASK) |
+ (btm_cb.btm_acl_pkt_types_supported & BTM_ACL_EXCEPTION_PKTS_MASK));
+ }
+ else
+ {
+ temp_pkt_types &= (~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_DEBUG1 ("SetPacketType Mask -> 0x%04x", 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);
+ UINT16 pkt_types = 0;
+ UINT16 pkt_size = 0;
+ BTM_TRACE_DEBUG0 ("btm_get_max_packet_size");
+ if (p != NULL)
+ {
+ pkt_types = p->pkt_types_mask;
+ }
+ else
+ {
+ /* Special case for when info for the local device is requested */
+ if (memcmp (btm_cb.devcb.local_addr, 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;
+ }
+
+#ifdef BRCM_VS
+ /* Using HCI size 1017 instead of 1021 */
+ if ((pkt_size == HCI_EDR3_DH5_PACKET_SIZE)
+ && (btu_cb.hcit_acl_data_size == 1017))
+ pkt_size = 1017;
+#endif
+
+ 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);
+ BTM_TRACE_DEBUG0 ("BTM_ReadRemoteVersion");
+ 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 features string
+**
+*******************************************************************************/
+UINT8 *BTM_ReadRemoteFeatures (BD_ADDR addr)
+{
+ tACL_CONN *p = btm_bda_to_acl(addr);
+ BTM_TRACE_DEBUG0 ("BTM_ReadRemoteFeatures");
+ if (p == NULL)
+ {
+ return(NULL);
+ }
+
+ return(p->features);
+}
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+tBTM_STATUS BTM_RegBusyLevelNotif (tBTM_BL_CHANGE_CB *p_cb, UINT8 *p_level,
+ tBTM_BL_EVENT_MASK evt_mask)
+{
+ BTM_TRACE_DEBUG0 ("BTM_RegBusyLevelNotif");
+ 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);
+}
+#else
+/*******************************************************************************
+**
+** Function BTM_AclRegisterForChanges
+**
+** Returns This function is called to register a callback for when the
+** ACL database changes, i.e. new entry or entry deleted.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_AclRegisterForChanges (tBTM_ACL_DB_CHANGE_CB *p_cb)
+{
+ BTM_TRACE_DEBUG0 ("BTM_AclRegisterForChanges");
+ if (!p_cb)
+ btm_cb.p_acl_changed_cb = NULL;
+ else if (btm_cb.p_acl_changed_cb)
+ return(BTM_BUSY);
+ else
+ btm_cb.p_acl_changed_cb = p_cb;
+
+ return(BTM_SUCCESS);
+}
+#endif
+
+/*******************************************************************************
+**
+** 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 = &btm_cb.acl_db[0];
+
+ BTM_TRACE_API6 ("BTM_SetQoS: BdAddr: %02x%02x%02x%02x%02x%02x",
+ 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)) != NULL)
+ {
+ btu_start_timer (&btm_cb.devcb.qossu_timer, BTU_TTYPE_BTM_ACL, 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_DEBUG0 ("btm_qos_setup_complete");
+ 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;
+ 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_DEBUG1 ("BTM: p_flow->delay_variation: 0x%02x",
+ qossu.flow.delay_variation);
+ (*p_cb)(&qossu);
+ }
+}
+
+
+/*******************************************************************************
+**
+** 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, tBTM_CMPL_CB *p_cb)
+{
+ tACL_CONN *p;
+
+ BTM_TRACE_API6 ("BTM_ReadRSSI: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ 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_rssi_cmpl_cb)
+ return(BTM_BUSY);
+
+ p = btm_bda_to_acl(remote_bda);
+ 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);
+ 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_API6 ("BTM_ReadLinkQuality: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ 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);
+ 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, 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_API6 ("BTM_ReadTxPower: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ 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);
+ 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->is_le_link)
+ {
+ 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);
+}
+/*******************************************************************************
+**
+** 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 = &btm_cb.acl_db[0];
+ UINT16 index;
+ BTM_TRACE_DEBUG0 ("btm_read_tx_power_complete");
+ 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 */
+ for (index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++)
+ {
+ if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle))
+ {
+ memcpy (results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN);
+ break;
+ }
+ }
+ }
+#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_DEBUG2 ("BTM TX power Complete: tx_power %d, hci status 0x%02x",
+ 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 = &btm_cb.acl_db[0];
+ UINT16 index;
+ BTM_TRACE_DEBUG0 ("btm_read_rssi_complete");
+ 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_DEBUG2 ("BTM RSSI Complete: rssi %d, hci status 0x%02x",
+ results.rssi, results.hci_status);
+
+ /* Search through the list of active channels for the correct BD Addr */
+ for (index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++)
+ {
+ if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle))
+ {
+ memcpy (results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN);
+ break;
+ }
+ }
+ }
+ 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 = &btm_cb.acl_db[0];
+ UINT16 index;
+ BTM_TRACE_DEBUG0 ("btm_read_link_quality_complete");
+ btu_stop_timer (&btm_cb.devcb.rssi_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_DEBUG2 ("BTM Link Quality Complete: Link Quality %d, hci status 0x%02x",
+ results.link_quality, results.hci_status);
+
+ /* Search through the list of active channels for the correct BD Addr */
+ for (index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++)
+ {
+ if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle))
+ {
+ memcpy (results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN);
+ break;
+ }
+ }
+ }
+ 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)
+{
+ UINT16 hci_handle = BTM_GetHCIConnHandle(bd_addr);
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ BTM_TRACE_DEBUG0 ("btm_remove_acl");
+#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)
+ {
+ 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_DEBUG0 ("BTM_SetTraceLevel");
+ if (new_level != 0xFF)
+ btm_cb.trace_level = new_level;
+
+ return(btm_cb.trace_level);
+}
+
+/*******************************************************************************
+**
+** Function btm_cont_rswitch_or_chglinkkey
+**
+** Description This function is called to continue processing an active
+** role switch or change of link key procedure. It first
+** disables encryption if enabled and EPR is not supported
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_cont_rswitch_or_chglinkkey (tACL_CONN *p, tBTM_SEC_DEV_REC *p_dev_rec,
+ UINT8 hci_status)
+{
+ BOOLEAN sw_ok = TRUE;
+ BOOLEAN chlk_ok = TRUE;
+ BTM_TRACE_DEBUG0 ("btm_cont_rswitch_or_chglinkkey ");
+ /* 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 ||
+ p->change_key_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;
+
+ if (p->change_key_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE)
+ p->change_key_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;
+
+ if (p->change_key_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE)
+ chlk_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 (p->change_key_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE)
+ {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IN_PROGRESS;
+ chlk_ok = btsnd_hcic_change_link_key (p->hci_handle);
+ }
+ }
+
+ if (!sw_ok)
+ {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+ btm_acl_report_role_change(hci_status, p->remote_addr);
+ }
+
+ if (!chlk_ok)
+ {
+ p->change_key_state = BTM_ACL_SWKEY_STATE_IDLE;
+ if (btm_cb.devcb.p_chg_link_key_cb)
+ {
+ btm_cb.devcb.chg_link_key_ref_data.hci_status = hci_status;
+ (*btm_cb.devcb.p_chg_link_key_cb)(&btm_cb.devcb.chg_link_key_ref_data);
+ btm_cb.devcb.p_chg_link_key_cb = NULL;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_resubmit_page
+**
+** Description send pending page request
+**
+*******************************************************************************/
+void btm_acl_resubmit_page (void)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BT_HDR *p_buf;
+ UINT8 *pp;
+ BD_ADDR bda;
+ BTM_TRACE_DEBUG0 ("btm_acl_resubmit_page");
+ /* If there were other page request schedule can start the next one */
+ if ((p_buf = (BT_HDR *)GKI_dequeue (&btm_cb.page_queue)) != 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;
+}
+
+/*******************************************************************************
+**
+** 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_DEBUG0 ("btm_acl_reset_paging");
+ /* If we sent reset we are definitely not paging any more */
+ while ((p = (BT_HDR *)GKI_dequeue(&btm_cb.page_queue)) != NULL)
+ GKI_freebuf (p);
+
+ btm_cb.paging = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_set_discing
+**
+** Description set discing to the given value
+**
+*******************************************************************************/
+void btm_acl_set_discing (BOOLEAN discing)
+{
+ BTM_TRACE_DEBUG0 ("btm_acl_set_discing");
+ btm_cb.discing = discing;
+}
+
+/*******************************************************************************
+**
+** Function btm_acl_paging
+**
+** Description send a paging command or queue it in btm_cb
+**
+*******************************************************************************/
+void btm_acl_paging (BT_HDR *p, BD_ADDR bda)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_DEBUG4 ("btm_acl_paging discing:%d, paging:%d BDA: %06x%06x",
+ 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;
+ GKI_enqueue (&btm_cb.page_queue, p);
+ }
+ else
+ {
+ if (!BTM_ACL_IS_CONNECTED (bda))
+ {
+ BTM_TRACE_DEBUG2 ("connecting_bda: %06x%06x",
+ (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)
+ {
+ GKI_enqueue (&btm_cb.page_queue, p);
+ }
+ 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);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** 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 BTM_BUSY_LEVEL_CHANGE_INCLUDED == FALSE, or no one
+** needs the notification.
+**
+** Note: Function only used if BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE
+**
+*******************************************************************************/
+BOOLEAN btm_acl_notif_conn_collision (BD_ADDR bda)
+{
+#if (BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ tBTM_BL_EVENT_DATA evt_data;
+
+ /* Report possible collision to the upper layer. */
+ if (btm_cb.p_bl_changed_cb)
+ {
+ BTM_TRACE_DEBUG6 ("btm_acl_notif_conn_collision: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ 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;
+ (*btm_cb.p_bl_changed_cb)(&evt_data);
+ return TRUE;
+ }
+ else
+ return FALSE;
+#else
+ return FALSE;
+#endif
+}
+
+
+/*******************************************************************************
+**
+** 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->features))
+ *p_pkt_type &= ~(BTM_ACL_PKT_TYPES_MASK_DH3 +BTM_ACL_PKT_TYPES_MASK_DM3);
+
+ if (!HCI_5_SLOT_PACKETS_SUPPORTED(p->features))
+ *p_pkt_type &= ~(BTM_ACL_PKT_TYPES_MASK_DH5 + BTM_ACL_PKT_TYPES_MASK_DM5);
+
+ /* If HCI version > 2.0, then also check EDR packet types */
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+ /* 2 and 3 MPS support? */
+ if (!HCI_EDR_ACL_2MPS_SUPPORTED(p->features))
+ /* 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->features))
+ /* 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->features) || HCI_EDR_ACL_3MPS_SUPPORTED(p->features))
+ {
+ if (!HCI_3_SLOT_EDR_ACL_SUPPORTED(p->features))
+ /* 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->features))
+ /* 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);
+ }
+ }
+}
diff --git a/stack/btm/btm_ble.c b/stack/btm/btm_ble.c
new file mode 100644
index 0000000..74b5767
--- /dev/null
+++ b/stack/btm/btm_ble.c
@@ -0,0 +1,1900 @@
+/******************************************************************************
+ *
+ * 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 <string.h>
+
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_int.h"
+#include "btm_ble_api.h"
+#include "smp_api.h"
+
+#if SMP_INCLUDED == TRUE
+extern BOOLEAN AES_CMAC ( 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
+
+static void btm_ble_update_active_bgconn_scan_params(void);
+
+/*******************************************************************************/
+/* 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.
+**
+** Returns TRUE if added OK, else FALSE
+**
+*******************************************************************************/
+BOOLEAN BTM_SecAddBleDevice (BD_ADDR bd_addr, BD_NAME bd_name, tBT_DEVICE_TYPE dev_type,
+ tBLE_ADDR_TYPE addr_type)
+{
+#if BLE_INCLUDED == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ UINT8 i = 0;
+ tBTM_INQ_INFO *p_info=NULL;
+
+ BTM_TRACE_DEBUG1 ("BTM_SecAddBleDevice dev_type=0x%x", dev_type);
+ p_dev_rec = btm_find_dev (bd_addr);
+
+ if (!p_dev_rec)
+ {
+ BTM_TRACE_DEBUG0("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. */
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++)
+ {
+ if (!(btm_cb.sec_dev_rec[i].sec_flags & BTM_SEC_IN_USE))
+ {
+ BTM_TRACE_DEBUG1 ("allocate a new dev rec idx=0x%x ", i );
+ p_dev_rec = &btm_cb.sec_dev_rec[i];
+
+ /* 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);
+
+ /* 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_DEBUG1 ("hci_handl=0x%x ", p_dev_rec->hci_handle );
+ break;
+ }
+ }
+
+ if (!p_dev_rec)
+ return(FALSE);
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0("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, sizeof (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;
+ BTM_TRACE_DEBUG3 ("p_dev_rec->device_type =0x%x addr_type=0x%x sec_flags=0x%x",
+ dev_type, addr_type, p_dev_rec->sec_flags);
+
+ /* 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_DEBUG2 ("InqDb device_type =0x%x addr_type=0x%x",
+ p_info->results.device_type, p_info->results.ble_addr_type);
+ }
+
+#endif
+ return(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
+**
+*******************************************************************************/
+BOOLEAN BTM_SecAddBleKey (BD_ADDR bd_addr, tBTM_LE_KEY_VALUE *p_le_key, tBTM_LE_KEY_TYPE key_type)
+{
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BTM_TRACE_DEBUG0 ("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))
+ {
+ BTM_TRACE_WARNING3 ("BTM_SecAddLeKey() No BT Link Key, 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_DEBUG3 ("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);
+
+ if (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)
+ {
+ btm_sec_save_le_key (bd_addr, key_type, p_le_key, FALSE);
+ }
+
+#endif
+
+ return(TRUE);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+#if BLE_INCLUDED == TRUE
+ tBTM_DEVCB *p_devcb = &btm_cb.devcb;
+ BTM_TRACE_DEBUG0 ("BTM_BleLoadLocalKeys");
+ 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->er, p_key->er, sizeof(BT_OCTET16));
+ break;
+
+ default:
+ BTM_TRACE_ERROR1("unknow local key type: %d", key_type);
+ break;
+ }
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetDeviceEncRoot
+**
+** Description This function is called to read the local device encryption
+** root.
+**
+** Returns void
+** the local device ER is copied into er
+**
+*******************************************************************************/
+void BTM_GetDeviceEncRoot (BT_OCTET16 er)
+{
+ BTM_TRACE_DEBUG0 ("BTM_GetDeviceEncRoot");
+
+#if BLE_INCLUDED == TRUE
+ memcpy (er, btm_cb.devcb.er, BT_OCTET16_LEN);
+#endif
+}
+
+/*******************************************************************************
+**
+** 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_DEBUG0 ("BTM_GetDeviceIDRoot ");
+
+#if BLE_INCLUDED == TRUE
+ memcpy (irk, btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN);
+#endif
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+#if BLE_INCLUDED == TRUE
+ BTM_TRACE_DEBUG0 ("BTM_GetDeviceDHK");
+ memcpy (dhk, btm_cb.devcb.id_keys.dhk, BT_OCTET16_LEN);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadConnectionAddr
+**
+** Description This function is called to set the local device random address
+** .
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_ReadConnectionAddr (BD_ADDR conn_addr)
+{
+#if BLE_INCLUDED == TRUE
+ BTM_TRACE_DEBUG0 ("BTM_ReadConnectionAddr");
+ if (btm_cb.ble_ctr_cb.inq_var.own_addr_type == BLE_ADDR_PUBLIC)
+ {
+ BTM_GetLocalDeviceAddr(conn_addr);
+ }
+ else
+ {
+ memcpy (conn_addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr, BD_ADDR_LEN);
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** 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 (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_REPEATED_ATTEMPTS;
+ BTM_TRACE_DEBUG0 ("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 (BLE_INCLUDED == TRUE && 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;
+
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+ BTM_TRACE_DEBUG0 ("BTM_BlePasskeyReply");
+ SMP_PasskeyReply(bd_addr, res_smp, passkey);
+#endif
+}
+
+/*******************************************************************************
+**
+** 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 (BLE_INCLUDED == TRUE && 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_DEBUG0 ("BTM_BleOobDataReply");
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+ SMP_OobDataReply(bd_addr, res_smp, len, p_data);
+#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 (UINT16 scan_interval, UINT16 scan_window)
+{
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb;
+ BOOLEAN new_param = FALSE;
+
+ if (BTM_BLE_VALID_PRAM(scan_interval, BTM_BLE_SCAN_INT_MIN, BTM_BLE_SCAN_INT_MAX) &&
+ BTM_BLE_VALID_PRAM(scan_window, BTM_BLE_SCAN_WIN_MIN, BTM_BLE_SCAN_WIN_MAX))
+ {
+ btu_stop_timer(&p_ble_cb->scan_param_idle_timer);
+
+ 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)
+ btm_ble_update_active_bgconn_scan_params();
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("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)
+{
+#if BLE_INCLUDED == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+
+ BTM_TRACE_API4 ("BTM_BleSetPrefConnParams min: %u max: %u latency: %u \
+ tout: %u",
+ min_conn_int, max_conn_int, slave_latency, supervision_tout);
+
+ if (BTM_BLE_VALID_PRAM(min_conn_int, BTM_BLE_CONN_INT_MIN, BTM_BLE_CONN_INT_MAX) &&
+ BTM_BLE_VALID_PRAM(max_conn_int, BTM_BLE_CONN_INT_MIN, BTM_BLE_CONN_INT_MAX) &&
+ BTM_BLE_VALID_PRAM(supervision_tout, BTM_BLE_CONN_SUP_TOUT_MIN, BTM_BLE_CONN_SUP_TOUT_MAX) &&
+ slave_latency <= BTM_BLE_CONN_LATENCY_MAX)
+ {
+ 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.slave_latency = BTM_BLE_CONN_TIMEOUT_DEF;
+
+ }
+
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("Unknown Device, setting rejected");
+ }
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("Illegal Connection Parameters");
+ }
+#endif /* BLE_INCLUDED */
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+#if BLE_INCLUDED == TRUE
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (remote_bda);
+ tBTM_INQ_INFO *p_inq_info = BTM_InqDbRead(remote_bda);
+
+ *p_dev_type = BT_DEVICE_TYPE_BREDR;
+ *p_addr_type = BLE_ADDR_PUBLIC;
+
+ if (!p_dev_rec)
+ {
+ /* 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;
+ }
+ /* unknown device, assume BR/EDR */
+ }
+ 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;
+ }
+ *p_dev_type = p_dev_rec->device_type;
+ *p_addr_type = p_dev_rec->ble.ble_addr_type;
+
+ }
+
+ BTM_TRACE_DEBUG2 ("btm_find_dev_type - device_type = %d addr_type = %d", *p_dev_type , *p_addr_type);
+#endif
+
+ return;
+}
+
+
+/*******************************************************************************
+** Internal Functions
+*******************************************************************************/
+#if BLE_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function btm_ble_update_active_bgconn_scan_params
+**
+** Description This function is called to update the scan parameter if background
+** connection has been active.
+**
+*******************************************************************************/
+static void btm_ble_update_active_bgconn_scan_params(void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ tBTM_BLE_SEL_CBACK *p_select_cback;
+
+ /* if active , cancel and restart and apply the params */
+ if (p_cb->bg_conn_state == BLE_BG_CONN_ACTIVE)
+ {
+ if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO)
+ {
+ if (btm_ble_start_auto_conn(FALSE))
+ btm_ble_start_auto_conn(TRUE);
+ }
+ else if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE)
+ {
+ p_select_cback = p_cb->p_select_cback;
+ if (btm_ble_start_select_conn(FALSE, NULL))
+ btm_ble_start_select_conn(TRUE, p_select_cback);
+ }
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_check_link_type
+**
+** Description This function is to check the link type is BLE or BR/EDR.
+**
+** Returns TRUE if BLE link; FALSE if BR/EDR.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_check_link_type (BD_ADDR bd_addr)
+{
+ tACL_CONN *p;
+ BTM_TRACE_DEBUG0 ("btm_ble_check_link_type");
+ if ((p = btm_bda_to_acl(bd_addr)) != NULL)
+ return p->is_le_link;
+ else
+ 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_DEBUG0 ("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 */
+ }
+}
+
+
+#if (SMP_INCLUDED == TRUE)
+
+/*******************************************************************************
+**
+** Function btm_ble_get_enc_key_type
+**
+** Description This function is to increment local sign counter
+** Returns None
+**
+*******************************************************************************/
+void btm_ble_increment_sign_ctr(BD_ADDR bd_addr, BOOLEAN is_local )
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_DEBUG1 ("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_DEBUG3 ("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);
+ }
+}
+
+/*******************************************************************************
+**
+** 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.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_get_enc_key_type(BD_ADDR bd_addr, UINT8 *p_key_types)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_DEBUG0 ("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 TURE - 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_DEBUG0 ("btm_get_local_div");
+
+ BTM_TRACE_DEBUG6("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_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_DEBUG2 ("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;
+
+ BTM_TRACE_DEBUG2 ("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_DEBUG6("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)
+ {
+ switch (key_type)
+ {
+ case BTM_LE_KEY_PENC:
+ memcpy(p_rec->ble.keys.ltk, 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_LINK_KEY_KNOWN;
+ if (p_keys->penc_key.sec_level == SMP_SEC_AUTHENTICATED)
+ p_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+ else
+ p_rec->sec_flags &= ~BTM_SEC_LINK_KEY_AUTHED;
+ BTM_TRACE_DEBUG3("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:
+ memcpy(p_rec->ble.keys.irk, p_keys->pid_key, BT_OCTET16_LEN);
+ p_rec->ble.key_type |= BTM_LE_KEY_PID;
+ BTM_TRACE_DEBUG1("BTM_LE_KEY_PID key_type=0x%x save peer IRK", p_rec->ble.key_type);
+ break;
+
+ case BTM_LE_KEY_PCSRK:
+ memcpy(p_rec->ble.keys.csrk, 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_LINK_KEY_KNOWN;
+ if ( p_keys->pcsrk_key.sec_level== SMP_SEC_AUTHENTICATED)
+ p_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+ else
+ p_rec->sec_flags &= ~BTM_SEC_LINK_KEY_AUTHED;
+
+ BTM_TRACE_DEBUG4("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:
+ 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;
+
+ BTM_TRACE_DEBUG4("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 */
+ 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_DEBUG4("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;
+
+ default:
+ BTM_TRACE_WARNING1("btm_sec_save_le_key (Bad key_type 0x%02x)", key_type);
+ return;
+ }
+
+ BTM_TRACE_DEBUG3 ("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_WARNING3 ("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_DEBUG1 ("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_DEBUG1("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;
+}
+
+/*******************************************************************************
+**
+** 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, cur_sec_level;
+
+ BTM_TRACE_DEBUG1 ("btm_ble_link_sec_check auth_req =0x%x", auth_req);
+
+ if (p_dev_rec == NULL)
+ {
+ BTM_TRACE_ERROR0 ("btm_ble_link_sec_check received for unknown device");
+ return;
+ }
+
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING)
+ {
+ /* 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_BOND|BTM_LE_AUTH_REQ_MITM)) ||
+ (auth_req == (BTM_LE_AUTH_REQ_MITM)) )
+ {
+ req_sec_level = BTM_LE_SEC_AUTHENTICATED;
+ }
+
+ BTM_TRACE_DEBUG1 ("dev_rec sec_flags=0x%x", p_dev_rec->sec_flags);
+
+ /* currently encrpted */
+ if (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED)
+ {
+ if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)
+ 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)
+ {
+ if (cur_sec_level == BTM_LE_SEC_NONE)
+ {
+ *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_NONE;
+ }
+ else
+ {
+ /* To avoid re-encryption on an encrypted link for an equal condition encryption
+ if (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED)
+ *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_DISCARD;
+ else
+ */
+ *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_DEBUG3("cur_sec_level=%d req_sec_level=%d sec_req_act=%d",
+ cur_sec_level,
+ req_sec_level,
+ *p_sec_req_act);
+
+}
+
+/*******************************************************************************
+**
+** 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;
+ tBTM_BLE_SEC_ACT sec_act = *(tBTM_BLE_SEC_ACT *)p_ref_data ;
+ tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bd_addr);
+
+ BTM_TRACE_DEBUG2 ("btm_ble_set_encryption sec_act=0x%x role_master=%d", sec_act, p_rec->role_master);
+
+ if (p_rec == NULL)
+ {
+ return(BTM_WRONG_MODE);
+ }
+
+ 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)
+ {
+ /* start link layer encryption using the security info stored */
+ btm_ble_start_encrypt(bd_addr, FALSE, NULL);
+ p_rec->sec_state = BTM_SEC_STATE_ENCRYPTING;
+ cmd = BTM_CMD_STARTED;
+ 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 (SMP_Pair(bd_addr) == SMP_STARTED)
+ {
+ cmd = BTM_CMD_STARTED;
+ p_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+ }
+ break;
+
+ default:
+ cmd = BTM_SUCCESS;
+ break;
+ }
+ return cmd;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_ltk_request
+**
+** Description This function is called when encryption request is received
+** on a slave device.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+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_OCTET8 dummy_stk = {0};
+
+ BTM_TRACE_DEBUG0 ("btm_ble_ltk_request");
+
+ p_cb->ediv = ediv;
+
+ memcpy(p_cb->enc_rand, rand, BT_OCTET8_LEN);
+
+ if (!smp_proc_ltk_request(p_dev_rec->bd_addr))
+ btm_ble_ltk_request_reply(p_dev_rec->bd_addr, FALSE, dummy_stk);
+
+
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_start_encrypt
+**
+** Description This function is called to start LE encryption.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN btm_ble_start_encrypt(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk)
+{
+ tBTM_CB *p_cb = &btm_cb;
+ tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bda);
+ BT_OCTET8 dummy_rand = {0};
+
+ BTM_TRACE_DEBUG0 ("btm_ble_start_encrypt");
+
+ if (!p_rec ||
+ (p_rec && p_rec->sec_state == BTM_SEC_STATE_ENCRYPTING))
+ return FALSE;
+
+ if (p_rec->sec_state == BTM_SEC_STATE_IDLE)
+ p_rec->sec_state = BTM_SEC_STATE_ENCRYPTING;
+ p_cb->enc_handle = p_rec->hci_handle;
+
+ if (use_stk)
+ {
+ if (!btsnd_hcic_ble_start_enc(p_rec->hci_handle, dummy_rand, 0, stk))
+ return FALSE;
+ }
+ else
+ {
+ if (!btsnd_hcic_ble_start_enc(p_rec->hci_handle, p_rec->ble.keys.rand,
+ p_rec->ble.keys.ediv, p_rec->ble.keys.ltk))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_link_encrypted
+**
+** Description This function is called when LE link encrption status is changed.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_link_encrypted(BD_ADDR bd_addr, UINT8 encr_enable)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+
+ BTM_TRACE_DEBUG1 ("btm_ble_link_encrypted encr_enable=%d", encr_enable);
+
+ smp_link_encrypted(bd_addr, encr_enable);
+
+ if (p_dev_rec)
+ {
+ BTM_TRACE_DEBUG1(" 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;
+
+ if (p_dev_rec->p_callback)
+ {
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING)
+ {
+ if (encr_enable)
+ btm_sec_dev_rec_cback_event(p_dev_rec, BTM_SUCCESS);
+ else if (p_dev_rec->role_master)
+ btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING);
+ }
+ }
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ }
+}
+
+/*******************************************************************************
+** Function btm_enc_proc_ltk
+** Description send LTK reply when it's ready.
+*******************************************************************************/
+static void btm_enc_proc_ltk(tSMP_ENC *p)
+{
+ UINT8 i;
+ BTM_TRACE_DEBUG0 ("btm_enc_proc_ltk");
+ if (p && p->param_len == BT_OCTET16_LEN)
+ {
+ for (i = 0; i < (BT_OCTET16_LEN - btm_cb.key_size); i ++)
+ p->param_buf[BT_OCTET16_LEN - i - 1] = 0;
+ btsnd_hcic_ble_ltk_req_reply(btm_cb.enc_handle, p->param_buf);
+ }
+}
+
+/*******************************************************************************
+** Function btm_enc_proc_slave_y
+** Description calculate LTK when Y is ready
+*******************************************************************************/
+static void btm_enc_proc_slave_y(tSMP_ENC *p)
+{
+ UINT16 div, y;
+ UINT8 *pp = p->param_buf;
+ tBTM_CB *p_cb = &btm_cb;
+ tSMP_ENC output;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_DEBUG0 ("btm_enc_proc_slave_y");
+ if (p != NULL)
+ {
+ STREAM_TO_UINT16(y, pp);
+
+ div = p_cb->ediv ^ y;
+ p_dev_rec = btm_find_dev_by_handle (p_cb->enc_handle);
+
+ if ( p_dev_rec &&
+ p_dev_rec->ble.keys.div == div )
+ {
+ BTM_TRACE_DEBUG0 ("LTK request OK");
+ /* calculating LTK , LTK = E er(div) */
+ SMP_Encrypt(p_cb->devcb.er, BT_OCTET16_LEN, (UINT8 *)&div, 2, &output);
+ btm_enc_proc_ltk(&output);
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0 ("LTK request failed - send negative reply");
+ btsnd_hcic_ble_ltk_req_neg_reply(p_cb->enc_handle);
+ if (p_dev_rec)
+ btm_ble_link_encrypted(p_dev_rec->bd_addr, 0);
+
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_ltk_request_reply
+**
+** Description This function is called to send a LTK request reply on a slave
+** device.
+**
+** Returns void
+**
+*******************************************************************************/
+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;
+ tSMP_ENC output;
+
+ if (p_rec == NULL)
+ {
+ BTM_TRACE_ERROR0("btm_ble_ltk_request_reply received for unknown device");
+ return;
+ }
+
+ BTM_TRACE_DEBUG0 ("btm_ble_ltk_request_reply");
+ p_cb->enc_handle = p_rec->hci_handle;
+ p_cb->key_size = p_rec->ble.keys.key_size;
+
+ BTM_TRACE_ERROR1("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 */
+ {
+ /* generate Y= Encrypt(DHK, Rand) received from encrypt request */
+ SMP_Encrypt(p_cb->devcb.id_keys.dhk, BT_OCTET16_LEN, p_cb->enc_rand,
+ BT_OCTET8_LEN, &output);
+ btm_enc_proc_slave_y(&output);
+ }
+}
+
+/*******************************************************************************
+**
+** 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_DEBUG0 ("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
+ {
+ p_data->auth_req &= BTM_LE_AUTH_REQ_MASK;
+
+ BTM_TRACE_DEBUG2 ("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_DEBUG2 ("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_DEBUG0("Non bonding: No keys should be exchanged");
+ p_data->init_keys = 0;
+ p_data->resp_keys = 0;
+ }
+
+ BTM_TRACE_DEBUG1 ("btm_ble_io_capabilities_req 3: auth_req:%d", p_data->auth_req);
+ BTM_TRACE_DEBUG2 ("btm_ble_io_capabilities_req 4: i_keys=0x%x r_keys=0x%x",
+ p_data->init_keys,
+ p_data->resp_keys);
+
+ BTM_TRACE_DEBUG2 ("btm_ble_io_capabilities_req 5: p_data->io_cap = %d auth_req:%d",
+ 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;
+
+ BTM_TRACE_DEBUG3 ("btm_ble_io_capabilities_req 6: IO_CAP:%d oob_data:%d auth_req:%d",
+ p_data->io_cap, p_data->oob_data, p_data->auth_req);
+ }
+ return callback_rc;
+}
+
+/*****************************************************************************
+** Function btm_proc_smp_cback
+**
+** Description This function is the SMP callback handler.
+**
+******************************************************************************/
+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;
+
+ BTM_TRACE_DEBUG1 ("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_PASSKEY_REQ_EVT:
+ case SMP_PASSKEY_NOTIF_EVT:
+ case SMP_OOB_REQ_EVT:
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+ case SMP_SEC_REQUEST_EVT:
+ case SMP_COMPLT_EVT:
+ if (btm_cb.api.p_le_callback)
+ {
+ /* the callback function implementation may change the IO capability... */
+ BTM_TRACE_DEBUG1 ("btm_cb.api.p_le_callback=0x%x", btm_cb.api.p_le_callback );
+ (*btm_cb.api.p_le_callback) (event, bd_addr, (tBTM_LE_EVT_DATA *)p_data);
+ }
+ else
+ {
+ BTM_TRACE_ERROR0 ("btm_proc_smp_cback: btm_cb.api.p_le_callback ==NULL");
+ }
+
+ if (event == SMP_COMPLT_EVT)
+ {
+ BTM_TRACE_DEBUG2 ("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_DEBUG3 ("after update result=%d sec_level=0x%x sec_flags=0x%x",
+ res, p_data->cmplt.sec_level , p_dev_rec->sec_flags );
+
+ btm_sec_dev_rec_cback_event(p_dev_rec, res);
+
+ if (p_data->cmplt.is_pair_cancel && btm_cb.api.p_bond_cancel_cmpl_callback )
+ {
+ BTM_TRACE_DEBUG0 ("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)
+ {
+ BTM_TRACE_DEBUG0 ("Pairing failed - Remove ACL");
+ btm_remove_acl(bd_addr);
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0 ("Pairing failed - Not Removing ACL");
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ }
+ }
+#else
+ if (res != BTM_SUCCESS)
+ btm_remove_acl(bd_addr);
+#endif
+
+ BTM_TRACE_DEBUG3 ("btm_cb pairing_state=%x pairing_flags=%x pin_code_len=%x",
+ btm_cb.pairing_state,
+ btm_cb.pairing_flags,
+ btm_cb.pin_code_len );
+ BTM_TRACE_DEBUG6 ("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]);
+
+ memset (btm_cb.pairing_bda, 0xff, BD_ADDR_LEN);
+ btm_cb.pairing_flags = 0;
+ }
+ break;
+
+ default:
+ BTM_TRACE_DEBUG1 ("unknown event = %d", event);
+ break;
+
+
+ }
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("btm_proc_smp_cback received for unknown device");
+ }
+
+ return 0;
+}
+
+#endif /* SMP_INCLUDED */
+#endif /* BLE_INCLUDED */
+
+
+/*******************************************************************************
+**
+** 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.
+**
+*******************************************************************************/
+BOOLEAN BTM_BleDataSignature (BD_ADDR bd_addr, UINT8 *p_text, UINT16 len,
+ BLE_SIGNATURE signature)
+{
+ BOOLEAN ret = FALSE;
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bd_addr);
+ UINT8 *p_buf, *pp;
+
+ BT_OCTET16 er;
+ UINT16 div;
+ UINT8 temp[4]; /* for (r || DIV) r=1*/
+ UINT16 r=1;
+ UINT8 *p=temp, *p_mac = (UINT8 *)signature;
+ tSMP_ENC output;
+ BT_OCTET16 local_csrk;
+
+ BTM_TRACE_DEBUG0 ("BTM_BleDataSignature");
+ if (p_rec == NULL)
+ {
+ BTM_TRACE_ERROR0("data signing can not be done from unknow device");
+ }
+ else
+ {
+ if ((p_buf = (UINT8 *)GKI_getbuf((UINT16)(len + 4))) != NULL)
+ {
+ BTM_TRACE_DEBUG0("Start to generate Local CSRK");
+ /* prepare plain text */
+ if (p_text)
+ {
+ memcpy(p_buf, p_text, len);
+ pp = (p_buf + len);
+ }
+
+#if BTM_BLE_CONFORMANCE_TESTING == TRUE
+ if ( btm_cb.devcb.enable_test_local_sign_cntr)
+ {
+ BTM_TRACE_DEBUG1 ("Use Test local counter value from script counter_val=%d", btm_cb.devcb.test_local_sign_cntr);
+ UINT32_TO_STREAM(pp, btm_cb.devcb.test_local_sign_cntr);
+ }
+ else
+ {
+ UINT32_TO_STREAM(pp, p_rec->ble.keys.local_counter);
+ }
+#else
+ UINT32_TO_STREAM(pp, p_rec->ble.keys.local_counter);
+#endif
+ /* compute local csrk */
+ if (btm_get_local_div(bd_addr, &div))
+ {
+ BTM_TRACE_DEBUG1 ("compute_csrk div=%x", div);
+ BTM_GetDeviceEncRoot(er);
+
+ /* CSRK = d1(ER, DIV, 1) */
+ UINT16_TO_STREAM(p, div);
+ UINT16_TO_STREAM(p, r);
+
+ if (!SMP_Encrypt(er, BT_OCTET16_LEN, temp, 4, &output))
+ {
+ BTM_TRACE_ERROR0("Local CSRK generation failed ");
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0("local CSRK generation success");
+ memcpy((void *)local_csrk, output.param_buf, BT_OCTET16_LEN);
+
+
+#if BTM_BLE_CONFORMANCE_TESTING == TRUE
+ if (btm_cb.devcb.enable_test_local_sign_cntr)
+ {
+ UINT32_TO_STREAM(p_mac, btm_cb.devcb.test_local_sign_cntr);
+ }
+ else
+ {
+ UINT32_TO_STREAM(p_mac, p_rec->ble.keys.local_counter);
+ }
+#else
+ UINT32_TO_STREAM(p_mac, p_rec->ble.keys.local_counter);
+#endif
+
+ if ((ret = AES_CMAC(local_csrk, p_buf, (UINT16)(len + 4), BTM_CMAC_TLEN_SIZE, p_mac)) == TRUE)
+ {
+ btm_ble_increment_sign_ctr(bd_addr, TRUE);
+
+#if BTM_BLE_CONFORMANCE_TESTING == TRUE
+ if ( btm_cb.devcb.enable_test_mac_val)
+ {
+ BTM_TRACE_DEBUG0 ("Use MAC value from script");
+ memcpy(p_mac, btm_cb.devcb.test_mac, BTM_CMAC_TLEN_SIZE);
+ }
+#endif
+ }
+ BTM_TRACE_DEBUG1("BTM_BleDataSignature p_mac = %d", p_mac);
+ BTM_TRACE_DEBUG4("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_DEBUG4("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));
+
+ GKI_freebuf(p_buf);
+ }
+ }
+ }
+ }
+#endif /* BLE_INCLUDED */
+ 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;
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ 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_ERROR0("can not verify signature for unknown device");
+ }
+ else if (counter < p_rec->ble.keys.counter)
+ {
+ BTM_TRACE_ERROR0("signature received with out dated sign counter");
+ }
+ else if (p_orig == NULL)
+ {
+ BTM_TRACE_ERROR0("No signature to verify");
+ }
+ else
+ {
+ BTM_TRACE_DEBUG2 ("BTM_BleVerifySignature rcv_cnt=%d >= expected_cnt=%d", counter, p_rec->ble.keys.counter);
+
+ if (AES_CMAC(p_rec->ble.keys.csrk, 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;
+ }
+ }
+ }
+#endif /* BLE_INCLUDED */
+ return verified;
+}
+
+#if BLE_INCLUDED == TRUE
+/*******************************************************************************
+** 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
+**
+*******************************************************************************/
+static void btm_notify_new_key(UINT8 key_type)
+{
+ tBTM_BLE_LOCAL_KEYS *p_locak_keys = NULL;
+
+ BTM_TRACE_DEBUG1 ("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_DEBUG0 ("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_DEBUG0 ("BTM_BLE_KEY_TYPE_ER");
+ p_locak_keys = (tBTM_BLE_LOCAL_KEYS *)&btm_cb.devcb.er;
+ break;
+
+ default:
+ BTM_TRACE_ERROR1("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_DEBUG0 ("btm_ble_process_er2");
+
+ if (p &&p->opcode == HCI_BLE_RAND)
+ {
+ memcpy(&btm_cb.devcb.er[8], p->param_buf, BT_OCTET8_LEN);
+ btm_notify_new_key(BTM_BLE_KEY_TYPE_ER);
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("Generating ER2 exception.");
+ memset(&btm_cb.devcb.er, 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_DEBUG0 ("btm_ble_process_er");
+
+ if (p &&p->opcode == HCI_BLE_RAND)
+ {
+ memcpy(&btm_cb.devcb.er[0], p->param_buf, BT_OCTET8_LEN);
+
+ if (!btsnd_hcic_ble_rand((void *)btm_ble_process_er2))
+ {
+ memset(&btm_cb.devcb.er, 0, sizeof(BT_OCTET16));
+ BTM_TRACE_ERROR0("Generating ER2 failed.");
+ }
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("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_DEBUG0 ("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);
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("Generating IRK exception.");
+ }
+
+ /* proceed generate ER */
+ if (!btsnd_hcic_ble_rand((void *)btm_ble_process_er))
+ {
+ BTM_TRACE_ERROR0("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)
+{
+#if SMP_INCLUDED == TRUE
+ UINT8 btm_ble_irk_pt = 0x01;
+ tSMP_ENC output;
+
+ BTM_TRACE_DEBUG0 ("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_DEBUG0("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));
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+#if SMP_INCLUDED == TRUE
+ UINT8 btm_ble_dhk_pt = 0x03;
+ tSMP_ENC output;
+
+ BTM_TRACE_DEBUG0 ("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_DEBUG0("BLE IR generated.");
+ }
+ else
+ {
+ memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** 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_DEBUG0 ("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_ERROR0("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_DEBUG0 ("btm_ble_reset_id");
+
+ /* regenrate Identity Root*/
+ if (!btsnd_hcic_ble_rand((void *)btm_ble_process_ir))
+ {
+ BTM_TRACE_DEBUG0("Generating IR failed.");
+ }
+}
+
+#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_DEBUG1 ("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_DEBUG1 ("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_DEBUG2 ("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;
+}
+
+#endif /* BTM_BLE_CONFORMANCE_TESTING */
+
+
+#endif /* BLE_INCLUDED */
diff --git a/stack/btm/btm_ble_addr.c b/stack/btm/btm_ble_addr.c
new file mode 100644
index 0000000..04872f9
--- /dev/null
+++ b/stack/btm/btm_ble_addr.c
@@ -0,0 +1,383 @@
+/******************************************************************************
+ *
+ * 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 "bt_types.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_int.h"
+
+
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+ #include "smp_api.h"
+ #define BTM_BLE_PRIVATE_ADDR_INT 900 /* 15 minutes minimum for random address refreshing */
+
+/*******************************************************************************
+**
+** 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;
+ tBTM_BLE_INQ_CB *p_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+ BTM_TRACE_EVENT0 ("btm_gen_resolve_paddr_cmpl");
+ if (p && p->param_buf)
+ {
+ /* get the high bytes of the random address */
+ 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];
+ /* mask off the 1st MSB */
+ p_cb->private_addr[0] &= 0xfe;
+ /* set the 2nd MSB to be 1 */
+ p_cb->private_addr[0] |= 0x02;
+ /* set it to controller */
+ btsnd_hcic_ble_set_random_addr(p_cb->private_addr);
+
+ p_inq_cb->own_addr_type = BLE_ADDR_RANDOM;
+
+ /* start a periodical timer to refresh random addr */
+ btu_stop_timer(&p_cb->raddr_timer_ent);
+ btu_start_timer (&p_cb->raddr_timer_ent, BTU_TTYPE_BLE_RANDOM_ADDR,
+ BTM_BLE_PRIVATE_ADDR_INT);
+
+ /* if adv is active, restart adv with new private addr */
+ if (p_inq_cb->adv_mode == BTM_BLE_ADV_ENABLE)
+ {
+ btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE);
+
+ btsnd_hcic_ble_write_adv_params (p_inq_cb->adv_interval_min,
+ p_inq_cb->adv_interval_max,
+ p_inq_cb->evt_type,
+ p_inq_cb->own_addr_type,
+ p_inq_cb->direct_bda.type,
+ p_inq_cb->direct_bda.bda,
+ p_inq_cb->adv_chnl_map,
+ p_inq_cb->afp);
+ }
+ }
+ else
+ {
+ /* random address set failure */
+ BTM_TRACE_DEBUG0("set random address failed");
+ }
+}
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+static 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_EVENT0 ("btm_gen_resolve_paddr_low");
+ if (p && p->param_buf)
+ {
+ 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];
+
+ /* 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)
+{
+ BTM_TRACE_EVENT0 ("btm_gen_resolvable_private_addr");
+ /* generate 3B rand as BD LSB, SRK with it, get BD MSB */
+ if (!btsnd_hcic_ble_rand((void *)btm_gen_resolve_paddr_low))
+ 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;
+ UINT8 *pp;
+ BTM_TRACE_EVENT0 ("btm_gen_non_resolve_paddr_cmpl");
+ if (p && p->param_buf)
+ {
+ pp = p->param_buf;
+ STREAM_TO_BDADDR(p_cb->private_addr, pp);
+ /* mask off the 2 MSB */
+ p_cb->private_addr[0] &= 0xfc;
+ /* write to controller */
+ btsnd_hcic_ble_set_random_addr(p_cb->private_addr);
+
+ btm_cb.ble_ctr_cb.inq_var.own_addr_type = BLE_ADDR_RANDOM;
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0("btm_gen_non_resolvable_private_addr failed");
+ }
+}
+/*******************************************************************************
+**
+** 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 (void)
+{
+ BTM_TRACE_EVENT0 ("btm_gen_non_resolvable_private_addr");
+ if (!btsnd_hcic_ble_rand((void *)btm_gen_non_resolve_paddr_cmpl))
+ {
+ btm_gen_non_resolve_paddr_cmpl(NULL);
+ }
+}
+ #if SMP_INCLUDED == TRUE
+/*******************************************************************************
+** Utility functions for Random address resolving
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function btm_ble_resolve_address_cmpl
+**
+** Description This function sends the random address resolving complete
+** callback.
+**
+** Returns None.
+**
+*******************************************************************************/
+static void btm_ble_resolve_address_cmpl(void)
+{
+ tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+
+ BTM_TRACE_EVENT0 ("btm_ble_resolve_address_cmpl");
+ if (p_mgnt_cb->index < BTM_SEC_MAX_DEVICE_RECORDS)
+ p_dev_rec = &btm_cb.sec_dev_rec[p_mgnt_cb->index];
+
+ p_mgnt_cb->busy = FALSE;
+
+ (* p_mgnt_cb->p_resolve_cback)(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_EVENT0 ("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 && p->param_buf)
+ {
+ if (!memcmp(p->param_buf, &comp[0], 3))
+ {
+ /* match is found */
+ BTM_TRACE_EVENT0 ("match is found");
+ btm_ble_resolve_address_cmpl();
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+/*******************************************************************************
+**
+** 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(UINT16 rec_index)
+{
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ UINT8 rand[3];
+ tSMP_ENC output;
+
+ /* use the 3 MSB of bd address as prand */
+ 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_EVENT1("btm_ble_match_random_bda rec_index = %d", rec_index);
+
+ if (rec_index < BTM_SEC_MAX_DEVICE_RECORDS)
+ {
+ p_dev_rec = &btm_cb.sec_dev_rec[rec_index];
+
+ BTM_TRACE_ERROR2("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;
+ }
+ }
+ else /* no match found */
+ {
+ btm_ble_resolve_address_cmpl();
+ return TRUE;
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+ tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+
+ BTM_TRACE_EVENT0 ("btm_ble_resolve_random_addr");
+ if ( !p_mgnt_cb->busy)
+ {
+ p_mgnt_cb->p = p;
+ p_mgnt_cb->busy = TRUE;
+ p_mgnt_cb->index = 0;
+ 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 */
+ while (TRUE)
+ {
+ if (btm_ble_match_random_bda(p_mgnt_cb->index++))
+ {
+ // match found or went through the list
+ break;
+ }
+ }
+ }
+ else
+ (*p_cback)(NULL, p);
+}
+ #endif
+/*******************************************************************************
+** address mapping between pseudo address and real connection address
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function btm_ble_map_bda_to_conn_bda
+**
+** Description This function map a BD address to the real connection address
+** and return the connection address type.
+*******************************************************************************/
+tBLE_ADDR_TYPE btm_ble_map_bda_to_conn_bda(BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+ BTM_TRACE_EVENT0 ("btm_ble_map_bda_to_conn_bda");
+ if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL &&
+ p_dev_rec->device_type == BT_DEVICE_TYPE_BLE)
+ {
+ if (p_dev_rec->ble.ble_addr_type != BLE_ADDR_PUBLIC)
+ {
+ memcpy(bd_addr, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
+ }
+ return p_dev_rec->ble.ble_addr_type;
+ }
+ else
+ return BLE_ADDR_PUBLIC;
+}
+/*******************************************************************************
+**
+** Function btm_ble_map_bda_to_pseudo_bda
+**
+** Description This function map a BD address to a pseudo address when the
+** address given is a random address.
+**
+*******************************************************************************/
+void btm_ble_map_bda_to_pseudo_bda(BD_ADDR bd_addr)
+{
+ BTM_TRACE_EVENT0 ("btm_ble_map_bda_to_pseudo_bda");
+}
+#endif
+
+
diff --git a/stack/btm/btm_ble_bgconn.c b/stack/btm/btm_ble_bgconn.c
new file mode 100644
index 0000000..aa002e8
--- /dev/null
+++ b/stack/btm/btm_ble_bgconn.c
@@ -0,0 +1,616 @@
+/******************************************************************************
+ *
+ * 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 "bt_types.h"
+#include "btu.h"
+#include "btm_int.h"
+#include "l2c_int.h"
+#include "hcimsgs.h"
+
+#ifndef BTM_BLE_SCAN_PARAM_TOUT
+#define BTM_BLE_SCAN_PARAM_TOUT 50 /* 50 seconds */
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function btm_update_scanner_filter_policy
+**
+** Description This function update the filter policy of scnner or advertiser.
+*******************************************************************************/
+void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy)
+{
+ tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
+ BTM_TRACE_EVENT0 ("btm_update_scanner_filter_policy");
+ btm_cb.ble_ctr_cb.inq_var.sfp = scan_policy;
+
+ btsnd_hcic_ble_set_scan_params ((UINT8)((p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE) ? BTM_BLE_SCAN_MODE_ACTI: p_inq->scan_type),
+ (UINT16)(!p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval),
+ (UINT16)(!p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window),
+ BLE_ADDR_PUBLIC,
+ scan_policy);
+}
+/*******************************************************************************
+**
+** Function btm_update_adv_filter_policy
+**
+** Description This function update the filter policy of scnner or advertiser.
+*******************************************************************************/
+void btm_update_adv_filter_policy(tBTM_BLE_AFP adv_policy)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ BTM_TRACE_EVENT0 ("btm_update_adv_filter_policy");
+ p_cb->afp = adv_policy;
+}
+/*******************************************************************************
+**
+** Function btm_update_dev_to_white_list
+**
+** Description This function adds a device into white list.
+*******************************************************************************/
+BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type)
+{
+ /* look up the sec device record, and find the address */
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BD_ADDR dummy_bda = {0};
+ BOOLEAN started = FALSE, suspend = FALSE;
+
+ if (btm_cb.btm_inq_vars.inq_active)
+ {
+ suspend = TRUE;
+ btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+ }
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL &&
+ p_dev_rec->device_type == BT_DEVICE_TYPE_BLE)
+ {
+ BTM_TRACE_DEBUG0("btm_update_dev_to_white_list 1");
+
+ if ((to_add && p_cb->num_empty_filter == 0) ||
+ (!to_add && p_cb->num_empty_filter == p_cb->max_filter_entries))
+ {
+ BTM_TRACE_ERROR1("num_entry available in controller: %d", p_cb->num_empty_filter);
+ return started;
+ }
+
+
+ if ( p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC)
+ {
+ if (to_add)
+ started = btsnd_hcic_ble_add_white_list (BLE_ADDR_PUBLIC, bd_addr);
+ else
+ started = btsnd_hcic_ble_remove_from_white_list (BLE_ADDR_PUBLIC, bd_addr);
+ }
+ else
+ {
+ if (BLE_ADDR_IS_STATIC(bd_addr))
+ {
+ if (to_add)
+ started = btsnd_hcic_ble_add_white_list (BLE_ADDR_RANDOM, bd_addr);
+ else
+ started = btsnd_hcic_ble_remove_from_white_list (BLE_ADDR_RANDOM, bd_addr);
+
+ }
+ if (memcmp(p_dev_rec->ble.reconn_addr, dummy_bda, BD_ADDR_LEN) != 0)
+ {
+ if (to_add)
+ started = btsnd_hcic_ble_add_white_list (BLE_ADDR_RANDOM, p_dev_rec->ble.reconn_addr);
+ else
+ started = btsnd_hcic_ble_remove_from_white_list (BLE_ADDR_RANDOM, p_dev_rec->ble.reconn_addr);
+ }
+ }
+ }
+ /* if not a known device, shall we add it? */
+ else
+ {
+ 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);
+ }
+
+ if (suspend)
+ {
+ btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE);
+ }
+
+ return started;
+}
+/*******************************************************************************
+**
+** Function btm_ble_clear_white_list
+**
+** Description This function clears the white list.
+*******************************************************************************/
+void btm_ble_clear_white_list (void)
+{
+ BTM_TRACE_EVENT0 ("btm_ble_clear_white_list");
+ btsnd_hcic_ble_clear_white_list();
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_clear_white_list_complete
+**
+** Description This function clears the white list complete.
+*******************************************************************************/
+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;
+ BTM_TRACE_EVENT0 ("btm_ble_clear_white_list_complete");
+ STREAM_TO_UINT8 (status, p_data);
+
+ if (status == HCI_SUCCESS)
+ p_cb->num_empty_filter = p_cb->max_filter_entries;
+
+}
+/*******************************************************************************
+**
+** Function btm_ble_add_2_white_list_complete
+**
+** Description This function read the current white list size.
+*******************************************************************************/
+void btm_ble_add_2_white_list_complete(UINT8 *p, UINT16 evt_len)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ BTM_TRACE_EVENT0 ("btm_ble_add_2_white_list_complete");
+
+ if (*p == HCI_SUCCESS)
+ {
+ p_cb->num_empty_filter --;
+ }
+}
+/*******************************************************************************
+**
+** Function btm_ble_add_2_white_list_complete
+**
+** Description This function read the current white list size.
+*******************************************************************************/
+void btm_ble_remove_from_white_list_complete(UINT8 *p, UINT16 evt_len)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ BTM_TRACE_EVENT0 ("btm_ble_remove_from_white_list_complete");
+ if (*p == HCI_SUCCESS)
+ {
+ p_cb->num_empty_filter ++;
+ }
+}
+/*******************************************************************************
+**
+** Function btm_ble_find_dev_in_whitelist
+**
+** Description This function check if the device is in the white list
+*******************************************************************************/
+BOOLEAN btm_ble_find_dev_in_whitelist(BD_ADDR bd_addr)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ UINT8 i;
+
+ BTM_TRACE_EVENT0 ("btm_ble_find_dev_in_whitelist");
+
+ /* empty wl */
+ if (p_cb->num_empty_filter == p_cb->max_filter_entries)
+ {
+ BTM_TRACE_DEBUG0("white list empty");
+ return FALSE;
+ }
+
+ for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && i < p_cb->max_filter_entries; i ++)
+ {
+ if (memcmp(p_cb->bg_conn_dev_list[i], bd_addr, BD_ADDR_LEN) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+/*******************************************************************************
+**
+** Function btm_ble_count_unconn_dev_in_whitelist
+**
+** Description This function check the number of unconnected device in white list.
+*******************************************************************************/
+UINT8 btm_ble_count_unconn_dev_in_whitelist(void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ UINT8 count = 0, i;
+ BD_ADDR dummy_bda ={0};
+
+ BTM_TRACE_EVENT0 ("btm_ble_find_dev_in_whitelist");
+
+ for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && i < p_cb->max_filter_entries; i ++)
+ {
+ if (memcmp(p_cb->bg_conn_dev_list[i], dummy_bda, BD_ADDR_LEN) != 0 &&
+ !BTM_IsAclConnectionUp(p_cb->bg_conn_dev_list[i]))
+ {
+ count ++;
+ }
+ }
+ return count;
+}
+/*******************************************************************************
+**
+** Function btm_update_bg_conn_list
+**
+** Description This function update the local background connection device list.
+*******************************************************************************/
+BOOLEAN btm_update_bg_conn_list(BOOLEAN to_add, BD_ADDR bd_addr)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ UINT8 i;
+ BD_ADDR dummy_bda = {0};
+ BTM_TRACE_EVENT0 ("btm_update_bg_conn_list");
+ if ((to_add && (p_cb->bg_conn_dev_num == BTM_BLE_MAX_BG_CONN_DEV_NUM || p_cb->num_empty_filter == 0)) ||
+ (!to_add && p_cb->num_empty_filter == p_cb->max_filter_entries))
+ {
+ BTM_TRACE_DEBUG1("num_empty_filter = %d", p_cb->num_empty_filter);
+ return FALSE;
+ }
+
+ for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && i < p_cb->max_filter_entries; i ++)
+ {
+ /* to add */
+ if (memcmp(p_cb->bg_conn_dev_list[i], dummy_bda, BD_ADDR_LEN) == 0 && to_add)
+ {
+ memcpy(p_cb->bg_conn_dev_list[i], bd_addr, BD_ADDR_LEN);
+ p_cb->bg_conn_dev_num ++;
+ return TRUE;
+ }
+ /* to remove */
+ if (!to_add && memcmp(p_cb->bg_conn_dev_list[i], bd_addr, BD_ADDR_LEN) == 0)
+ {
+ memset(p_cb->bg_conn_dev_list[i], 0, BD_ADDR_LEN);
+ p_cb->bg_conn_dev_num --;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+/*******************************************************************************
+**
+** Function btm_write_bg_conn_wl
+**
+** Description This function write background connection device list into
+** controller.
+*******************************************************************************/
+void btm_write_bg_conn_wl(void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ UINT8 i;
+ BTM_TRACE_EVENT0 ("btm_write_bg_conn_wl");
+ btm_ble_clear_white_list();
+
+ for (i = 0; i < p_cb->bg_conn_dev_num; i ++)
+ {
+ if (!btm_update_dev_to_white_list(TRUE, p_cb->bg_conn_dev_list[i], BLE_ADDR_PUBLIC))
+ break;
+ }
+ return;
+}
+/*******************************************************************************
+**
+** 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, scan_win;
+
+ scan_int = (p_cb->scan_int == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_CONN_EST_SCAN_INT : p_cb->scan_int;
+ scan_win = (p_cb->scan_win == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_CONN_EST_SCAN_WIND : p_cb->scan_win;
+
+ if (start)
+ {
+ if (!l2cb.is_ble_connecting &&
+ btm_ble_count_unconn_dev_in_whitelist() > 0)
+ {
+ if (p_cb->bg_conn_state != BLE_BG_CONN_ACTIVE && p_cb->bg_conn_dev_num > 0)
+ {
+ if (!btsnd_hcic_ble_create_ll_conn (scan_int, /* UINT16 scan_int */
+ scan_win, /* UINT16 scan_win */
+ 0x01, /* UINT8 white_list */
+ BLE_ADDR_PUBLIC, /* UINT8 addr_type_peer */
+ dummy_bda, /* BD_ADDR bda_peer */
+ BLE_ADDR_PUBLIC, /* 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;
+ }
+ else
+ {
+ p_cb->bg_conn_state = BLE_BG_CONN_ACTIVE;
+ }
+ }
+ }
+ else
+ exec = FALSE;
+ }
+ else
+ {
+ if (p_cb->bg_conn_state == BLE_BG_CONN_ACTIVE)
+ {
+ if (!btsnd_hcic_ble_create_conn_cancel())
+ exec = FALSE;
+ else
+ p_cb->bg_conn_state = BLE_BG_CONN_IDLE;
+ }
+ }
+ 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 connectino 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;
+ UINT16 scan_int, scan_win;
+
+ BTM_TRACE_EVENT0 ("btm_ble_start_select_conn");
+
+ scan_int = (p_cb->scan_int == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_CONN_EST_SCAN_INT : p_cb->scan_int;
+ scan_win = (p_cb->scan_win == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_CONN_EST_SCAN_WIND : p_cb->scan_win;
+
+ if (start)
+ {
+ if (!btm_cb.btm_inq_vars.inq_active)
+ {
+ btm_cb.ble_ctr_cb.p_select_cback = p_select_cback;
+
+ btm_update_scanner_filter_policy(SP_ADV_WL);
+
+ if (!btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_PASS, /* use passive scan by default */
+ scan_int, /* scan interval */
+ scan_win, /* scan window */
+ BLE_ADDR_PUBLIC, /* own device, DUMO always use public */
+ SP_ADV_WL) /* process advertising packets only from devices in the White List */
+ )
+ return FALSE;
+
+ if (p_cb->inq_var.adv_mode == BTM_BLE_ADV_ENABLE)
+ {
+ BTM_TRACE_ERROR0("peripheral device cannot initiate a selective connection");
+ return FALSE;
+ }
+ else if (p_cb->bg_conn_dev_num > 0 && btm_ble_count_unconn_dev_in_whitelist() > 0 )
+ {
+
+ if (!btsnd_hcic_ble_set_scan_enable(TRUE, TRUE)) /* duplicate filtering enabled */
+ return FALSE;
+
+ /* mark up inquiry status flag */
+ btm_cb.btm_inq_vars.inq_active = TRUE;
+ btm_cb.ble_ctr_cb.inq_var.proc_mode = BTM_BLE_SELECT_SCAN;
+
+ p_cb->bg_conn_state = BLE_BG_CONN_ACTIVE;
+
+ }
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("scan active, can not start selective connection procedure");
+ return FALSE;
+ }
+ }
+ else /* disable selective connection mode */
+ {
+ p_cb->p_select_cback = NULL;
+ btm_cb.btm_inq_vars.inq_active = FALSE;
+ btm_cb.ble_ctr_cb.inq_var.proc_mode = BTM_BLE_INQUIRY_NONE;
+
+ btm_update_scanner_filter_policy(SP_ADV_ALL);
+
+ /* stop scanning */
+ if (p_cb->bg_conn_dev_num > 0)
+ {
+ if (!btsnd_hcic_ble_set_scan_enable(FALSE, TRUE)) /* duplicate filtering enabled */
+ return FALSE;
+ }
+ }
+ 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 connectino procedure is started.
+**
+*******************************************************************************/
+void btm_ble_initiate_select_conn(BD_ADDR bda)
+{
+ UINT8 addr_type;
+ BTM_TRACE_EVENT0 ("btm_ble_initiate_select_conn");
+ addr_type = btm_ble_map_bda_to_conn_bda(bda);
+
+ /* use direct connection procedure to initiate connection */
+ if (!L2CA_ConnectFixedChnl(L2CAP_ATT_CID, bda))
+ {
+ BTM_TRACE_ERROR0("btm_ble_initiate_select_conn failed");
+ }
+}
+/*******************************************************************************
+**
+** Function btm_ble_suspend_bg_sele_conn
+**
+** Description This function is to suspend an active background connection
+** procedure.
+**
+** Parameters none.
+**
+** Returns none.
+**
+*******************************************************************************/
+void btm_ble_suspend_bg_sele_conn(void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ BTM_TRACE_EVENT0 ("btm_ble_suspend_bg_sele_conn");
+
+ if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE)
+ {
+ p_cb->bg_conn_state = BLE_BG_CONN_SUSPEND;
+ btm_ble_start_select_conn(FALSE, NULL);
+ }
+}
+/*******************************************************************************
+**
+** Function btm_ble_suspend_bg_conn
+**
+** Description This function is to suspend an active background connection
+** procedure.
+**
+** Parameters none.
+**
+** Returns none.
+**
+*******************************************************************************/
+void btm_ble_suspend_bg_conn(void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ BTM_TRACE_EVENT0 ("btm_ble_suspend_bg_conn");
+
+ if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO)
+ {
+ if (btm_ble_start_auto_conn(FALSE))
+ p_cb->bg_conn_state = BLE_BG_CONN_SUSPEND;
+ }
+}
+/*******************************************************************************
+**
+** Function btm_ble_scan_param_idle
+**
+** Description This function is to process the scan parameter idle timeout
+** timeout.
+********************************************************************************/
+void btm_ble_scan_param_idle(void)
+{
+ BTM_BleSetConnScanParams(BTM_BLE_CONN_EST_SCAN_INT_LO, BTM_BLE_CONN_EST_SCAN_WIND_LO);
+}
+/*******************************************************************************
+**
+** 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(tBTM_BLE_SEL_CBACK *p_sele_callback, BOOLEAN def_param)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ BOOLEAN ret = FALSE;
+
+ if (p_cb->bg_conn_state != BLE_BG_CONN_ACTIVE )
+ {
+ if (def_param)
+ {
+ p_cb->scan_int = BTM_BLE_CONN_PARAM_UNDEF;
+ p_cb->scan_win = BTM_BLE_CONN_PARAM_UNDEF;
+
+ /* start scan param idle timer */
+ btu_start_timer(&p_cb->scan_param_idle_timer,
+ BTU_TTYPE_BLE_SCAN_PARAM_IDLE,
+ BTM_BLE_SCAN_PARAM_TOUT);
+ }
+
+ 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)
+ {
+ /* terminate selective connection mode if all devices are connected */
+ if (btm_ble_count_unconn_dev_in_whitelist() == 0)
+ {
+ btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_DISABLE);
+ btm_cb.ble_ctr_cb.inq_var.proc_mode = BTM_BLE_INQUIRY_NONE;
+ btm_cb.btm_inq_vars.inq_active = FALSE;
+ }
+ else if (!btm_cb.btm_inq_vars.inq_active)
+ btm_ble_start_select_conn(TRUE, btm_cb.ble_ctr_cb.p_select_cback);
+ }
+
+ if (ret)
+ p_cb->bg_conn_state = BLE_BG_CONN_ACTIVE;
+
+ }
+
+ return ret;
+}
+/*******************************************************************************
+**
+** Function btm_ble_update_bg_state
+**
+** Description This function is to update the bg connection status.
+**
+** Parameters none.
+**
+** Returns none.
+**
+*******************************************************************************/
+void btm_ble_update_bg_state(void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+
+ if (!l2cb.is_ble_connecting && (p_cb->bg_conn_state != BLE_BG_CONN_SUSPEND))
+ p_cb->bg_conn_state = BLE_BG_CONN_IDLE;
+
+}
+
+#endif
+
diff --git a/stack/btm/btm_ble_gap.c b/stack/btm/btm_ble_gap.c
new file mode 100644
index 0000000..b9e17c0
--- /dev/null
+++ b/stack/btm/btm_ble_gap.c
@@ -0,0 +1,2084 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2008-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 GAP.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "bt_types.h"
+#include "btu.h"
+#include "btm_int.h"
+#include "hcimsgs.h"
+#if (GAP_INCLUDED == TRUE)
+#include "gap_api.h"
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+#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 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_RESOLVE_BDA(x) ((x[0] & BLE_RESOLVE_ADDR_MASK) == BLE_RESOLVE_ADDR_MSB)
+
+#define BTM_EXT_BLE_RMT_NAME_TIMEOUT 30
+static tBLE_BD_ADDR le_bda_any ={BLE_ADDR_PUBLIC, {0x00,0x00,0x00,0x00,0x00,0x00}};
+
+
+#define BTM_BLE_VALID_CONN_DIRECT(x) (memcmp(&le_bda_any, x, sizeof(tBLE_BD_ADDR)) != 0)
+
+/*******************************************************************************
+** 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);
+static UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst, tBTM_BLE_ADV_DATA *p_data);
+
+
+
+
+
+
+
+
+/*******************************************************************************
+**
+** Function BTM_BleReset
+**
+** Description This function is called to reset ULP controller.
+**
+** Parameters None.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleReset(void)
+{
+ btsnd_hcic_ble_reset();
+}
+
+/*******************************************************************************
+**
+** 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, UINT8 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_NO_RESOURCES;
+
+ BTM_TRACE_EVENT0 ("BTM_BleObserve ");
+
+ if (start)
+ {
+ if (p_inq->proc_mode != BTM_BLE_INQUIRY_NONE)
+ return BTM_BUSY;
+
+ btm_cb.btm_inq_vars.p_inq_results_cb = p_results_cb;
+ btm_cb.btm_inq_vars.p_inq_cmpl_cb = p_cmpl_cb;
+
+ /* allow config scanning type */
+ if (btsnd_hcic_ble_set_scan_params ((UINT8)((p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE) ? BTM_BLE_SCAN_MODE_ACTI: p_inq->scan_type),
+ (UINT16)(!p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval),
+ (UINT16)(!p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window),
+ BLE_ADDR_PUBLIC,
+ BTM_BLE_DEFAULT_SFP)) /* assume observe always not using white list */
+ {
+ /* start scan, disable duplicate filtering */
+ if (btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE))
+ {
+ status = BTM_SUCCESS;
+ p_inq->proc_mode = BTM_BLE_OBSERVE;
+ btm_cb.btm_inq_vars.inq_active = TRUE;
+
+ if (duration != 0)
+ {
+ /* start inquiry timer */
+ btu_start_timer (&p_inq->inq_timer_ent, BTU_TTYPE_BLE_INQUIRY, duration);
+ }
+ }
+ }
+ }
+ else if (p_inq->proc_mode == BTM_BLE_OBSERVE)
+ {
+ btm_ble_stop_scan();
+ }
+
+ 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_STATUS status = BTM_NO_RESOURCES;
+ 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;
+
+#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 && p_cb->adv_mode == BTM_BLE_ADV_DISABLE)
+ {
+ /* 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_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;
+
+ if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE))
+ {
+ p_cb->adv_mode = BTM_BLE_ADV_ENABLE;
+
+ status = BTM_SUCCESS;
+ }
+ }
+ else if (!start && p_cb->adv_mode == BTM_BLE_ADV_ENABLE)
+ {
+ if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE))
+ {
+ p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
+
+ status = BTM_SUCCESS;
+ }
+ }
+ else
+ {
+ status = BTM_WRONG_MODE;
+ BTM_TRACE_ERROR2("Can not %s Broadcast, device %s in Broadcast mode",
+ (start ? "Start" : "Stop"), (start ? "alerady" :"not"));
+ }
+
+ return status;
+}
+
+
+
+
+
+
+
+/*******************************************************************************
+**
+** Function BTM_RegisterScanReqEvt
+**
+** Description This function is called to register a scan request callback
+** on the advertiser.
+**
+** Parameters p_scan_req_cback: scan request callback. If NULL, remove the
+** registration.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_RegisterScanReqEvt(tBTM_BLE_SCAN_REQ_CBACK *p_scan_req_cback)
+{
+#ifdef BTM_BLE_PC_ADV_TEST_MODE // For general stack code (e.g. BTInsight testing), we simply do not define it to exclude or set it to TRUE to include
+ if (BTM_BLE_PC_ADV_TEST_MODE) // For stack component, it is always defined and maps to a global variable g_bDraculaAdvertisingMode
+ {
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ p_cb->p_scan_req_cback = p_scan_req_cback;
+ }
+#endif
+}
+/*******************************************************************************
+**
+** Function BTM_BleConfigPrivacy
+**
+** Description This function is called to enable or disable the privacy in
+** the local device.
+**
+** Parameters enable: TRUE to enable it; FALSE to disable it.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleConfigPrivacy(BOOLEAN enable)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ BTM_TRACE_EVENT0 (" BTM_BleConfigPrivacy");
+ p_cb->privacy = enable;
+}
+
+/*******************************************************************************
+**
+** 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_EVENT0 ("BTM_BleSetBgConnType ");
+
+ 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);
+ }
+ started = 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_ERROR1("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_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)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+ tBTM_BLE_SEL_CBACK *p_select_cback;
+ BOOLEAN ret = TRUE;
+
+ BTM_TRACE_EVENT0 (" BTM_BleUpdateBgConnDev");
+
+ /* if auto connection is active */
+ if (p_cb->bg_conn_state == BLE_BG_CONN_ACTIVE)
+ {
+ if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO)
+ {
+ /* terminate auto connection first */
+ ret = btm_ble_start_auto_conn(FALSE);
+ }
+ else if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE)
+ {
+ p_select_cback = btm_cb.ble_ctr_cb.p_select_cback;
+ ret = btm_ble_start_select_conn(FALSE, NULL);
+ }
+ }
+ if (ret)
+ {
+ /* update white list */
+ ret = btm_update_bg_conn_list(add_remove, remote_bda);
+ btm_update_dev_to_white_list(add_remove, remote_bda, BLE_ADDR_PUBLIC);
+ }
+
+ if (ret && p_cb->bg_conn_state == BLE_BG_CONN_IDLE)
+ {
+ if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO)
+ {
+ /* restart auto connection */
+ btm_ble_start_auto_conn(TRUE);
+ }
+ else if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE)
+ {
+ p_select_cback = btm_cb.ble_ctr_cb.p_select_cback;
+ btm_ble_start_select_conn(TRUE, p_select_cback);
+ }
+ }
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function BTM_BleSetConnMode
+**
+** Description This function is called to set BLE connectable mode for a
+** peripheral device.
+**
+** Parameters directed: is directed connectable mode, or non-directed.
+** p_dir_bda: connectable direct initiator's LE device address
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleSetConnMode(BOOLEAN directed, tBLE_BD_ADDR *p_dir_bda)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ tBTM_STATUS status = BTM_SUCCESS;
+ BD_ADDR reconn_bda;
+
+ BTM_TRACE_EVENT0 ("BTM_BleSetConnMode ");
+
+ memcpy(&p_cb->direct_bda, &le_bda_any, sizeof(tBLE_BD_ADDR));
+ p_cb->own_addr_type = BLE_ADDR_PUBLIC;
+
+ if (directed)
+ {
+ if (p_dir_bda)
+ {
+ memcpy(&p_cb->direct_bda, p_dir_bda, sizeof(tBLE_BD_ADDR));
+
+ if (btm_cb.ble_ctr_cb.privacy /* && GAP privacy ad reconnect addr exist */)
+ {
+ /* write reconnect address to controller*/
+ btsnd_hcic_ble_set_random_addr(reconn_bda);
+ }
+ /* else use static address or publich address */
+
+ }
+ else
+ status = BTM_ILLEGAL_VALUE;
+ }
+ else /* undirected connecatable */
+ {
+ if (btm_cb.ble_ctr_cb.privacy /* GAP privacy flag enabled */)
+ {
+ /* generate resolvable private address */
+ btm_gen_resolvable_private_addr();
+ } /* else use publich address */
+
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** 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_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ BTM_TRACE_EVENT0 ("BTM_BleSetAdvParams");
+
+ if (!BTM_BLE_VALID_PRAM(adv_int_min, BTM_BLE_ADV_INT_MIN, BTM_BLE_ADV_INT_MAX) ||
+ !BTM_BLE_VALID_PRAM(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));
+ }
+ else
+ memcpy(&p_cb->direct_bda, &le_bda_any, sizeof(tBLE_BD_ADDR));
+
+ if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE)
+ {
+ BTM_TRACE_EVENT0 ("update params for an active adv");
+
+ if (p_cb->connectable_mode == BTM_BLE_NON_CONNECTABLE)
+ {
+ if (BTM_BLE_VALID_CONN_DIRECT(&p_cb->direct_bda))
+ p_cb->evt_type = BTM_BLE_CONNECT_DIR_EVT;
+ else
+ p_cb->evt_type = BTM_BLE_CONNECT_EVT;
+
+ BTM_TRACE_DEBUG1(" evt_type = %d", p_cb->evt_type);
+ }
+
+ if (!btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE))
+ status = BTM_NO_RESOURCES;
+ else
+ /* update adv params */
+ if (!btsnd_hcic_ble_write_adv_params (p_cb->adv_interval_min,
+ p_cb->adv_interval_max,
+ p_cb->evt_type,
+ p_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 if (!btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE))
+ {
+ p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
+
+ status = BTM_NO_RESOURCES;
+ }
+
+ }
+
+ 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_EVENT0 ("BTM_BleReadAdvParams ");
+
+ *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 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.
+** scan_type: active scan or passive scan
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_BleSetScanParams(UINT16 scan_interval, UINT16 scan_window, tBTM_BLE_SCAN_MODE scan_mode)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ BTM_TRACE_EVENT0 (" BTM_BleSetScanParams");
+
+ if (BTM_BLE_VALID_PRAM(scan_interval, BTM_BLE_SCAN_INT_MIN, BTM_BLE_SCAN_INT_MAX) &&
+ BTM_BLE_VALID_PRAM(scan_window, BTM_BLE_SCAN_WIN_MIN, BTM_BLE_SCAN_WIN_MAX) &&
+ (scan_mode == BTM_BLE_SCAN_MODE_ACTI || scan_mode == BTM_BLE_SCAN_MODE_PASS))
+ {
+ p_cb->scan_type = scan_mode;
+
+ if (BTM_BLE_CONN_PARAM_UNDEF != scan_interval)
+ p_cb->scan_interval = scan_interval;
+
+ if (BTM_BLE_CONN_PARAM_UNDEF != scan_window)
+ p_cb->scan_window = scan_window;
+ }
+ else
+ {
+ BTM_TRACE_ERROR2("Illegal params: scan_interval = %d scan_window = %d",
+ scan_interval, scan_window);
+ }
+
+}
+
+/*******************************************************************************
+**
+** 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 status = BTM_NO_RESOURCES;
+ UINT8 rsp_data[BTM_BLE_AD_DATA_LEN],
+ *p = rsp_data;
+
+ BTM_TRACE_EVENT0 (" BTM_BleWriteScanRsp");
+ memset(rsp_data, 0, BTM_BLE_AD_DATA_LEN);
+ btm_ble_build_adv_data(&data_mask, &p, p_data);
+
+ if (btsnd_hcic_ble_set_scan_rsp_data((UINT8)(p - rsp_data), rsp_data))
+ {
+ status = BTM_SUCCESS;
+
+ if (p_data != NULL)
+ btm_cb.ble_ctr_cb.inq_var.scan_rsp = TRUE;
+ else
+ btm_cb.ble_ctr_cb.inq_var.scan_rsp = FALSE;
+ }
+ else
+ status = BTM_ILLEGAL_VALUE;
+
+ 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;
+ UINT16 mask = data_mask;
+
+ memset(p_cb_data, 0, sizeof(tBTM_BLE_LOCAL_ADV_DATA));
+ p = p_cb_data->ad_data;
+ p_cb_data->data_mask = data_mask;
+
+ BTM_TRACE_EVENT0 ("BTM_BleWriteAdvData ");
+ p_cb_data->p_flags = btm_ble_build_adv_data(&mask, &p, p_data);
+
+ p_cb_data->p_pad = p;
+
+ if (data_mask != 0)
+ {
+ BTM_TRACE_ERROR0("Partial data write into ADV");
+ }
+
+ 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))
+ return BTM_SUCCESS;
+ else
+ return BTM_NO_RESOURCES;
+
+}
+
+/*******************************************************************************
+**
+** 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_API1("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 */
+ STREAM_TO_UINT8(length, p);
+ }
+
+ *p_length = 0;
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_build_adv_data
+**
+** Description This function is called build the adv data and rsp data.
+*******************************************************************************/
+static UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst, tBTM_BLE_ADV_DATA *p_data)
+{
+ UINT16 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_ATTR *p_attr;
+ tBTM_BLE_PROP_ELEM *p_elem;
+
+ BTM_TRACE_EVENT0 (" 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++ = 2;
+ *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;
+ }
+ /* device name */
+ if (len > 2 && data_mask & BTM_BLE_AD_BIT_DEV_NAME)
+ {
+ if (strlen(btm_cb.cfg.bd_name) > (UINT16)(len - 2))
+ {
+ *p++ = len - 2 + 1;
+ *p++ = BTM_BLE_AD_TYPE_NAME_SHORT;
+ ARRAY_TO_STREAM(p, btm_cb.cfg.bd_name, len - 2);
+ }
+ 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 + 2);
+ data_mask &= ~BTM_BLE_AD_BIT_DEV_NAME;
+ }
+ /* manufacturer data */
+ if (len > 2 && data_mask & BTM_BLE_AD_BIT_MANU &&
+ p_data && p_data->manu.len != 0 && p_data->manu.p_val)
+ {
+ if (p_data->manu.len > (len - 2))
+ cp_len = len - 2;
+ else
+ cp_len = p_data->manu.len;
+
+ *p++ = cp_len + 1;
+ *p++ = BTM_BLE_AD_TYPE_MANU;
+ ARRAY_TO_STREAM(p, p_data->manu.p_val, cp_len);
+
+ len -= (cp_len + 2);
+ data_mask &= ~BTM_BLE_AD_BIT_MANU;
+ }
+ /* TX power */
+ if (len > 2 && data_mask & BTM_BLE_AD_BIT_TX_PWR)
+ {
+ *p++ = 2;
+ *p++ = BTM_BLE_AD_TYPE_TX_PWR;
+ *p++ = btm_cb.ble_ctr_cb.inq_var.tx_power;
+ len -= 3;
+
+ data_mask &= ~BTM_BLE_AD_BIT_TX_PWR;
+ }
+ /* services */
+ if (len > 2 && data_mask & BTM_BLE_AD_BIT_SERVICE &&
+ p_data && p_data->services.num_service != 0 &&
+ p_data->services.p_uuid)
+ {
+ if (p_data->services.num_service * 2 > (len - 2))
+ {
+ cp_len = (len - 2)/2;
+ *p ++ = 1 + cp_len * 2;
+ *p++ = BTM_BLE_AD_TYPE_SRV_PART;
+ }
+ else
+ {
+ cp_len = p_data->services.num_service;
+ *p++ = 1 + cp_len * 2;
+ *p++ = BTM_BLE_AD_TYPE_SRV_CMPL;
+ }
+ for (i = 0; i < cp_len; i ++)
+ {
+ UINT16_TO_STREAM(p, *(p_data->services.p_uuid + i));
+ }
+
+ len -= (cp_len * 2 + 2);
+ data_mask &= ~BTM_BLE_AD_BIT_SERVICE;
+ }
+ 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_ATTR && p_data && p_data->attr.num_attr != 0)
+ {
+ for (i = 0; i < p_data->attr.num_attr ; i ++)
+ {
+ p_attr = p_data->attr.attr_list + i;
+
+ if (len >= (2 + 2 + p_attr->data_len))/* len byte(1) + ATTR type(1) + Uuid len(2) + value length */
+ {
+ *p ++ = p_attr->data_len + 2 + 1; /* Uuid len + value length */
+ *p ++ = BTM_BLE_AD_TYPE_ATTR;
+ UINT16_TO_STREAM(p, p_attr->uuid);
+ ARRAY_TO_STREAM(p, p_attr->p_data, p_attr->data_len);
+
+ len -= (4 + p_attr->data_len);
+ }
+ else
+ break;
+ }
+ if (i == p_data->attr.num_attr)
+ data_mask &= ~BTM_BLE_AD_BIT_ATTR;
+ }
+ 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 >= (2 + 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 -= (2 + p_elem->len);
+ }
+ else
+ {
+ BTM_TRACE_WARNING0("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_set_discoverability
+**
+** Description This function is called to set BLE discoverable mode.
+**
+** Parameters: mode: discoverability mode.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_set_discoverability(UINT16 combined_mode)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ UINT16 mode = (combined_mode & BTM_BLE_DISCOVERABLE_MASK);
+ UINT8 flag = 0;
+ UINT8 new_mode = BTM_BLE_ADV_ENABLE;
+ UINT8 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;
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ BTM_TRACE_EVENT2 ("btm_ble_set_discoverability mode=0x%0x combined_mode=0x%x", mode, combined_mode);
+
+ /*** Check mode parameter ***/
+ if (mode > BTM_BLE_MAX_DISCOVERABLE)
+ return(BTM_ILLEGAL_VALUE);
+
+ p_cb->br_edr_supported_flag |= (combined_mode & BTM_DISCOVERABLE_MASK);
+ p_cb->discoverable_mode = mode;
+
+ if (!p_cb->br_edr_supported_flag)
+ {
+ flag = BTM_BLE_BREDR_NOT_SPT;
+ BTM_TRACE_DEBUG1("btm_ble_set_discoverability (BREDR not sup)flag=0x%x",flag);
+ }
+
+ BTM_TRACE_DEBUG1 ("br_edr_supported=0x%x", p_cb->br_edr_supported_flag);
+
+ if (mode == BTM_BLE_LIMITED_DISCOVERABLE || mode == BTM_BLE_GENERAL_DISCOVERABLE)
+ {
+ BTM_TRACE_EVENT0 ("mode == BTM_BLE_LIMITED_DISCOVERABLE ");
+ /* write ADV data with limited disc flag */
+ if (mode == BTM_BLE_LIMITED_DISCOVERABLE)
+ flag |= BTM_BLE_LIMIT_DISC_FLAG ;
+ else
+ flag |= BTM_BLE_GEN_DISC_FLAG;
+ }
+ else /* non-discoverable */
+ {
+ BTM_TRACE_EVENT0 ("mode == BTM_BLE_NON_DISCOVERABLE ");
+
+ if (p_cb->connectable_mode == BTM_BLE_NON_CONNECTABLE)
+ {
+ p_cb->br_edr_supported_flag = 0;
+
+ BTM_TRACE_EVENT0 ("always disable adv in non-discoverable non-connectable mode if no scan rsp ");
+ if (!p_cb->scan_rsp )
+ new_mode = BTM_BLE_ADV_DISABLE;
+ }
+ else
+ {
+ if (BTM_BLE_VALID_CONN_DIRECT(&p_cb->direct_bda))
+ {
+ BTM_TRACE_DEBUG0("evt_type = BTM_BLE_CONNECT_DIR_EVT");
+ evt_type = BTM_BLE_CONNECT_DIR_EVT;
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0(" evt_type = BTM_BLE_CONNECT_EVT");
+ evt_type = BTM_BLE_CONNECT_EVT;
+ }
+ }
+ }
+ btm_ble_update_adv_flag(flag);
+
+ /* update adv params if start advertising */
+ BTM_TRACE_EVENT2 ("evt_type=0x%x p-cb->evt_type=0x%x ", evt_type, p_cb->evt_type);
+ if (new_mode == BTM_BLE_ADV_ENABLE && evt_type != p_cb->evt_type)
+ {
+ if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE)
+ {
+ BTM_TRACE_EVENT0 ("Set Adv disable");
+ p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
+ btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE);
+ }
+
+ /* 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_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;
+
+ }
+ if (status == BTM_SUCCESS && p_cb->adv_mode != new_mode)
+ {
+ /* update advertising mode */
+ if (!btsnd_hcic_ble_set_adv_enable (new_mode))
+ status = BTM_NO_RESOURCES;
+ else
+ p_cb->adv_mode = new_mode;
+ }
+
+ /* set up stop advertising timer */
+ if (status == BTM_SUCCESS && mode == BTM_BLE_LIMITED_DISCOVERABLE)
+ {
+ BTM_TRACE_EVENT1 ("start timer for limited disc mode duration=%d (30 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: mode: connectability mode.
+**
+** Returns void
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_set_connectability(UINT16 combined_mode)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ UINT16 mode = (combined_mode & BTM_BLE_CONNECTABLE_MASK);
+ UINT8 cur_flag = 0;
+ UINT8 cur_br_edr_not_sup_flag;
+ UINT8 new_flag;
+ UINT8 new_mode = BTM_BLE_ADV_ENABLE;
+ UINT8 evt_type = (p_cb->scan_rsp) ? BTM_BLE_DISCOVER_EVT: BTM_BLE_NON_CONNECT_EVT;
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ BTM_TRACE_EVENT2 ("btm_ble_set_connectability mode=0x%0x combined_mode=0x%x", mode, combined_mode);
+
+ /*** Check mode parameter ***/
+ if (mode > BTM_BLE_MAX_CONNECTABLE)
+ return(BTM_ILLEGAL_VALUE);
+ if (btm_cb.ble_ctr_cb.inq_var.adv_data.p_flags)
+ cur_flag = *btm_cb.ble_ctr_cb.inq_var.adv_data.p_flags ;
+ cur_br_edr_not_sup_flag = (cur_flag & ((UINT8) BTM_BLE_BREDR_NOT_SPT));
+
+ p_cb->br_edr_supported_flag |= ((combined_mode & BTM_CONNECTABLE_MASK) << 4);
+ if (p_cb->br_edr_supported_flag && cur_br_edr_not_sup_flag)
+ {
+ new_flag = cur_flag & ((UINT8) (~BTM_BLE_BREDR_NOT_SPT));
+ BTM_TRACE_EVENT2 ("new flag=0x%x cur flag=0x%x",new_flag, cur_flag);
+ btm_ble_update_adv_flag(new_flag);
+ }
+ p_cb->connectable_mode = mode;
+
+ if (mode == BTM_BLE_NON_CONNECTABLE)
+ {
+ if (p_cb->discoverable_mode == BTM_BLE_NON_DISCOVERABLE)
+ {
+ p_cb->br_edr_supported_flag = 0;
+ BTM_TRACE_EVENT0 ("always disable adv in non-discoverable non-connectable mode with no scan rsp");
+ if(!p_cb->scan_rsp)
+ new_mode = BTM_BLE_ADV_DISABLE;
+ }
+ }
+ else /* connectable */
+ {
+ BTM_TRACE_DEBUG2("btm_ble_set_connectability: mode = %04x discoverable_mode= %02x", mode, p_cb->discoverable_mode);
+
+ if (BTM_BLE_VALID_CONN_DIRECT(&p_cb->direct_bda))
+ {
+ BTM_TRACE_DEBUG0("evt_type = BTM_BLE_CONNECT_DIR_EVT");
+ evt_type = BTM_BLE_CONNECT_DIR_EVT;
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0(" evt_type = BTM_BLE_CONNECT_EVT");
+ evt_type = BTM_BLE_CONNECT_EVT;
+ }
+ }
+
+ /* update adv params if needed */
+ if (p_cb->evt_type != evt_type && new_mode == BTM_BLE_ADV_ENABLE)
+ {
+ if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE)
+ {
+ p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
+ btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE);
+ }
+
+ 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_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;
+ }
+ /* update advertising mode */
+ if (status == BTM_SUCCESS && new_mode != p_cb->adv_mode)
+ {
+ if (btsnd_hcic_ble_set_adv_enable (new_mode))
+ {
+ status = BTM_SUCCESS;
+
+ p_cb->adv_mode = new_mode;
+ }
+ }
+
+ 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_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_ble_start_inquiry (UINT8 mode, UINT8 duration)
+{
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+ tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
+
+ BTM_TRACE_DEBUG2("btm_ble_start_inquiry: mode = %02x inq_active = %d", mode, btm_cb.btm_inq_vars.inq_active);
+
+ if (p_inq->proc_mode != BTM_BLE_INQUIRY_NONE)
+ {
+ BTM_TRACE_ERROR0("LE scan is active, can not start inquiry");
+ return(BTM_BUSY);
+ }
+
+ btm_update_scanner_filter_policy(SP_ADV_ALL);
+
+ /* start scan, already enable duplicate filtering */
+ if (btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE))
+ {
+ status = BTM_SUCCESS;
+ p_inq->proc_mode = mode;
+
+ if (duration != 0)
+ {
+ /* start inquiry timer */
+ btu_start_timer (&p_inq->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);
+ 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, hci_status);
+ btm_sec_rmt_name_request_complete (bda, (UINT8 *)p_name, hci_status);
+}
+
+/*******************************************************************************
+**
+** 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 (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_DEBUG0("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 (!GAP_BleReadPeerDevName(remote_bda, btm_ble_read_remote_name_cmpl))
+ return BTM_BUSY;
+
+ 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;
+
+ status = GAP_BleCancelReadPeerDevName(remote_bda);
+
+ 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_DEBUG1 ("btm_ble_update_adv_flag new=0x%x", flag);
+
+ if (p_adv_data->p_flags != NULL)
+ {
+ BTM_TRACE_DEBUG1 ("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;
+ tBTM_BLE_ATTR *p_attr;
+
+ BTM_TRACE_EVENT0 (" btm_ble_parse_adv_data");
+
+ while (len > 0)
+ {
+ BTM_TRACE_DEBUG1("btm_ble_parse_adv_data: len = %d", len);
+ if ((ad_len = *p_cur ++) == 0)
+ break;
+
+ ad_type = *p_cur ++;
+
+ BTM_TRACE_DEBUG2(" 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_DEBUG1("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_DEBUG3("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_DEBUG1("BTM_BLE_AD_TYPE_TX_PWR tx_level = %d", p_adv_data->tx_power_level);
+ break;
+
+ case BTM_BLE_AD_TYPE_ATTR:
+ p_adv_data->ad_mask |= BTM_BLE_AD_BIT_ATTR;
+ p_attr = &p_adv_data->attr_data.attr_list[p_adv_data->attr_data.num_attr];
+ p_attr->uuid = *p_cur ++;
+
+ if (ad_len > 3)
+ {
+ p_attr->data_len = ad_len - 3;
+ p_attr->p_data = p_buf;
+ memcpy(p_attr->p_data, p_cur, p_attr->data_len);
+ p_buf += p_attr->data_len;
+ }
+
+ p_adv_data->attr_data.num_attr ++;
+ BTM_TRACE_DEBUG2("BTM_BLE_AD_TYPE_ATTR[%d] uuid = 0x%04x",p_adv_data->attr_data.num_attr, p_attr->uuid);
+ break;
+
+ case BTM_BLE_AD_TYPE_MANU:
+
+ case BTM_BLE_AD_TYPE_SRV_CMPL:
+ case BTM_BLE_AD_TYPE_SRV_PART:
+ p_adv_data->ad_mask |= ad_type;
+ /* need allocate memory to store UUID list */
+ p_adv_data->service.num_service = (ad_len - 1)/2;
+ BTM_TRACE_DEBUG1("service UUID list, num = %d", p_adv_data->service.num_service);
+
+ default:
+ p_cur += (ad_len - 1);
+ 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(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);
+ }
+
+ if (data_len > 0)
+ {
+ p_cache = &p_le_inq_cb->adv_data_cache[p_le_inq_cb->adv_len];
+ STREAM_TO_UINT8(length, p);
+ while ( length && ((p_le_inq_cb->adv_len + length + 1) <= BTM_BLE_CACHE_ADV_DATA_MAX))
+ {
+ /* copy from the length byte & data into cache */
+ memcpy(p_cache, p-1, length+1);
+ /* advance the cache pointer past data */
+ p_cache += length+1;
+ /* increment cache length */
+ p_le_inq_cb->adv_len += length+1;
+ /* skip the length of data */
+ p += length;
+ STREAM_TO_UINT8(length, p);
+ }
+ }
+
+ /* 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
+**
+*******************************************************************************/
+BOOLEAN btm_ble_is_discoverable(BD_ADDR bda, UINT8 evt_type, UINT8 *p)
+{
+ BOOLEAN is_discoverable = FALSE;
+ UINT8 *p_flag, flag = 0;
+ UINT8 data_len;
+ tBTM_INQ_PARMS *p_cond = &btm_cb.btm_inq_vars.inqparms;
+
+ STREAM_TO_UINT8 (data_len, p);
+
+ /* for observer, always "discoverable */
+ if (btm_cb.ble_ctr_cb.inq_var.proc_mode == BTM_BLE_OBSERVE ||
+ (btm_cb.ble_ctr_cb.inq_var.proc_mode == BTM_BLE_SELECT_SCAN &&
+ btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE))
+ return TRUE;
+
+ /* 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_DEBUG0("BD ADDR does not meet filter condition");
+ return FALSE;
+ }
+
+ /* scan response does not include the flag */
+ if (evt_type == BTM_BLE_SCAN_RSP_EVT)
+ return FALSE;
+
+ if (data_len > BTM_BLE_ADV_DATA_LEN_MAX)
+ {
+ BTM_TRACE_WARNING1("ADV data too long %d. discard", data_len);
+ return FALSE;
+ }
+
+ if (data_len != 0)
+ {
+ if ((p_flag = BTM_CheckAdvData(p, BTM_BLE_AD_TYPE_FLAG, &data_len)) != NULL)
+ {
+ flag = * p_flag;
+
+ if ((btm_cb.ble_ctr_cb.inq_var.proc_mode == BTM_BLE_GENERAL_INQUIRY) &&
+ (flag & (BTM_BLE_LIMIT_DISC_FLAG|BTM_BLE_GEN_DISC_FLAG)) != 0)
+ {
+ BTM_TRACE_DEBUG0("Find Generable Discoverable device");
+ is_discoverable = TRUE;
+ }
+
+ else if (btm_cb.ble_ctr_cb.inq_var.proc_mode == BTM_BLE_LIMITED_INQUIRY &&
+ (flag & BTM_BLE_LIMIT_DISC_FLAG) != 0)
+ {
+ BTM_TRACE_DEBUG0("Find limited discoverable device");
+ is_discoverable = TRUE;
+ }
+
+ }
+ }
+
+ if (!is_discoverable)
+ {
+ BTM_TRACE_ERROR1("discoverable flag not desired: %d", flag);
+ }
+
+ return is_discoverable;
+}
+/*******************************************************************************
+**
+** Function btm_ble_update_inq_result
+**
+** Description Update adv packet information into inquiry result.
+**
+** Parameters
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN btm_ble_update_inq_result(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;
+
+ STREAM_TO_UINT8 (data_len, p);
+
+ if (data_len > BTM_BLE_ADV_DATA_LEN_MAX)
+ {
+ BTM_TRACE_WARNING1("EIR data too long %d. discard", data_len);
+ return FALSE;
+ }
+ btm_ble_cache_adv_data(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)))
+ {
+ p_i->scan_rsp = FALSE;
+ to_report = FALSE;
+ }
+ 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;
+
+ 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 BR/EDR not supported is not set, assume is a DUMO device */
+ if ((p_cur->flag & BTM_BLE_BREDR_NOT_SPT) == 0)
+ {
+ BTM_TRACE_ERROR0("BR/EDR NOT support bit not set, treat as DUMO");
+ p_cur->device_type |= BT_DEVICE_TYPE_DUMO;
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0("BR/EDR NOT SUPPORT bit set, LE only device");
+ }
+
+ return to_report;
+
+}
+
+/*******************************************************************************
+**
+** 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};
+
+ 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);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_resolve_random_addr_cmpl
+**
+** Description resolve random address complete callback.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_ble_resolve_random_addr_cmpl(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_EVENT0 ("btm_ble_resolve_random_addr_cmpl ");
+
+ STREAM_TO_UINT8 (evt_type, pp);
+ STREAM_TO_UINT8 (addr_type, pp);
+ STREAM_TO_BDADDR (bda, pp);
+
+ if (match_rec)
+ {
+ BTM_TRACE_ERROR0("Random match");
+ memcpy(match_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN);
+ memcpy(bda, match_rec->bd_addr, BD_ADDR_LEN);
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("Random unmatch");
+ }
+
+ btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, pp);
+
+ return;
+}
+
+/*******************************************************************************
+**
+** 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;
+
+ BTM_TRACE_EVENT0 ("btm_ble_process_adv_pkt ");
+
+ /* always get one device at a time */
+ p ++;
+
+ /* Extract inquiry results */
+ STREAM_TO_UINT8 (evt_type, p);
+ STREAM_TO_UINT8 (addr_type, p);
+ STREAM_TO_BDADDR (bda, p);
+
+#ifdef BTM_BLE_PC_ADV_TEST_MODE // For general stack code (e.g. BTInsight testing), we simply do not define it to exclude or set it to TRUE to include
+ if (BTM_BLE_PC_ADV_TEST_MODE) // For stack component, it is always defined and maps to a global variable g_bDraculaAdvertisingMode
+ {
+ if (btm_cb.ble_ctr_cb.p_scan_req_cback)
+ (*btm_cb.ble_ctr_cb.p_scan_req_cback)(bda, addr_type, evt_type);
+ }
+#endif
+
+ /* Only process the results if the inquiry is still active */
+ if (!btm_cb.btm_inq_vars.inq_active &&
+ (btm_cb.ble_ctr_cb.bg_conn_type != BTM_BLE_CONN_SELECTIVE ||
+ /* or selective auto connection is active */
+ btm_cb.ble_ctr_cb.p_select_cback == NULL))
+ return;
+
+
+#if SMP_INCLUDED == TRUE
+ if (addr_type == BLE_ADDR_RANDOM && BTM_BLE_IS_RESOLVE_BDA(bda))
+ {
+ btm_ble_resolve_random_addr(bda, btm_ble_resolve_random_addr_cmpl, p_data);
+ }
+ else
+#endif
+ btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, p);
+}
+
+/*******************************************************************************
+**
+** 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;
+ BOOLEAN to_report = FALSE;
+ 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_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ 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)))
+ ||
+ btm_cb.ble_ctr_cb.inq_var.proc_mode == BTM_BLE_OBSERVE)
+ {
+ BTM_TRACE_DEBUG0("update new BLE information ");
+ to_report = TRUE;
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0("LE in le_bd_db already");
+ /* if yes, skip it */
+ return; /* assumption: one result per event */
+ }
+ }
+ else /* not been processed int his round */
+ {
+ BTM_TRACE_DEBUG0("new LE BD_ADDR");
+ to_report = TRUE;
+ }
+
+ /* If existing entry, use that, else get a new one (possibly reusing the oldest) */
+ if (p_i == NULL)
+ {
+ if (btm_ble_is_discoverable(bda, evt_type, p))
+ {
+ if ((p_i = btm_inq_db_new (bda)) != NULL)
+ {
+ p_inq->inq_cmpl_info.num_resp++;
+ BTM_TRACE_DEBUG0("adv pkt process: new record is added into inq db");
+ to_report = TRUE;
+ }
+ else
+ return;
+ }
+ else
+ {
+ BTM_TRACE_ERROR0("discard adv pkt");
+ 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 (to_report)
+ {
+ to_report = btm_ble_update_inq_result(p_i, addr_type, evt_type, p);
+ }
+
+#if BTM_USE_INQ_RESULTS_FILTER == TRUE
+ /* 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 && p_i->scan_rsp))
+ {
+ BTM_TRACE_WARNING0("INQ RES: Extra Response Received...cancelling inquiry..");
+
+ if (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) )
+ btsnd_hcic_inq_cancel();
+
+ /* stop LE scan now */
+ btm_ble_stop_scan();
+
+#if BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE
+ btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);
+#endif
+ }
+ }
+#endif
+
+ /* background connection in selective connection mode */
+ if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE)
+ {
+ btm_send_sel_conn_callback(bda, evt_type, p, addr_type);
+ }
+ else if (p_inq_results_cb && to_report)
+ {
+ BTM_TRACE_DEBUG0("BTMINQ LE: Found devices, send callback btm_inqrslt_cb");
+
+ if (p_inq->inq_active)
+ (p_inq_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_stop_scan
+**
+** Description Stop the BLE scan.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_stop_scan(void)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ BTM_TRACE_EVENT0 ("btm_ble_stop_scan ");
+
+ btu_stop_timer (&p_cb->inq_timer_ent);
+
+ /* Clear the inquiry callback if set */
+ p_cb->scan_type = BTM_BLE_SCAN_MODE_NONE;
+ p_cb->proc_mode = BTM_BLE_INQUIRY_NONE;
+
+ /* stop discovery now */
+ btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+
+ /* If we have a callback registered for inquiry complete, call it */
+ BTM_TRACE_DEBUG2 ("BTM Inq Compl Callback: status 0x%02x, num results %d",
+ p_inq->inq_cmpl_info.status, p_inq->inq_cmpl_info.num_resp);
+
+ btm_update_scanner_filter_policy(SP_ADV_ALL);
+
+ btm_process_inq_complete(HCI_SUCCESS, (UINT8)(p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK));
+
+}
+
+/*******************************************************************************
+**
+** Function btm_ble_stop_adv
+**
+** Description Stop the BLE advertising.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_stop_adv(void)
+{
+ BTM_TRACE_EVENT0 (" btm_ble_stop_adv");
+
+ if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE))
+ {
+ btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+ }
+}
+
+/*******************************************************************************
+**
+** 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_EVENT0 ("btm_ble_timeout");
+
+ switch (p_tle->event)
+ {
+ case BTU_TTYPE_BLE_INQUIRY:
+ btm_ble_stop_scan();
+ break;
+
+ case BTU_TTYPE_BLE_GAP_LIM_DISC:
+ /* lim_timeout expiried, limited discovery should exit now */
+ btm_ble_update_adv_flag(BTM_BLE_NON_LIMIT_DISC_FLAG);
+
+ btm_ble_stop_adv();
+ break;
+
+ case BTU_TTYPE_BLE_RANDOM_ADDR:
+ if (btm_cb.ble_ctr_cb.inq_var.adv_mode == BTM_BLE_ADV_ENABLE &&
+ btm_cb.ble_ctr_cb.inq_var.own_addr_type == BLE_ADDR_RANDOM)
+ {
+ /* refresh the random addr */
+ btm_gen_resolvable_private_addr();
+ }
+ break;
+
+ }
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda);
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+
+ BTM_TRACE_EVENT0 ("btm_ble_connected");
+
+ /* Commenting out trace due to obf/compilation problems.
+ */
+#if (BT_USE_TRACES == TRUE)
+ if (p_dev_rec)
+ {
+ BTM_TRACE_EVENT4 ("Security Manager: btm_sec_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_DEBUG1 ("btm_ble_connected sec_flags=0x%x",p_dev_rec->sec_flags);
+ }
+ else
+ {
+ BTM_TRACE_EVENT3 ("Security Manager: btm_sec_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 */
+ p_dev_rec = btm_sec_alloc_dev (bda);
+ }
+ else /* Update the timestamp for this device */
+ {
+ p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+ }
+
+ p_dev_rec->device_type = BT_DEVICE_TYPE_BLE;
+ p_dev_rec->hci_handle = handle;
+ if (role == HCI_ROLE_MASTER)
+ p_dev_rec->role_master = TRUE;
+
+ p_cb->inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+
+ return;
+}
+
+/*******************************************************************************
+**
+** 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 = &btm_cb.acl_db[0];
+ UINT8 size;
+ UINT16 handle;
+ int xx, yy;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_EVENT0 ("btm_ble_read_remote_features_complete ");
+
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT8 (size, p);
+
+ /* Look up the connection by handle and copy features */
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_acl_cb++)
+ {
+ if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle))
+ {
+ for (yy = 0; yy < BD_FEATURES_LEN; yy++)
+ STREAM_TO_UINT8 (p_acl_cb->features[yy], p);
+
+ p_dev_rec = btm_find_dev_by_handle (handle);
+ if (!p_dev_rec)
+ {
+ /* Get a new device; might be doing dedicated bonding */
+ p_dev_rec = btm_find_or_alloc_dev (p_acl_cb->remote_addr);
+ }
+
+ memcpy (p_dev_rec->features, p_acl_cb->features, BD_FEATURES_LEN);
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+ tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ /* if write adv enable/disbale not succeed */
+ if (*p != HCI_SUCCESS)
+ {
+ /* toggle back the adv mode */
+ p_cb->adv_mode = !p_cb->adv_mode;
+ }
+}
+/*******************************************************************************
+**
+** Function btm_ble_init
+**
+** Description Initialize the control block variable values.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_ble_init (void)
+{
+ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+
+ BTM_TRACE_EVENT0 ("btm_ble_init ");
+
+ memset(p_cb, 0, sizeof(tBTM_BLE_CB));
+
+ 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_CONN_PARAM_UNDEF;
+
+ p_cb->inq_var.evt_type = BTM_BLE_UNKNOWN_EVT;
+}
+
+#endif /* BLE_INCLUDED */
diff --git a/stack/btm/btm_ble_int.h b/stack/btm/btm_ble_int.h
new file mode 100644
index 0000000..449de8f
--- /dev/null
+++ b/stack/btm/btm_ble_int.h
@@ -0,0 +1,299 @@
+/******************************************************************************
+ *
+ * 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 "bt_target.h"
+#include "gki.h"
+#include "hcidefs.h"
+#include "btm_ble_api.h"
+#include "btm_int.h"
+
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+#include "smp_api.h"
+#endif
+
+#define BTM_BLE_CONNECT_EVT 0x00
+#define BTM_BLE_CONNECT_DIR_EVT 0x01
+#define BTM_BLE_DISCOVER_EVT 0x02
+#define BTM_BLE_NON_CONNECT_EVT 0x03
+#define BTM_BLE_SCAN_RSP_EVT 0x04
+#define BTM_BLE_SCAN_REQ_EVT 0x06
+#define BTM_BLE_UNKNOWN_EVT 0xff
+
+#define BTM_BLE_UNKNOWN_EVT 0xff
+
+/* 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_ENABLE 1
+#define BTM_BLE_DUPLICATE_DISABLE 0
+
+#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 30 /* Tgap(lim_timeout) = 30.72 s max, round down to 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;
+
+
+
+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
+
+#define BTM_BLE_VALID_PRAM(x, min, max) (((x) >= (min) && (x) <= (max)) || ((x) == BTM_BLE_CONN_PARAM_UNDEF))
+
+typedef struct
+{
+
+ UINT16 discoverable_mode;
+ UINT16 connectable_mode;
+ UINT16 br_edr_supported_flag; /* combined BR EDR discoverable and connectable mode */
+ /* only meaningful when it is zero. This means
+ BR EDR is not supported*/
+ UINT8 proc_mode; /* current procedure mode : inquiry or discovery */
+
+ UINT16 scan_window;
+ UINT16 scan_interval;
+ UINT8 scan_type; /* current scan type: active or passive */
+ UINT16 adv_interval_min;
+ UINT16 adv_interval_max;
+ tBLE_ADDR_TYPE own_addr_type;
+ tBTM_BLE_AFP afp; /* advertising filter policy */
+ tBTM_BLE_SFP sfp; /* scanning filter policy */
+
+ UINT8 evt_type;
+ UINT8 adv_mode;
+ tBLE_BD_ADDR direct_bda;
+
+ UINT8 adv_len;
+ UINT8 adv_data_cache[BTM_BLE_CACHE_ADV_DATA_MAX];
+
+ /* inquiry BD addr database */
+ UINT8 num_bd_entries;
+ UINT8 max_bd_entries;
+
+ tBLE_BD_ADDR local_bda;
+
+ tBTM_BLE_LOCAL_ADV_DATA adv_data;
+ tBTM_BLE_ADV_CHNL_MAP adv_chnl_map;
+
+ TIMER_LIST_ENT inq_timer_ent;
+ BOOLEAN scan_rsp;
+ UINT8 state; /* Current state that the inquiry process is in */
+ UINT8 tx_power;
+} tBTM_BLE_INQ_CB;
+
+
+/* random address resolving complete callback */
+typedef void (tBTM_BLE_RESOLVE_CBACK) (void * match_rec, void *p);
+
+/* random address management control block */
+typedef struct
+{
+ BD_ADDR private_addr;
+ BD_ADDR random_bda;
+ BOOLEAN busy;
+ UINT16 index;
+ tBTM_BLE_RESOLVE_CBACK *p_resolve_cback;
+ void *p;
+ TIMER_LIST_ENT raddr_timer_ent;
+} 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;
+
+/* Define BLE Device Management control structure
+*/
+typedef struct
+{
+ /*****************************************************
+ ** BLE Inquiry
+ *****************************************************/
+ tBTM_BLE_INQ_CB inq_var;
+
+ /* background connection procedure cb value */
+ tBTM_BLE_CONN_TYPE bg_conn_type;
+ UINT16 scan_int;
+ UINT16 scan_win;
+ tBTM_BLE_SEL_CBACK *p_select_cback;
+ TIMER_LIST_ENT scan_param_idle_timer;
+
+ UINT8 bg_conn_dev_num;
+ BD_ADDR bg_conn_dev_list[BTM_BLE_MAX_BG_CONN_DEV_NUM];
+
+#define BLE_BG_CONN_IDLE 0
+#define BLE_BG_CONN_ACTIVE 1
+#define BLE_BG_CONN_SUSPEND 2
+
+ UINT8 bg_conn_state;
+
+ /* random address management control block */
+ tBTM_LE_RANDOM_CB addr_mgnt_cb;
+
+ /* white list information */
+ UINT8 num_empty_filter; /* Number of entries in white list */
+ UINT8 max_filter_entries; /* Maximum number of entries that can be stored */
+ BOOLEAN enabled;
+ BOOLEAN privacy; /* privacy enabled or disabled */
+
+#ifdef BTM_BLE_PC_ADV_TEST_MODE
+ tBTM_BLE_SCAN_REQ_CBACK *p_scan_req_cback;
+#endif
+
+} tBTM_BLE_CB;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void btm_ble_timeout(TIMER_LIST_ENT *p_tle);
+extern void btm_ble_process_adv_pkt (UINT8 *p);
+extern void btm_ble_proc_scan_rsp_rpt (UINT8 *p);
+extern tBTM_STATUS btm_ble_read_remote_name(BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur, tBTM_CMPL_CB *p_cb);
+extern BOOLEAN btm_ble_cancel_remote_name(BD_ADDR remote_bda);
+
+extern tBTM_STATUS btm_ble_set_discoverability(UINT16 combined_mode);
+extern tBTM_STATUS btm_ble_set_connectability(UINT16 combined_mode);
+extern tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8 duration);
+
+extern void btm_ble_stop_scan(void);
+extern void btm_ble_att_db_init(void);
+extern void btm_ble_init (void);
+extern void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role);
+extern void btm_ble_read_remote_features_complete(UINT8 *p);
+extern void btm_ble_stop_adv(void);
+extern void btm_ble_write_adv_enable_complete(UINT8 * p);
+
+/* LE security function from btm_sec.c */
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+extern 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);
+extern void btm_ble_ltk_request_reply(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk);
+extern UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data);
+extern tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, void *p_ref_data, UINT8 link_role);
+extern void btm_ble_ltk_request(UINT16 handle, UINT8 rand[8], UINT16 ediv);
+extern BOOLEAN btm_ble_start_encrypt(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk);
+extern void btm_ble_link_encrypted(BD_ADDR bd_addr, UINT8 encr_enable);
+#endif
+
+/* LE device management functions */
+extern void btm_ble_reset_id( void );
+
+/* security related functions */
+extern void btm_ble_increment_sign_ctr(BD_ADDR bd_addr, BOOLEAN is_local );
+extern BOOLEAN btm_get_local_div (BD_ADDR bd_addr, UINT16 *p_div);
+extern BOOLEAN btm_ble_check_link_type (BD_ADDR bd_addr);
+extern BOOLEAN btm_ble_get_enc_key_type(BD_ADDR bd_addr, UINT8 *p_key_types);
+
+extern void btm_ble_rand_enc_complete (UINT8 *p, UINT16 op_code, tBTM_RAND_ENC_CB *p_enc_cplt_cback);
+extern 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);
+extern void btm_ble_update_sec_key_size(BD_ADDR bd_addr, UINT8 enc_key_size);
+extern UINT8 btm_ble_read_sec_key_size(BD_ADDR bd_addr);
+
+/* white list function */
+extern BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr,tBLE_ADDR_TYPE addr_type);
+extern BOOLEAN btm_update_bg_conn_list(BOOLEAN to_add, BD_ADDR bd_addr);
+extern void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy);
+extern void btm_update_adv_filter_policy(tBTM_BLE_AFP adv_policy);
+extern void btm_ble_clear_white_list (void);
+extern void btm_write_bg_conn_wl(void);
+
+/* background connection function */
+extern void btm_ble_suspend_bg_conn(void);
+extern BOOLEAN btm_ble_resume_bg_conn(tBTM_BLE_SEL_CBACK *p_sele_callback, BOOLEAN def_param);
+extern void btm_ble_update_bg_state(void);
+extern void btm_ble_initiate_select_conn(BD_ADDR bda);
+extern BOOLEAN btm_ble_start_auto_conn(BOOLEAN start);
+extern BOOLEAN btm_ble_start_select_conn(BOOLEAN start,tBTM_BLE_SEL_CBACK *p_select_cback);
+extern BOOLEAN btm_ble_find_dev_in_whitelist(BD_ADDR bd_addr);
+extern BOOLEAN btm_ble_renew_bg_conn_params(BOOLEAN add, BD_ADDR bd_addr);
+extern void btm_ble_scan_param_idle(void);
+extern UINT8 btm_ble_count_unconn_dev_in_whitelist(void);
+
+/* BLE address management */
+extern tBLE_ADDR_TYPE btm_ble_map_bda_to_conn_bda(BD_ADDR bda);
+extern void btm_gen_resolvable_private_addr (void);
+extern void btm_gen_non_resolvable_private_addr (void);
+extern void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK * p_cback, void *p);
+
+#if BTM_BLE_CONFORMANCE_TESTING == TRUE
+BT_API extern void btm_ble_set_no_disc_if_pair_fail (BOOLEAN disble_disc);
+BT_API extern void btm_ble_set_test_mac_value (BOOLEAN enable, UINT8 *p_test_mac_val);
+BT_API extern void btm_ble_set_test_local_sign_cntr_value(BOOLEAN enable, UINT32 test_local_sign_cntr);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/stack/btm/btm_dev.c b/stack/btm/btm_dev.c
new file mode 100644
index 0000000..04994d1
--- /dev/null
+++ b/stack/btm/btm_dev.c
@@ -0,0 +1,464 @@
+/******************************************************************************
+ *
+ * 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 "bt_types.h"
+#include "gki.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "hcidefs.h"
+#include "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 supported features. 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,
+ BD_FEATURES features, UINT32 trusted_mask[],
+ LINK_KEY link_key, UINT8 key_type, tBTM_IO_CAP io_cap)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ int i;
+
+ 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. */
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++)
+ {
+ if (!(btm_cb.sec_dev_rec[i].sec_flags & BTM_SEC_IN_USE))
+ {
+ p_dev_rec = &btm_cb.sec_dev_rec[i];
+
+ /* 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);
+
+#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
+ break;
+ }
+ }
+
+ if (!p_dev_rec)
+ return(FALSE);
+ }
+
+ p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+
+ 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, sizeof (p_dev_rec->sec_bd_name),
+ (char *)bd_name, BTM_MAX_REM_BD_NAME_LEN);
+ }
+
+ if (features)
+ memcpy (p_dev_rec->features, features, sizeof (BD_FEATURES));
+ else
+ memset (p_dev_rec->features, 0, sizeof (BD_FEATURES));
+
+ BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
+
+ if (link_key)
+ {
+ BTM_TRACE_EVENT6 ("BTM_SecAddDevice() BDA: %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_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;
+ }
+
+#if defined(BTIF_MIXED_MODE_INCLUDED) && (BTIF_MIXED_MODE_INCLUDED == TRUE)
+ p_dev_rec->sm4 = BTM_SM4_KNOWN;
+#endif
+
+ p_dev_rec->rmt_io_caps = io_cap;
+
+ return(TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SecDeleteDevice
+**
+** Description Free resources associated with the device.
+**
+** Parameters: bd_addr - BD address of the peer
+**
+** Returns TRUE if removed OK, FALSE if not found or ACL link is active
+**
+*******************************************************************************/
+BOOLEAN BTM_SecDeleteDevice (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ if (BTM_IsAclConnectionUp(bd_addr))
+ {
+ BTM_TRACE_WARNING0("BTM_SecDeleteDevice FAILED: Cannot Delete when connection is active");
+ return(FALSE);
+ }
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL)
+ return(FALSE);
+
+ btm_sec_free_dev (p_dev_rec);
+
+ /* Tell controller to get rid of the link key if it has one stored */
+ BTM_DeleteStoredLinkKey (bd_addr, NULL);
+
+ return(TRUE);
+}
+
+/*******************************************************************************
+**
+** 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_sec_alloc_dev
+**
+** 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_sec_alloc_dev (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+ tBTM_INQ_INFO *p_inq_info;
+ int i;
+ BTM_TRACE_EVENT0 ("btm_sec_alloc_dev");
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++)
+ {
+ if (!(btm_cb.sec_dev_rec[i].sec_flags & BTM_SEC_IN_USE))
+ {
+ p_dev_rec = &btm_cb.sec_dev_rec[i];
+ break;
+ }
+ }
+
+ if (!p_dev_rec)
+ p_dev_rec = btm_find_oldest_dev();
+
+ memset (p_dev_rec, 0, sizeof (tBTM_SEC_DEV_REC));
+
+ 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
+
+#if BTM_INQ_GET_REMOTE_NAME == TRUE
+ if (p_inq_info->remote_name_state == BTM_INQ_RMT_NAME_DONE)
+ {
+ BCM_STRNCPY_S ((char *)p_dev_rec->sec_bd_name, sizeof (p_dev_rec->sec_bd_name),
+ (char *)p_inq_info->remote_name, BTM_MAX_REM_BD_NAME_LEN);
+ p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
+ }
+#endif
+ }
+ else
+ {
+#if BLE_INCLUDED == TRUE
+ p_dev_rec->device_type = BT_DEVICE_TYPE_BREDR; /* initialize it as BR/EDR device */
+ /* 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);
+
+ p_dev_rec->hci_handle = BTM_GetHCIConnHandle (bd_addr);
+ 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)
+{
+ 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
+
+
+}
+
+/*******************************************************************************
+**
+** 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 && HCI_SWITCH_SUPPORTED(btm_cb.devcb.local_features))
+ {
+ if (HCI_SWITCH_SUPPORTED(p_dev_rec->features))
+ {
+ BTM_TRACE_DEBUG0("btm_dev_support_switch return TRUE (feature found)");
+ 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[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_DEBUG0("btm_dev_support_switch return TRUE (feature empty)");
+ return (TRUE);
+ }
+ }
+
+ BTM_TRACE_DEBUG0("btm_dev_support_switch return FALSE");
+ 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 = &btm_cb.sec_dev_rec[0];
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++)
+ {
+ if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE)
+ && (p_dev_rec->hci_handle == handle))
+ return(p_dev_rec);
+ }
+ return(NULL);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = &btm_cb.sec_dev_rec[0];
+ int i;
+
+ if (bd_addr)
+ {
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++)
+ {
+ if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE)
+ && (!memcmp (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN)))
+ return(p_dev_rec);
+ }
+ }
+ return(NULL);
+}
+
+/*******************************************************************************
+**
+** 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_EVENT0 ("btm_find_or_alloc_dev");
+ 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 = &btm_cb.sec_dev_rec[0];
+ tBTM_SEC_DEV_REC *p_oldest = p_dev_rec;
+ UINT32 ot = 0xFFFFFFFF;
+ int i;
+
+ /* First look for the non-paired devices for the oldest entry */
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++)
+ {
+ if (((p_dev_rec->sec_flags & BTM_SEC_IN_USE) == 0)
+ || ((p_dev_rec->sec_flags & BTM_SEC_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 */
+ p_dev_rec = &btm_cb.sec_dev_rec[0];
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++)
+ {
+ 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);
+}
+
+
diff --git a/stack/btm/btm_devctl.c b/stack/btm/btm_devctl.c
new file mode 100644
index 0000000..f0fc437
--- /dev/null
+++ b/stack/btm/btm_devctl.c
@@ -0,0 +1,1953 @@
+/******************************************************************************
+ *
+ * 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 "bt_types.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_int.h"
+#include "l2c_int.h"
+
+#if BLE_INCLUDED == TRUE
+#include "gatt_int.h"
+
+#if GAP_INCLUDED == TRUE
+#include "gap_api.h"
+#include "gattdefs.h"
+#endif
+
+#endif /* BLE_INCLUDED */
+
+/* BTM_APP_DEV_INIT should be defined if additional controller initialization is
+** needed by the application to be performed after the HCI reset
+*/
+#ifdef BTM_APP_DEV_INIT
+extern void BTM_APP_DEV_INIT(void);
+#endif
+
+#ifdef BTA_PRM_CHECK_FW_VER
+extern BOOLEAN BTA_PRM_CHECK_FW_VER(UINT8 *p);
+#endif
+
+#ifndef TT_DEV_RESET_MASK
+#define TT_DEV_RESET_MASK 0xff
+#endif
+
+/********************************************************************************/
+/* L O C A L D A T A D E F I N I T I O N S */
+/********************************************************************************/
+
+/* The default class of device. */
+#ifndef BTM_INIT_CLASS_OF_DEVICE
+#define BTM_INIT_CLASS_OF_DEVICE "\x00\x1F\x00"
+#endif
+
+#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 */
+
+/* After Reset a timeout can be specified in the target.h for specific targets
+ * that may require additional time to reset
+ * otherwise no timeout is required
+*/
+#ifndef BTM_AFTER_RESET_TIMEOUT
+#define BTM_AFTER_RESET_TIMEOUT 0
+#endif
+
+/* Internal baseband so the parameters such as local features, version etc. are known
+so there is no need to issue HCI commands and wait for responses at BTM initialization */
+#ifndef BTM_INTERNAL_BB
+#define BTM_INTERNAL_BB FALSE
+#endif
+
+/* The local version information in the format specified in the HCI read local version
+response message */
+#ifndef BTM_INTERNAL_LOCAL_VER
+#define BTM_INTERNAL_LOCAL_VER {0x00, 0x01, 0x05, 0x81, 0x01, 0x30, 0x00, 0x40, 0x8D}
+#endif
+
+/* The local features information in the format specified in the HCI read local features
+response message */
+#ifndef BTM_INTERNAL_LOCAL_FEA
+#define BTM_INTERNAL_LOCAL_FEA {0x00, 0xFF, 0xF9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
+#endif
+
+#ifndef BTM_SET_DEV_NAME_UPON_RESET
+#define BTM_SET_DEV_NAME_UPON_RESET TRUE
+#endif
+
+/* host SCO buffer size */
+#ifndef BTM_SCO_HOST_BUF_SIZE
+#define BTM_SCO_HOST_BUF_SIZE 0xff
+#endif
+
+#ifndef BTM_GPS_UIPC_CH_NB
+#define BTM_GPS_UIPC_CH_NB UIPC_CH_ID_1
+#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_dev_reset (void);
+static void btm_after_reset_hold_complete (void);
+static void btm_continue_reset (void);
+
+/*******************************************************************************
+**
+** 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));
+#if (BTM_USE_DEF_LOCAL_NAME == TRUE)
+ BCM_STRNCPY_S(btm_cb.cfg.bd_name, sizeof(btm_cb.cfg.bd_name), BTM_DEF_LOCAL_NAME, BTM_MAX_LOC_BD_NAME_LEN);
+#endif
+#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.devcb.rlinkp_timer.param = (TIMER_PARAM_TYPE)TT_DEV_RLNKP;
+
+ 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;
+
+ btm_cb.first_disabled_channel = 0xff; /* To allow disabling 0th channel alone */
+ btm_cb.last_disabled_channel = 0xff; /* To allow disabling 0th channel alone */
+
+#if (BTM_AUTOMATIC_HCI_RESET == TRUE)
+
+#if (BTM_FIRST_RESET_DELAY > 0)
+ btm_cb.devcb.state = BTM_DEV_STATE_WAIT_RESET_CMPLT;
+ btu_start_timer (&btm_cb.devcb.reset_timer, BTU_TTYPE_BTM_DEV_CTL, BTM_FIRST_RESET_DELAY);
+#else
+ btm_dev_reset();
+#endif
+
+#else
+ BTM_TRACE_EVENT0 ("BTM_AUTOMATIC_HCI_RESET is FALSE, so skip btm reset for now");
+#endif
+
+}
+
+
+/*******************************************************************************
+**
+** 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_rlinkp_cmpl_cb)
+ {
+ p_cb = btm_cb.devcb.p_rlinkp_cmpl_cb;
+ btm_cb.devcb.p_rlinkp_cmpl_cb = NULL;
+
+ if (p_cb)
+ (*p_cb)((void *) &status);
+ }
+
+ 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);
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function btm_dev_absent
+**
+** Description This function is called by when it is detected that the
+** device is not connected any more.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_dev_absent (void)
+{
+ btm_cb.devcb.state = BTM_DEV_STATE_WAIT_RESET_CMPLT;
+
+ btm_db_reset ();
+ btm_inq_db_reset();
+
+ /* If anyone wants device status notifications, give him one */
+ btm_report_device_status (BTM_DEV_STATUS_DOWN);
+
+ btu_stop_timer (&btm_cb.devcb.reset_timer);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_DeviceReset
+**
+** Description This function is called to reset the HCI. Callback function
+** if provided is called when startup of the device is
+** completed.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_DeviceReset (tBTM_CMPL_CB *p_cb)
+{
+ tBTM_STATUS status;
+
+ /* If device is already resetting, do not allow another */
+ if ((!btm_cb.devcb.p_reset_cmpl_cb) || (btm_cb.devcb.p_reset_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();
+
+ /* Save address of the completion routine, if provided */
+ btm_cb.devcb.p_reset_cmpl_cb = p_cb;
+
+ btm_dev_reset ();
+ }
+ else
+ {
+ /* pass an error to the bad callback, another one was already provided */
+ if (p_cb)
+ {
+ status = BTM_ILLEGAL_VALUE;
+ p_cb (&status);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** 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 ((BOOLEAN) (btm_cb.devcb.state == BTM_DEV_STATE_READY));
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetAfhChannels
+**
+** Description This function is called disable channels
+**
+** Returns tBTM_STATUS
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetAfhChannels (UINT8 first, UINT8 last)
+{
+ BTM_TRACE_API4 ("BTM_SetAfhChannels first: %d (%d) last: %d (%d)",
+ first, btm_cb.first_disabled_channel, last,
+ btm_cb.last_disabled_channel);
+
+ /* Make sure the local device supports the feature before sending */
+ if ((!HCI_LMP_AFH_CAP_MASTR_SUPPORTED(btm_cb.devcb.local_features)) &&
+ (!HCI_LMP_AFH_CLASS_SLAVE_SUPPORTED(btm_cb.devcb.local_features)) &&
+ (!HCI_LMP_AFH_CLASS_MASTR_SUPPORTED(btm_cb.devcb.local_features)))
+ return (BTM_MODE_UNSUPPORTED);
+
+ if (!BTM_IsDeviceUp())
+ return (BTM_WRONG_MODE);
+
+ if ((btm_cb.first_disabled_channel != first)
+ || (btm_cb.last_disabled_channel != last))
+ {
+ if (btsnd_hcic_set_afh_channels (first, last))
+ {
+ btm_cb.first_disabled_channel = first;
+ btm_cb.last_disabled_channel = last;
+ }
+ else
+ return (BTM_NO_RESOURCES);
+ }
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetAfhChannelAssessment
+**
+** Description This function is called to set the channel assessment mode on or off
+**
+** Returns none
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetAfhChannelAssessment (BOOLEAN enable_or_disable)
+{
+ /* whatever app wants if device is not 1.2 scan type should be STANDARD */
+ if (!HCI_LMP_AFH_CAP_SLAVE_SUPPORTED(btm_cb.devcb.local_features))
+ return (BTM_MODE_UNSUPPORTED);
+
+ if (!btsnd_hcic_write_afh_channel_assessment_mode (enable_or_disable))
+ return (BTM_NO_RESOURCES);
+
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ContinueReset
+**
+** Description This function is called by the application to continue
+** initialization after the application has completed its
+** vendor specific sequence. It is only used when
+** BTM_APP_DEV_INIT is defined in target.h.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_ContinueReset (void)
+{
+#ifdef BTM_APP_DEV_INIT
+ btm_continue_reset();
+#endif
+}
+
+/*******************************************************************************
+**
+** Function btm_dev_reset
+**
+** Description Local function called to send a reset command
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_dev_reset (void)
+{
+ btm_cb.devcb.state = BTM_DEV_STATE_WAIT_RESET_CMPLT;
+
+ /* flush out the command complete queue and command transmit queue */
+ btu_hcif_flush_cmd_queue();
+
+ /* Start reset timer. When timer expires we will send first command */
+ /* from the setup sequence */
+
+ btu_start_timer (&btm_cb.devcb.reset_timer, BTU_TTYPE_BTM_DEV_CTL,
+ BTM_DEV_RESET_TIMEOUT);
+ btsnd_hcic_reset (LOCAL_BR_EDR_CONTROLLER_ID);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_get_hci_buf_size
+**
+** Description Local function called to send a read buffer size command
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_get_hci_buf_size (void)
+{
+
+ btu_start_timer (&btm_cb.devcb.reset_timer, BTU_TTYPE_BTM_DEV_CTL, BTM_DEV_REPLY_TIMEOUT);
+
+ /* Send a Read Buffer Size message to the Host Controller. */
+ btsnd_hcic_read_buffer_size ();
+
+}
+#if BLE_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function btm_read_ble_wl_size
+**
+** Description Local function called to send a read BLE buffer size command
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_ble_wl_size(void)
+{
+ BTM_TRACE_DEBUG0("btm_read_ble_wl_size ");
+ btu_start_timer (&btm_cb.devcb.reset_timer, BTU_TTYPE_BTM_DEV_CTL, BTM_DEV_REPLY_TIMEOUT);
+
+ /* Send a Read Buffer Size message to the Host Controller. */
+ btsnd_hcic_ble_read_white_list_size();
+}
+/*******************************************************************************
+**
+** Function btm_get_ble_buffer_size
+**
+** Description Local function called to send a read BLE buffer size command
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_get_ble_buffer_size(void)
+{
+ BTM_TRACE_DEBUG0("btm_get_ble_buffer_size ");
+ btu_start_timer (&btm_cb.devcb.reset_timer, BTU_TTYPE_BTM_DEV_CTL, BTM_DEV_REPLY_TIMEOUT);
+
+ /* Send a Read Buffer Size message to the Host Controller. */
+ btsnd_hcic_ble_read_buffer_size ();
+}
+#endif
+/*******************************************************************************
+**
+** Function btm_get_local_version
+**
+** Description Local function called to send a read local version to controller
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_get_local_version (void)
+{
+
+ btu_start_timer (&btm_cb.devcb.reset_timer, BTU_TTYPE_BTM_DEV_CTL, BTM_DEV_REPLY_TIMEOUT);
+
+ /* Send a Read Local Version message to the Host Controller. */
+ btsnd_hcic_read_local_ver (LOCAL_BR_EDR_CONTROLLER_ID);
+ btsnd_hcic_read_bd_addr ();
+
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ btm_pm_reset();
+#endif
+
+}
+
+/*******************************************************************************
+**
+** Function btm_get_local_features
+**
+** Description Local function called to send a read local features
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_get_local_features (void)
+{
+ btu_start_timer (&btm_cb.devcb.reset_timer, BTU_TTYPE_BTM_DEV_CTL, BTM_DEV_REPLY_TIMEOUT);
+
+ btsnd_hcic_read_local_features ();
+}
+
+/*******************************************************************************
+**
+** 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 & TT_DEV_RESET_MASK) == TT_DEV_RESET)
+ {
+ /* Call device reset as long as there is timeout*/
+ btm_dev_reset();
+ }
+ else 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_reset_complete
+**
+** Description This function is called when command complete for HCI_Reset
+** is received. It does not make sense to send next command
+** because device is resetting after command complete is
+** received. Just start timer and set required state.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_reset_complete (void)
+{
+ int devinx;
+
+ BTM_TRACE_EVENT0 ("btm_reset_complete");
+
+#ifdef BRCM_VS
+ btm_vs_reset_complete();
+#endif
+
+
+ /* Handle if btm initiated the reset */
+ if (btm_cb.devcb.state == BTM_DEV_STATE_WAIT_RESET_CMPLT)
+ {
+ /* Tell L2CAP that all connections are gone */
+ l2cu_device_reset ();
+
+ /* Clear current security state */
+ for (devinx = 0; devinx < BTM_SEC_MAX_DEVICE_RECORDS; devinx++)
+ {
+ btm_cb.sec_dev_rec[devinx].sec_state = BTM_SEC_STATE_IDLE;
+ }
+
+ /* 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;
+
+#if (BTM_AFTER_RESET_TIMEOUT > 0)
+ btu_start_timer (&btm_cb.devcb.reset_timer, BTU_TTYPE_BTM_DEV_CTL,
+ BTM_AFTER_RESET_TIMEOUT);
+#else
+ btm_cb.devcb.state = BTM_DEV_STATE_WAIT_AFTER_RESET;
+ btm_after_reset_hold_complete();
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+ btm_cb.ble_ctr_cb.bg_conn_state = BLE_BG_CONN_IDLE;
+ btm_cb.ble_ctr_cb.bg_conn_dev_num = 0;
+ btm_cb.ble_ctr_cb.bg_conn_type = BTM_BLE_CONN_NONE;
+ btm_cb.ble_ctr_cb.p_select_cback = NULL;
+ memset(&btm_cb.ble_ctr_cb.bg_conn_dev_list, 0, (sizeof(BD_ADDR)*BTM_BLE_MAX_BG_CONN_DEV_NUM));
+ gatt_reset_bgdev_list();
+#endif
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_continue_reset
+**
+** Description This function is called when wait period expired after
+** device reset or called by the application to continue
+** initialization after the application has completed its
+** vendor specific sequence.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_continue_reset (void)
+{
+
+ /* Reinitialize the default class of device */
+#if BTM_INTERNAL_BB == TRUE
+ btsnd_hcic_read_bd_addr ();
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ btm_pm_reset();
+#endif
+#endif
+
+ btm_get_hci_buf_size ();
+
+ /* default device class */
+ BTM_SetDeviceClass((UINT8 *) BTM_INIT_CLASS_OF_DEVICE);
+
+#if (BTM_MAX_LOC_BD_NAME_LEN > 0) && (BTM_SET_DEV_NAME_UPON_RESET == TRUE)
+ BTM_SetLocalDeviceName(btm_cb.cfg.bd_name);
+#elif BTM_USE_DEF_LOCAL_NAME == TRUE
+ BTM_SetLocalDeviceName(BTM_DEF_LOCAL_NAME);
+#endif
+
+ BTM_SetPinType (btm_cb.cfg.pin_type, btm_cb.cfg.pin_code, btm_cb.cfg.pin_code_len);
+}
+
+/*******************************************************************************
+**
+** Function btm_after_reset_hold_complete
+**
+** Description This function is called when wait period expired after
+** device reset. Continue intitialization
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_after_reset_hold_complete (void)
+{
+#ifdef BTM_APP_DEV_INIT
+ btu_stop_timer(&btm_cb.devcb.reset_timer);
+ BTM_APP_DEV_INIT();
+#else
+ btm_continue_reset();
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function btm_read_hci_buf_size_complete
+**
+** Description This function is called when command complete for
+** get HCI buffer size is received. Start timer and send
+** read local featues request
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_hci_buf_size_complete (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT8 lm_sco_buf_size;
+ UINT16 lm_num_acl_bufs;
+ UINT16 lm_num_sco_bufs;
+ UINT16 acl_buf_size;
+
+ STREAM_TO_UINT8 (status, p);
+ if (status == HCI_SUCCESS)
+ {
+ STREAM_TO_UINT16 (btu_cb.hcit_acl_data_size, p);
+ STREAM_TO_UINT8 (lm_sco_buf_size, p);
+ STREAM_TO_UINT16 (lm_num_acl_bufs, p);
+ STREAM_TO_UINT16 (lm_num_sco_bufs, p);
+
+ btu_cb.hcit_acl_pkt_size = btu_cb.hcit_acl_data_size + HCI_DATA_PREAMBLE_SIZE;
+
+ l2c_link_processs_num_bufs (lm_num_acl_bufs);
+
+#if BTM_ACL_BUF_SIZE > 0
+ acl_buf_size = (BTM_ACL_BUF_SIZE < L2CAP_MTU_SIZE) ? BTM_ACL_BUF_SIZE : L2CAP_MTU_SIZE;
+#else
+ acl_buf_size = L2CAP_MTU_SIZE;
+#endif
+ /* Tell the controller what our buffer sizes are. ?? Need SCO info */
+ btsnd_hcic_set_host_buf_size (acl_buf_size, BTM_SCO_HOST_BUF_SIZE, L2CAP_HOST_FC_ACL_BUFS, 10);
+
+#if L2CAP_HOST_FLOW_CTRL == TRUE
+ btsnd_hcic_set_host_flow_ctrl (HCI_HOST_FLOW_CTRL_ACL_ON);
+#endif
+ }
+
+ /* Set the device into connectable and/or discoverable mode (if configured to do so) */
+#if BTM_IS_CONNECTABLE == TRUE
+ (void) BTM_SetConnectability (BTM_CONNECTABLE, BTM_DEFAULT_CONN_WINDOW, BTM_DEFAULT_CONN_INTERVAL);
+#endif
+
+#if BTM_IS_DISCOVERABLE == TRUE
+ (void) BTM_SetDiscoverability (BTM_DEFAULT_DISC_MODE, BTM_DEFAULT_DISC_WINDOW, BTM_DEFAULT_DISC_INTERVAL);
+#endif
+
+#if BTM_INTERNAL_BB == TRUE
+ {
+ UINT8 buf[9] = BTM_INTERNAL_LOCAL_VER;
+ btm_read_local_version_complete( buf, 9 );
+ }
+#else
+ btm_get_local_version ();
+#endif
+}
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function btm_read_ble_buf_size_complete
+**
+** Description This function is called when command complete for
+** get HCI buffer size is received. Start timer and send
+** read local featues request
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_ble_buf_size_complete (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+ UINT16 lm_num_le_bufs;
+
+ BTM_TRACE_DEBUG0("btm_read_ble_buf_size_complete ");
+ STREAM_TO_UINT8 (status, p);
+ if (status == HCI_SUCCESS)
+ {
+ STREAM_TO_UINT16 (btu_cb.hcit_ble_acl_data_size, p);
+ STREAM_TO_UINT8 (lm_num_le_bufs, p);
+
+ btu_cb.hcit_ble_acl_pkt_size = btu_cb.hcit_ble_acl_data_size + HCI_DATA_PREAMBLE_SIZE;
+
+ l2c_link_processs_ble_num_bufs (lm_num_le_bufs);
+ }
+
+#if BTM_INTERNAL_BB == TRUE
+ {
+ UINT8 buf[9] = BTM_INTERNAL_LOCAL_FEA;
+ btm_read_local_features_complete( buf, 9 );
+ }
+#else
+#ifdef BRCM_VS
+ btm_brcm_feat_init();
+#else
+ /* get local feature if BRCM specific feature is not included */
+ btm_get_local_features ();
+#endif
+#endif
+
+}
+
+/*******************************************************************************
+**
+** Function btm_read_white_list_size_complete
+**
+** Description This function read the current white list size.
+*******************************************************************************/
+void btm_read_white_list_size_complete(UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+
+ BTM_TRACE_DEBUG0("btm_read_white_list_size_complete ");
+ STREAM_TO_UINT8 (status, p);
+
+ if (status == HCI_SUCCESS)
+ {
+ STREAM_TO_UINT8(btm_cb.ble_ctr_cb.max_filter_entries, p);
+ btm_cb.ble_ctr_cb.num_empty_filter = btm_cb.ble_ctr_cb.max_filter_entries;
+ }
+
+ btm_get_ble_buffer_size();
+}
+
+#endif
+/*******************************************************************************
+**
+** Function btm_read_local_version_complete
+**
+** Description This function is called when local BD Addr read complete
+** message is received from the HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_local_version_complete (UINT8 *p, UINT16 evt_len)
+{
+ tBTM_VERSION_INFO *p_vi = &btm_cb.devcb.local_version;
+ UINT8 status;
+
+#ifdef BTA_PRM_CHECK_FW_VER
+ if(BTA_PRM_CHECK_FW_VER(p))
+ return;
+#endif
+
+ STREAM_TO_UINT8 (status, p);
+ if (status == HCI_SUCCESS)
+ {
+
+ STREAM_TO_UINT8 (p_vi->hci_version, p);
+ STREAM_TO_UINT16 (p_vi->hci_revision, p);
+ STREAM_TO_UINT8 (p_vi->lmp_version, p);
+ STREAM_TO_UINT16 (p_vi->manufacturer, p);
+ STREAM_TO_UINT16 (p_vi->lmp_subversion, p);
+ }
+
+#if BLE_INCLUDED == TRUE
+ {
+ btm_read_ble_wl_size();
+ }
+#elif BTM_INTERNAL_BB == TRUE
+ {
+ UINT8 buf[9] = BTM_INTERNAL_LOCAL_FEA;
+ btm_read_local_features_complete( buf, 9 );
+ }
+#else
+#ifdef BRCM_VS
+ btm_brcm_feat_init();
+#else
+ /* get local feature if BRCM specific feature is not included */
+ btm_get_local_features ();
+#endif
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function btm_read_local_features_complete
+**
+** Description This function is called when local features read is complete.
+** This is the last step of the startup sequence.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_local_features_complete (UINT8 *p, UINT16 evt_len)
+{
+ tBTM_DEVCB *p_devcb = &btm_cb.devcb;
+ tBTM_CMPL_CB *p_cb = p_devcb->p_reset_cmpl_cb;
+ UINT8 status;
+ UINT16 xx;
+ UINT8 last;
+ UINT8 first;
+
+ btu_stop_timer (&btm_cb.devcb.reset_timer);
+ /* If there was a callback address for reset complete, call it */
+ p_devcb->p_reset_cmpl_cb = NULL;
+
+ STREAM_TO_UINT8 (status, p);
+ if (status == HCI_SUCCESS)
+ {
+ /* stop guard timer to avoid accidental timeout */
+ btu_stop_timer(&p_devcb->reset_timer);
+
+ p_devcb->state = BTM_DEV_STATE_READY;
+
+ /* Extract features and create "btm_acl_pkt_types_supported" flag
+ */
+ for (xx = 0; xx < HCI_NUM_FEATURE_BYTES; xx++)
+ STREAM_TO_UINT8 (p_devcb->local_features[xx], p);
+
+ /* 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_devcb->local_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_devcb->local_features))
+ btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_DH5 +
+ BTM_ACL_PKT_TYPES_MASK_DM5);
+
+ /* _NO_X_DXX masks are reserved before ver 2.0.
+ Set them only for later versions of controller */
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+
+ /* Add in EDR related ACL types */
+ if (!HCI_EDR_ACL_2MPS_SUPPORTED(p_devcb->local_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_devcb->local_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_devcb->local_features) ||
+ HCI_EDR_ACL_3MPS_SUPPORTED(p_devcb->local_features))
+ {
+ if (!HCI_3_SLOT_EDR_ACL_SUPPORTED(p_devcb->local_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_devcb->local_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_DEBUG1("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_devcb->local_features))
+ {
+ btm_cb.btm_sco_pkt_types_supported = BTM_SCO_PKT_TYPES_MASK_HV1;
+
+ if (HCI_HV2_PACKETS_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_HV2;
+
+ if (HCI_HV3_PACKETS_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_HV3;
+ }
+
+ if (HCI_ESCO_EV3_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_EV3;
+
+ if (HCI_ESCO_EV4_SUPPORTED(p_devcb->local_features))
+ btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_EV4;
+
+ if (HCI_ESCO_EV5_SUPPORTED(p_devcb->local_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_devcb->local_features))
+ {
+ if (!HCI_3_SLOT_EDR_ESCO_SUPPORTED(p_devcb->local_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_devcb->local_features))
+ {
+ if (!HCI_3_SLOT_EDR_ESCO_SUPPORTED(p_devcb->local_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_DEBUG1("Local supported SCO packet types: 0x%04x",
+ btm_cb.btm_sco_pkt_types_supported);
+
+ /* Create Default Policy Settings
+ */
+ if (HCI_SWITCH_SUPPORTED(p_devcb->local_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_devcb->local_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_devcb->local_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_devcb->local_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 802.11 present might have to disable some channels */
+ if (btm_cb.last_disabled_channel != 0xff)
+ {
+ last = btm_cb.last_disabled_channel;
+ first = btm_cb.first_disabled_channel;
+ btm_cb.last_disabled_channel = 0xff;
+ btm_cb.first_disabled_channel = 0xff;
+ BTM_SetAfhChannels(first, last);
+ }
+
+#if ((BTM_EIR_SERVER_INCLUDED == TRUE)||(BTM_EIR_CLIENT_INCLUDED == TRUE))
+ if (HCI_LMP_INQ_RSSI_SUPPORTED(p_devcb->local_features))
+ {
+ if (HCI_EXT_INQ_RSP_SUPPORTED(p_devcb->local_features))
+ BTM_SetInquiryMode (BTM_INQ_RESULT_EXTENDED);
+ else
+ BTM_SetInquiryMode (BTM_INQ_RESULT_WITH_RSSI);
+ }
+#else
+ if (HCI_LMP_INQ_RSSI_SUPPORTED(p_devcb->local_features))
+ BTM_SetInquiryMode (BTM_INQ_RESULT_WITH_RSSI);
+#endif
+#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE
+ if( HCI_NON_FLUSHABLE_PB_SUPPORTED(p_devcb->local_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);
+
+ /* If anyone wants device status notifications, give him one */
+ btm_report_device_status (BTM_DEV_STATUS_UP);
+
+#ifdef BRCM_VS
+ btm_brcm_arc_init();
+#endif
+
+ /* Reset sequence is complete. If this was an application originated */
+ /* reset, tell him its done. */
+ if (p_cb)
+ (*p_cb)((void *) NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_get_voice_coding_support
+**
+** Description This function is provides a way to get the voice coding schemes
+** supported the device.
+**
+** Returns A bit mask - Bit 0 if set indicates CVSD support
+** Bit 1 if set indicates PCM A-law support
+** Bit 2 if set indicates PCM Mu-law support
+**
+*******************************************************************************/
+
+UINT8 btm_get_voice_coding_support( void )
+{
+ UINT8 code = 0;
+
+ if( HCI_LMP_CVSD_SUPPORTED(btm_cb.devcb.local_features) ) code |= 0x01 ;
+ if( HCI_LMP_A_LAW_SUPPORTED(btm_cb.devcb.local_features) ) code |= 0x02 ;
+ if( HCI_LMP_U_LAW_SUPPORTED(btm_cb.devcb.local_features) ) code |= 0x04 ;
+
+ return code ;
+}
+
+/*******************************************************************************
+**
+** 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 BLE_INCLUDED == TRUE && GAP_INCLUDED == TRUE
+ tGAP_BLE_ATTR_VALUE attr_value;
+#endif
+
+ if (!p_name || !p_name[0] || (strlen ((char *)p_name) > BD_NAME_LEN))
+ return (BTM_ILLEGAL_VALUE);
+
+ if (btm_cb.devcb.state == BTM_DEV_STATE_WAIT_RESET_CMPLT ||
+ btm_cb.devcb.state == BTM_DEV_STATE_WAIT_AFTER_RESET)
+ 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, sizeof(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 BLE_INCLUDED == TRUE && GAP_INCLUDED == TRUE
+ attr_value.p_dev_name = (UINT8 *)p_name;
+ GAP_BleAttrDBUpdate(GATT_UUID_GAP_DEVICE_NAME, &attr_value);
+#endif
+
+ if (btsnd_hcic_change_name(p))
+ return (BTM_CMD_STARTED);
+ else
+ 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;
+
+ btu_stop_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_GetLocalDeviceAddr
+**
+** Description This function is called to read the local device address
+**
+** Returns void
+** the local device address is copied into bd_addr
+**
+*******************************************************************************/
+void BTM_GetLocalDeviceAddr (BD_ADDR bd_addr)
+{
+ memcpy (bd_addr, btm_cb.devcb.local_addr, BD_ADDR_LEN);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalDeviceAddr
+**
+** Description This function is called to read the local device address
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadLocalDeviceAddr (tBTM_CMPL_CB *p_cb)
+{
+ if(p_cb)
+ (*p_cb)(btm_cb.devcb.local_addr);
+
+ return (BTM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function btm_read_local_addr_complete
+**
+** Description This function is called when local BD Addr read complete
+** message is received from the HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_local_addr_complete (UINT8 *p, UINT16 evt_len)
+{
+ UINT8 status;
+
+ STREAM_TO_UINT8 (status, p);
+
+ if (status == HCI_SUCCESS)
+ {
+ STREAM_TO_BDADDR (btm_cb.devcb.local_addr, p);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadLocalVersion
+**
+** Description This function is called to read the local device version
+**
+** Returns status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadLocalVersion (tBTM_VERSION_INFO *p_vers)
+{
+ /* Make sure the device has retrieved the info (not being reset) */
+ if (btm_cb.devcb.state < BTM_DEV_STATE_READY)
+ return (BTM_DEV_RESET);
+
+ *p_vers = btm_cb.devcb.local_version;
+
+ return (BTM_SUCCESS);
+}
+
+
+
+
+/*******************************************************************************
+**
+** 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 (btm_cb.devcb.state == BTM_DEV_STATE_WAIT_RESET_CMPLT ||
+ btm_cb.devcb.state == BTM_DEV_STATE_WAIT_AFTER_RESET)
+ 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
+**
+*******************************************************************************/
+UINT8 *BTM_ReadLocalFeatures (void)
+{
+ return (btm_cb.devcb.local_features);
+}
+
+/*******************************************************************************
+**
+** Function BTM_ReadBrcmFeatures
+**
+** Description This function is called to read the Broadcom specific features
+**
+** Returns pointer to the Broadcom features string
+**
+*******************************************************************************/
+UINT8 *BTM_ReadBrcmFeatures (void)
+{
+ return (btm_cb.devcb.brcm_features);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+ void *p_buf;
+
+ BTM_TRACE_EVENT2 ("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 = GKI_getbuf((UINT16)(sizeof(BT_HDR) + sizeof (tBTM_CMPL_CB *) +
+ param_len + HCIC_PREAMBLE_SIZE))) != 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);
+
+}
+
+
+/*******************************************************************************
+**
+** 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)
+{
+ 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 */
+ }
+}
+
+/*******************************************************************************
+**
+** 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_EVENT0("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_EVENT0("BTM Register For VSEvents is successfully");
+ }
+ else
+ {
+ /* No free entries available */
+ BTM_TRACE_ERROR0 ("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;
+
+ BTM_TRACE_DEBUG0 ("BTM Event: Vendor Specific event from controller");
+
+ 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);
+ }
+}
+
+
+/*******************************************************************************
+**
+** 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)
+{
+ BTM_TRACE_EVENT1 ("BTM: BTM_WritePageTimeout: Timeout: %d.", timeout);
+
+ /* Send the HCI command */
+ if (btsnd_hcic_write_page_tout (timeout))
+ return (BTM_SUCCESS);
+ else
+ return (BTM_NO_RESOURCES);
+}
+
+/*******************************************************************************
+**
+** Function BTM_WriteVoiceSettings
+**
+** Description Send HCI Write Voice Settings command.
+** See 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_EVENT1 ("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_EVENT0 ("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 */
+ if (!btsnd_hcic_set_event_mask(LOCAL_BR_EDR_CONTROLLER_ID,
+ (UINT8 *)"\x00\x00\x00\x00\x00\x00\x00\x00"))
+ {
+ return BTM_NO_RESOURCES;
+ }
+
+ /* Send the HCI command */
+ if (btsnd_hcic_enable_test_mode ())
+ return (BTM_SUCCESS);
+ else
+ return (BTM_NO_RESOURCES);
+}
+
+/*******************************************************************************
+**
+** Function btm_get_hci_version
+**
+** Description Local function called to retrieve the current HCI version
+**
+** Returns Bluetooth HCI Version returned by the controller
+**
+*******************************************************************************/
+UINT8 btm_get_hci_version (void)
+{
+ return (btm_cb.devcb.local_version.hci_version);
+}
+
+
+
+/*******************************************************************************
+**
+** Function BTM_ReadStoredLinkKey
+**
+** Description This function is called to obtain link key for the specified
+** device from the NVRAM storage attached to the Bluetooth
+** controller.
+**
+** Parameters: bd_addr - Address of the device
+** p_cb - Call back function to be called to return
+** the results
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadStoredLinkKey (BD_ADDR bd_addr, tBTM_CMPL_CB *p_cb)
+{
+ BD_ADDR local_bd_addr;
+ BOOLEAN read_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 read all the link keys */
+ read_all_flag = TRUE;
+
+ /* We don't care the BD address. Just pass a non zero pointer */
+ bd_addr = local_bd_addr;
+ }
+
+ BTM_TRACE_EVENT1 ("BTM: BTM_ReadStoredLinkKey: Read_All: %s",
+ read_all_flag ? "TRUE" : "FALSE");
+
+ /* Send the HCI command */
+ btm_cb.devcb.p_stored_link_key_cmpl_cb = p_cb;
+ if (btsnd_hcic_read_stored_key (bd_addr, read_all_flag))
+ return (BTM_SUCCESS);
+ else
+ return (BTM_NO_RESOURCES);
+
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_WriteStoredLinkKey
+**
+** Description This function is called to write link keys for the specified
+** device addresses to the NVRAM storage attached to the Bluetooth
+** controller.
+**
+** Parameters: num_keys - Number of link keys
+** bd_addr - Addresses of the devices
+** link_key - Link Keys to be stored
+** p_cb - Call back function to be called to return
+** the results
+**
+*******************************************************************************/
+tBTM_STATUS BTM_WriteStoredLinkKey (UINT8 num_keys,
+ BD_ADDR *bd_addr,
+ LINK_KEY *link_key,
+ tBTM_CMPL_CB *p_cb)
+{
+ /* Check if the previous command is completed */
+ if (btm_cb.devcb.p_stored_link_key_cmpl_cb)
+ return (BTM_BUSY);
+
+ BTM_TRACE_EVENT1 ("BTM: BTM_WriteStoredLinkKey: num_keys: %d", num_keys);
+
+ /* Check the maximum number of link keys */
+ if(num_keys > HCI_MAX_NUM_OF_LINK_KEYS_PER_CMMD)
+ num_keys = HCI_MAX_NUM_OF_LINK_KEYS_PER_CMMD;
+
+ /* Send the HCI command */
+ btm_cb.devcb.p_stored_link_key_cmpl_cb = p_cb;
+ if (btsnd_hcic_write_stored_key (num_keys, bd_addr, link_key))
+ 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;
+ 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_EVENT1 ("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_read_stored_link_key_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the read stored link key command.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_read_stored_link_key_complete (UINT8 *p)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_stored_link_key_cmpl_cb;
+ tBTM_READ_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_READ_STORED_LINK_KEYS;
+
+ /* Extract the result fields from the HCI event if status is success */
+ STREAM_TO_UINT8 (result.status, p);
+ if (result.status == HCI_SUCCESS)
+ {
+ STREAM_TO_UINT16 (result.max_keys, p);
+ STREAM_TO_UINT16 (result.read_keys, p);
+ }
+ else
+ {
+ BTM_TRACE_WARNING1("Read stored link key status %d", result.status);
+ result.max_keys = 0;
+ result.read_keys = 0;
+ }
+ /* Call the call back and pass the result */
+ (*p_cb)(&result);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_write_stored_link_key_complete
+**
+** Description This function is called when the command complete message
+** is received from the HCI for the write stored link key command.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_write_stored_link_key_complete (UINT8 *p)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_stored_link_key_cmpl_cb;
+ tBTM_WRITE_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_WRITE_STORED_LINK_KEYS;
+
+ /* Extract the result fields from the HCI event */
+ STREAM_TO_UINT8 (result.status, p);
+ STREAM_TO_UINT8 (result.num_keys, p);
+
+ /* Call the call back and pass the result */
+ (*p_cb)(&result);
+ }
+}
+
+
+/*******************************************************************************
+**
+** 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_return_link_keys_evt
+**
+** Description This function is called when the return link keys event
+** is received from the HCI for the read stored link key command.
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_return_link_keys_evt (tBTM_RETURN_LINK_KEYS_EVT *result)
+{
+ tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_stored_link_key_cmpl_cb;
+ UINT8 i, *p, *p1;
+ UINT8 bd_addr[BD_ADDR_LEN];
+ UINT8 link_key[LINK_KEY_LEN];
+
+ /* Call the call back to pass the link keys to application */
+ if (p_cb)
+ {
+ /* Change the BD addr and Link key in to big endian order */
+ p = (UINT8 *)(result + 1);
+ for (i=0; i<result->num_keys; i++)
+ {
+ /* Initialize the backup pointer */
+ p1 = p;
+
+ /* Extract the BD Addr and Link Key */
+ REVERSE_STREAM_TO_ARRAY(bd_addr, p1, BD_ADDR_LEN);
+ REVERSE_STREAM_TO_ARRAY(link_key, p1, LINK_KEY_LEN);
+
+ /* Write the BD Addr and Link Key back in big endian format */
+ ARRAY_TO_STREAM(p, bd_addr, BD_ADDR_LEN);
+ ARRAY_TO_STREAM(p, link_key, LINK_KEY_LEN);
+ }
+
+ (*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);
+}
+
+
diff --git a/stack/btm/btm_inq.c b/stack/btm/btm_inq.c
new file mode 100644
index 0000000..5598562
--- /dev/null
+++ b/stack/btm/btm_inq.c
@@ -0,0 +1,3265 @@
+/******************************************************************************
+ *
+ * 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 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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "bt_types.h"
+#include "gki.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "hcidefs.h"
+
+#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 (( BTM_EIR_CLIENT_INCLUDED == TRUE )||( BTM_EIR_SERVER_INCLUDED == TRUE ))
+#ifndef BTM_EIR_UUID_LKUP_TBL
+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
+/*
+If customized UUID look-up table needs to be used,
+the followings should be defined in bdroid_buildcfg.h.
+BTM_EIR_UUID_LKUP_TBL = <customized UUID list>
+BTM_EIR_MAX_SERVICES = <number of UUID in list>
+*/
+#if (BTM_EIR_MAX_SERVICES == 0)
+const UINT16 BTM_EIR_UUID_LKUP_TBL[];
+#else
+extern UINT16 BTM_EIR_UUID_LKUP_TBL[BTM_EIR_MAX_SERVICES];
+#endif
+#endif
+#endif /* BTM_EIR_UUID_LKUP_TBL*/
+
+/********************************************************************************/
+/* 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);
+
+#if ((BTM_EIR_SERVER_INCLUDED == TRUE)||(BTM_EIR_CLIENT_INCLUDED == TRUE))
+static UINT8 btm_convert_uuid_to_eir_service( UINT16 uuid16 );
+#endif
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+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 );
+#endif
+
+/*******************************************************************************
+**
+** 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_API0 ("BTM_SetDiscoverability");
+#if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE)
+ if (btm_ble_set_discoverability((UINT16)(inq_mode))
+ == BTM_SUCCESS)
+ {
+ btm_cb.btm_inq_vars.discoverable_mode &= (~BTM_BLE_DISCOVERABLE_MASK);
+ btm_cb.btm_inq_vars.discoverable_mode |= (inq_mode & BTM_BLE_CONNECTABLE_MASK);
+ }
+ inq_mode &= ~BTM_BLE_DISCOVERABLE_MASK;
+#endif
+
+ /*** Check mode parameter ***/
+ if (inq_mode > BTM_MAX_DISCOVERABLE)
+ return (BTM_ILLEGAL_VALUE);
+
+ /* Make sure the controller is active */
+ if (btm_cb.devcb.state < BTM_DEV_STATE_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_API3 ("BTM_SetDiscoverability: mode %d [NonDisc-0, Lim-1, Gen-2], window 0x%04x, interval 0x%04x",
+ 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_API0 ("BTM_SetInquiryScanType");
+ 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 (!HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(btm_cb.devcb.local_features))
+ 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_API0 ("BTM_SetPageScanType");
+ 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 (!HCI_LMP_INTERLACED_PAGE_SCAN_SUPPORTED(btm_cb.devcb.local_features))
+ 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)
+{
+ BTM_TRACE_API0 ("BTM_SetInquiryMode");
+ if (mode == BTM_INQ_RESULT_STANDARD)
+ {
+ /* mandatory mode */
+ }
+ else if (mode == BTM_INQ_RESULT_WITH_RSSI)
+ {
+ if (!HCI_LMP_INQ_RSSI_SUPPORTED(btm_cb.devcb.local_features))
+ return (BTM_MODE_UNSUPPORTED);
+ }
+#if (( BTM_EIR_CLIENT_INCLUDED == TRUE )||( BTM_EIR_SERVER_INCLUDED == TRUE ))
+ else if (mode == BTM_INQ_RESULT_EXTENDED)
+ {
+ if (!HCI_EXT_INQ_RSP_SUPPORTED(btm_cb.devcb.local_features))
+ return (BTM_MODE_UNSUPPORTED);
+ }
+#endif
+ 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_API0 ("BTM_ReadDiscoverability");
+ 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_API6 ("BTM_SetPeriodicInquiryMode: mode: %d, dur: %d, rsps: %d, flt: %d, min: %d, max: %d",
+ 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)
+ {
+ 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 (defined(BTM_BYPASS_EVENT_FILTERING) && BTM_BYPASS_EVENT_FILTERING == TRUE)
+ BTM_TRACE_WARNING0("BTM: Bypassing event filtering...");
+
+ p_inq->state = BTM_INQ_ACTIVE_STATE;
+ p_inq->inqfilt_active = FALSE;
+ btm_initiate_inquiry (p_inq);
+ status = BTM_CMD_STARTED;
+#else
+ /* 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;
+
+ }
+
+#endif
+ 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_API0 ("BTM_CancelPeriodicInquiry called");
+
+ /*** 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_API0 ("BTM_SetConnectability");
+
+#if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE)
+ if (btm_ble_set_connectability(page_mode) == BTM_SUCCESS)
+ {
+ p_inq->connectable_mode &= (~BTM_BLE_CONNECTABLE_MASK);
+ p_inq->connectable_mode |= (page_mode & BTM_BLE_CONNECTABLE_MASK);
+ }
+ page_mode &= ~BTM_BLE_CONNECTABLE_MASK;
+
+#endif
+
+ /*** Check mode parameter ***/
+ if (page_mode != BTM_NON_CONNECTABLE && page_mode != BTM_CONNECTABLE)
+ return (BTM_ILLEGAL_VALUE);
+
+ /* Make sure the controller is active */
+ if (btm_cb.devcb.state < BTM_DEV_STATE_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_API3 ("BTM_SetConnectability: mode %d [NonConn-0, Conn-1], window 0x%04x, interval 0x%04x",
+ 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_API0 ("BTM_ReadConnectability");
+ 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_API0 ("BTM_IsInquiryActive");
+
+ 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;
+
+ BTM_TRACE_API0 ("BTM_CancelInquiry called");
+
+ /*** 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 &&
+ (!(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 (!btsnd_hcic_inq_cancel())
+ status = BTM_NO_RESOURCES;
+#if BLE_INCLUDED == TRUE
+ if ((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0)
+ btm_ble_stop_scan();
+#endif
+ }
+
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ /* 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);
+ */
+#endif
+
+ 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
+** 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;
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ BTM_TRACE_API4 ("BTM_StartInquiry: mode: %d, dur: %d, rsps: %d, flt: %d",
+ 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)
+ return (BTM_BUSY);
+
+ /*** 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)
+ 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;
+#if (BLE_INCLUDED == TRUE)
+ p_inq->inqparms.mode = (UINT8)(p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) | (UINT8)(1 << (p_inqparms->mode & BTM_BR_INQUIRY_MASK));
+#else
+ p_inq->inqparms.mode = (UINT8)(1 << (p_inqparms->mode & BTM_BR_INQUIRY_MASK));
+#endif
+
+ /* 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 = (UINT8)(1 << (p_inqparms->mode & BTM_BR_INQUIRY_MASK));
+
+ BTM_TRACE_DEBUG1("BTM_StartInquiry: p_inq->inq_active = 0x%02x", p_inq->inq_active);
+
+/* start LE inquiry here if requested */
+#if BLE_INCLUDED == TRUE
+ if (p_inqparms->mode & BTM_BLE_INQUIRY_MASK)
+ {
+ /* BLE for now does not support filter condition for inquiry */
+ if (btm_ble_start_inquiry((UINT8)(p_inqparms->mode & BTM_BLE_INQUIRY_MASK),
+ p_inq->inqparms.duration) != BTM_SUCCESS)
+ {
+ BTM_TRACE_ERROR0("Err Starting LE Inquiry.");
+ p_inq->inqparms.mode &= ~ BTM_BLE_INQUIRY_MASK;
+ }
+
+ p_inqparms->mode &= ~BTM_BLE_INQUIRY_MASK;
+
+ BTM_TRACE_DEBUG1("BTM_StartInquiry: mode = %02x", p_inqparms->mode);
+ }
+#endif /* end of BLE_INCLUDED */
+
+#if (defined(BTM_BYPASS_EVENT_FILTERING) && BTM_BYPASS_EVENT_FILTERING == TRUE)
+ BTM_TRACE_WARNING0("BTM: Bypassing event filtering...");
+ p_inq->inqfilt_active = FALSE;
+ btm_initiate_inquiry (p_inq);
+ status = BTM_CMD_STARTED;
+#else
+ /* 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;
+#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)
+{
+ tBTM_INQ_INFO *p_cur = NULL;
+ tINQ_DB_ENT *p_i;
+
+#if BLE_INCLUDED == TRUE
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type;
+#endif
+
+ BTM_TRACE_API6 ("BTM_ReadRemoteDeviceName: bd addr [%02x%02x%02x%02x%02x%02x]",
+ 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;
+
+#if (BTM_INQ_GET_REMOTE_NAME == TRUE)
+ p_cur->remote_name_state = BTM_INQ_RMT_NAME_EMPTY;
+#endif
+ }
+ BTM_TRACE_API0 ("no device found in inquiry db");
+
+#if (BLE_INCLUDED == TRUE)
+ BTM_ReadDevInfo(remote_bda, &dev_type, &addr_type);
+ if (dev_type == BT_DEVICE_TYPE_BLE)
+ {
+ 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;
+
+#if BLE_INCLUDED == TRUE
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type;
+#endif
+
+ BTM_TRACE_API0 ("BTM_CancelRemoteDeviceName()");
+
+ /* Make sure there is not already one in progress */
+ if (p_inq->remname_active)
+ {
+#if BLE_INCLUDED == TRUE
+ BTM_ReadDevInfo(p_inq->remname_bda, &dev_type, &addr_type);
+ if (dev_type == BT_DEVICE_TYPE_BLE)
+ {
+ 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_InqFirstResult
+**
+** Description This function looks through the inquiry database for the first
+** used entrysince the LAST inquiry. This is used in conjunction
+** with BTM_InqNext by applications as a way to walk through the
+** inquiry results database.
+**
+** Returns pointer to first in-use entry, or NULL if DB is empty
+**
+*******************************************************************************/
+tBTM_INQ_INFO *BTM_InqFirstResult (void)
+{
+ UINT16 xx;
+ tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db;
+ UINT32 cur_inq_count = btm_cb.btm_inq_vars.inq_counter - 1;
+
+ for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++)
+ {
+ if (p_ent->in_use && p_ent->inq_count == cur_inq_count)
+ return (&p_ent->inq_info);
+ }
+
+ /* If here, no used entry found */
+ return ((tBTM_INQ_INFO *)NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_InqNextResult
+**
+** Description This function looks through the inquiry database for the next
+** used entrysince the LAST inquiry. 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_InqNextResult (tBTM_INQ_INFO *p_cur)
+{
+ tINQ_DB_ENT *p_ent;
+ UINT16 inx;
+ UINT32 cur_inq_count = btm_cb.btm_inq_vars.inq_counter - 1;
+
+ 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 && p_ent->inq_count == cur_inq_count)
+ return (&p_ent->inq_info);
+ }
+
+ /* If here, more entries found */
+ return ((tBTM_INQ_INFO *)NULL);
+ }
+ else
+ return (BTM_InqDbFirst());
+}
+
+
+/*******************************************************************************
+**
+** 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)
+{
+ UINT16 xx;
+ tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db;
+
+ BTM_TRACE_API6 ("BTM_InqDbRead: bd addr [%02x%02x%02x%02x%02x%02x]",
+ p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
+
+ 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->inq_info);
+ }
+
+ /* If here, not found */
+ return ((tBTM_INQ_INFO *)NULL);
+}
+
+
+/*******************************************************************************
+**
+** 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_ReadNumInqDbEntries
+**
+** Returns This function returns the number of entries in the inquiry database.
+**
+*******************************************************************************/
+UINT8 BTM_ReadNumInqDbEntries (void)
+{
+ UINT8 num_entries;
+ UINT8 num_results;
+ tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db;
+
+ for (num_entries = 0, num_results = 0; num_entries < BTM_INQ_DB_SIZE; num_entries++, p_ent++)
+ {
+ if (p_ent->in_use)
+ num_results++;
+ }
+
+ return (num_results);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_InquiryRegisterForChanges
+**
+** Returns This function is called to register a callback for when the
+** inquiry database changes, i.e. new entry or entry deleted.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_InquiryRegisterForChanges (tBTM_INQ_DB_CHANGE_CB *p_cb)
+{
+ if (!p_cb)
+ btm_cb.btm_inq_vars.p_inq_change_cb = NULL;
+ else if (btm_cb.btm_inq_vars.p_inq_change_cb)
+ return (BTM_BUSY);
+ else
+ btm_cb.btm_inq_vars.p_inq_change_cb = p_cb;
+
+ return (BTM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SetInquiryFilterCallback
+**
+** Description Host can register to be asked whenever an inquiry result
+** is received. If host does not like the device no name
+** request is issued for the device
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_SetInquiryFilterCallback (tBTM_FILTER_CB *p_callback)
+{
+ btm_cb.p_inq_filter_cb = p_callback;
+}
+
+/*******************************************************************************
+**
+** 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);
+}
+/*******************************************************************************
+**
+** Function BTM_WriteInquiryTxPower
+**
+** Description This command is used to write the inquiry transmit power level
+** used to transmit the inquiry (ID) data packets. The Controller
+** should use the supported TX power level closest to the Tx_Power
+** parameter.
+**
+** Returns BTM_SUCCESS if successful
+**
+*******************************************************************************/
+tBTM_STATUS BTM_WriteInquiryTxPower (INT8 tx_power)
+{
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ if (tx_power < BTM_MIN_INQ_TX_POWER || tx_power > BTM_MAX_INQ_TX_POWER)
+ {
+ status = BTM_ILLEGAL_VALUE;
+ }
+ else if (!btsnd_hcic_write_inq_tx_power(tx_power))
+ status = BTM_NO_RESOURCES;
+
+ return status;
+}
+/*********************************************************************************
+**********************************************************************************
+** **
+** 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
+ 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_DEBUG4 ("btm_inq_stop_on_ssp: no_inc_ssp=%d inq_active:0x%x state:%d inqfilt_active:%d",
+ 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_DEBUG2 ("btm_clr_inq_db: inq_active:0x%x state:%d",
+ 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_GET_REMOTE_NAME == TRUE)
+ p_ent->inq_info.remote_name_state = BTM_INQ_RMT_NAME_EMPTY;
+#endif
+
+ if (btm_cb.btm_inq_vars.p_inq_change_cb)
+ (*btm_cb.btm_inq_vars.p_inq_change_cb) (&p_ent->inq_info, FALSE);
+ }
+ }
+ }
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG2 ("inq_active:0x%x state:%d",
+ 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)
+{
+#if BTM_USE_INQ_RESULTS_FILTER == TRUE
+ tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+ if (p_inq->p_bd_db)
+ {
+ GKI_freebuf(p_inq->p_bd_db);
+ p_inq->p_bd_db = NULL;
+ }
+ p_inq->num_bd_entries = 0;
+ p_inq->max_bd_entries = 0;
+#endif
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+#if BTM_USE_INQ_RESULTS_FILTER == TRUE
+ 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++;
+ }
+
+#endif
+ /* 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;
+
+#if (BTM_INQ_GET_REMOTE_NAME==TRUE)
+ p_ent->inq_info.remote_name_state = BTM_INQ_RMT_NAME_EMPTY;
+#endif
+
+ 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. */
+
+ /* Before deleting the oldest, if anyone is registered for change */
+ /* notifications, then tell him we are deleting an entry. */
+ if (btm_cb.btm_inq_vars.p_inq_change_cb)
+ (*btm_cb.btm_inq_vars.p_inq_change_cb) (&p_old->inq_info, FALSE);
+
+ 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;
+
+#if (BTM_INQ_GET_REMOTE_NAME==TRUE)
+ p_old->inq_info.remote_name_state = BTM_INQ_RMT_NAME_EMPTY;
+#endif
+
+ 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_DEBUG1 ("btm_set_inq_event_filter: filter type %d [Clear-0, COD-1, BDADDR-2]",
+ filter_cond_type);
+ BTM_TRACE_DEBUG6 (" condition [%02x%02x%02x %02x%02x%02x]",
+ 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_DEBUG3 ("btm_event_filter_complete: inq_active:0x%x state:%d inqfilt_active:%d",
+ 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_WARNING1 ("BTM Warning: Set Event Filter Failed (HCI returned 0x%x)", 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_DEBUG3 ("btm_initiate_inquiry: inq_active:0x%x state:%d inqfilt_active:%d",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ btm_acl_update_busy_level (BTM_BLI_INQ_EVT);
+#endif
+
+ 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
+ {
+#if BTM_USE_INQ_RESULTS_FILTER == TRUE
+ btm_clr_inq_result_flt();
+
+ /* Allocate memory to hold bd_addrs responding */
+ if ((p_inq->p_bd_db = (tINQ_BDADDR *)GKI_getbuf(GKI_MAX_BUF_SIZE)) != NULL)
+ {
+ p_inq->max_bd_entries = (UINT16)(GKI_MAX_BUF_SIZE / sizeof(tINQ_BDADDR));
+ memset(p_inq->p_bd_db, 0, GKI_MAX_BUF_SIZE);
+/* BTM_TRACE_DEBUG1("btm_initiate_inquiry: memory allocated for %d bdaddrs",
+ p_inq->max_bd_entries); */
+ }
+
+ if (!btsnd_hcic_inquiry(*lap, p_inqparms->duration, 0))
+#else
+ if (!btsnd_hcic_inquiry(*lap, p_inqparms->duration, p_inqparms->max_resps))
+#endif /* BTM_USE_INQ_RESULTS_FILTER */
+ 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;
+ 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;
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+ UINT8 *p_eir_data = NULL;
+#if (BTM_INQ_GET_REMOTE_NAME==TRUE)
+ UINT8 remote_name_len;
+#endif
+#endif
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG3 ("btm_process_inq_results inq_active:0x%x state:%d inqfilt_active:%d",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+ /* Only process the results if the inquiry is still active */
+ if (!p_inq->inq_active)
+ 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);
+
+#if BTM_USE_INQ_RESULTS_FILTER == TRUE
+ /* 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_WARNING0("INQ RES: Extra Response Received...ignoring"); */
+ return;
+ }
+#endif
+
+ /* Check if this address has already been processed for this inquiry */
+ if (btm_inq_find_bdaddr(bda))
+ {
+/* BTM_TRACE_DEBUG6("BDA seen before [%02x%02x %02x%02x %02x%02x]",
+ 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_DEBUG2("update RSSI new:%d, old:%d", 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;
+ }
+
+ /* Host can be registered to verify comming BDA or DC */
+ if (btm_cb.p_inq_filter_cb)
+ {
+ if (!(* btm_cb.p_inq_filter_cb) (bda, dc))
+ {
+ 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 = GKI_get_tick_count ();
+
+ 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 BTM_USE_INQ_RESULTS_FILTER == TRUE
+ /* 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_DEBUG0("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_scan();
+#endif
+
+
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);
+#endif
+ }
+#endif
+ /* 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 (BTM_INQ_GET_REMOTE_NAME==TRUE)
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+ if( inq_res_mode == BTM_INQ_RESULT_EXTENDED )
+ {
+ if((p_eir_data = BTM_CheckEirData( p, BTM_EIR_COMPLETE_LOCAL_NAME_TYPE,
+ &remote_name_len )) == NULL)
+ {
+ p_eir_data = BTM_CheckEirData( p, BTM_EIR_SHORTENED_LOCAL_NAME_TYPE,
+ &remote_name_len );
+ }
+
+ if( p_eir_data )
+ {
+ if( remote_name_len > BTM_MAX_REM_BD_NAME_LEN )
+ remote_name_len = BTM_MAX_REM_BD_NAME_LEN;
+
+ p_i->inq_info.remote_name_len = remote_name_len;
+ memcpy( p_i->inq_info.remote_name, p_eir_data, p_i->inq_info.remote_name_len );
+ p_i->inq_info.remote_name[p_i->inq_info.remote_name_len] = 0;
+ p_i->inq_info.remote_name_state = BTM_INQ_RMT_NAME_DONE;
+ }
+ else
+ p_i->inq_info.remote_name_state = BTM_INQ_RMT_NAME_EMPTY;
+ }
+ else
+#endif
+ {
+ /* Clear out the device name so that it can be re-read */
+ p_i->inq_info.remote_name_state = BTM_INQ_RMT_NAME_EMPTY;
+ }
+#endif /*(BTM_INQ_GET_REMOTE_NAME==TRUE)*/
+
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+ 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;
+#endif
+
+ /* If a callback is registered, call it with the results */
+ if (p_inq_results_cb)
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+ (p_inq_results_cb)((tBTM_INQ_RESULTS *) p_cur, p_eir_data);
+#else
+ (p_inq_results_cb)((tBTM_INQ_RESULTS *) p_cur, NULL);
+#endif
+
+ /* If anyone is registered for change notifications, then tell him we added an entry. */
+ if (p_inq->p_inq_change_cb)
+ (*p_inq->p_inq_change_cb) (&p_i->inq_info, TRUE);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** 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 *)GKI_getbuf(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);
+ }
+ }
+ }
+
+ GKI_freebuf(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 (BTM_INQ_GET_REMOTE_NAME==TRUE)
+ tBTM_INQ_INFO *p_cur;
+ UINT8 tempstate;
+#endif
+
+ p_inq->inqparms.mode &= ~(mode);
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG3 ("btm_process_inq_complete inq_active:0x%x state:%d inqfilt_active:%d",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);
+#endif
+ /* 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);
+
+#if (BTM_INQ_GET_REMOTE_NAME==TRUE)
+ if (p_inq->inq_cmpl_info.status == BTM_SUCCESS)
+ {
+ for (p_cur = BTM_InqDbFirst(); p_cur; p_cur = BTM_InqDbNext (p_cur))
+ {
+ if (p_cur->remote_name_state == BTM_INQ_RMT_NAME_EMPTY)
+ {
+ tempstate = p_cur->remote_name_state;
+ p_cur->remote_name_state = BTM_INQ_RMT_NAME_PENDING;
+
+ if (btm_initiate_rem_name (p_cur->results.remote_bd_addr,
+ p_cur, BTM_RMT_NAME_INQ,
+ BTM_INQ_RMT_NAME_TIMEOUT, NULL) != BTM_CMD_STARTED)
+ p_cur->remote_name_state = tempstate;
+ else
+ return;
+ }
+ }
+ }
+#endif
+
+ /* 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)
+ {
+ 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) && HCI_LMP_INQ_RSSI_SUPPORTED(btm_cb.devcb.local_features))
+ {
+ 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_DEBUG2 ("BTM Inq Compl Callback: status 0x%02x, num results %d",
+ 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 (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG3 ("inq_active:0x%x state:%d inqfilt_active:%d",
+ 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)
+{
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ btm_acl_update_busy_level (BTM_BLI_INQ_CANCEL_EVT);
+#endif
+ 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;
+ }
+ }
+ /* If the inquire feature is on */
+#if (BTM_INQ_GET_REMOTE_NAME==TRUE)
+
+ else if (origin == BTM_RMT_NAME_INQ)
+ {
+ /* 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
+ {
+ cmd_ok = FALSE
+ }
+
+ if (cmd_ok)
+ return BTM_CMD_STARTED;
+ else
+ return BTM_NO_RESOURCES;
+ }
+#endif
+ 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 = {0};
+ 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 (BTM_INQ_GET_REMOTE_NAME==TRUE)
+ /*** These are only used if part of the Inquiry Process ***/
+ tBTM_CMPL_CB *p_inq_cb;
+ tINQ_DB_ENT *p_i = NULL;
+ UINT8 *p_n;
+ tBTM_INQ_INFO *p_cur;
+#endif
+#if BLE_INCLUDED == TRUE
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type;
+#endif
+
+
+ if (bda != NULL)
+ {
+ BTM_TRACE_EVENT6("BDA %02x:%02x:%02x:%02x:%02x:%02x",bda[0], bda[1],
+ bda[2], bda[3],
+ bda[4], bda[5]);
+ }
+
+ BTM_TRACE_EVENT6("Inquire BDA %02x:%02x:%02x:%02x:%02x:%02x",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
+ BTM_ReadDevInfo(p_inq->remname_bda, &dev_type, &addr_type);
+ if (dev_type == BT_DEVICE_TYPE_BLE)
+ {
+ 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.status = BTM_SUCCESS;
+ temp_evt_len = rem_name.length;
+
+ while (temp_evt_len > 0)
+ {
+ *p_n1++ = *bdn++;
+ temp_evt_len--;
+ }
+ }
+
+
+ /* 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;
+ }
+ /* 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);
+ }
+
+
+#if (BTM_INQ_GET_REMOTE_NAME==TRUE)
+ /* If existing entry, update the name */
+ if ((bda != NULL) && ((p_i = btm_inq_db_find (bda)) != NULL)
+ && (hci_status == HCI_SUCCESS))
+ {
+ p_i->inq_info.remote_name_state = BTM_INQ_RMT_NAME_DONE;
+ p_n = p_i->inq_info.remote_name;
+ memset(p_n, 0, BTM_MAX_REM_BD_NAME_LEN + 1);
+ p_i->inq_info.remote_name_len = (rem_name.length < BTM_MAX_REM_BD_NAME_LEN) ?
+ rem_name.length : BTM_MAX_REM_BD_NAME_LEN;
+ evt_len = p_i->inq_info.remote_name_len;
+ p_n1 = (UINT8 *)rem_name.remote_bd_name;
+ while (evt_len > 0)
+ {
+ *p_n++ = *p_n1++;
+ evt_len--;
+ }
+
+ if (btm_cb.btm_inq_vars.p_inq_change_cb)
+ (*btm_cb.btm_inq_vars.p_inq_change_cb) (&p_i->inq_info, TRUE);
+ }
+ else
+ {
+ if (p_i)
+ p_i->inq_info.remote_name_state = BTM_INQ_RMT_NAME_FAILED;
+ else
+ {
+ /* Find the entry which is currently doing name request */
+ for (p_cur = BTM_InqDbFirst(); p_cur; p_cur = BTM_InqDbNext (p_cur))
+ {
+ if (p_cur->remote_name_state == BTM_INQ_RMT_NAME_PENDING)
+ {
+ /* Should be only one */
+ p_cur->remote_name_state = BTM_INQ_RMT_NAME_FAILED;
+ break;
+ }
+ }
+ }
+ }
+
+ /* If an inquiry is in progress then update other entries */
+ if (p_inq->inq_active)
+ {
+ /* Check if there are any more entries inquired but not named */
+ for (p_cur = BTM_InqDbFirst(); p_cur; p_cur = BTM_InqDbNext (p_cur))
+ {
+ if (p_cur->remote_name_state == BTM_INQ_RMT_NAME_EMPTY)
+ {
+ p_cur->remote_name_state = BTM_INQ_RMT_NAME_PENDING;
+#if (BLE_INCLUDED == TRUE)
+ BTM_ReadDevInfo(remote_bda, &dev_type, &addr_type);
+ if (dev_type == BT_DEVICE_TYPE_BLE)
+ {
+ if (btm_ble_read_remote_name(remote_bda, p_cur, p_cb) != BTM_CMD_STARTED)
+ p_cur->remote_name_state = BTM_INQ_RMT_NAME_FAILED;
+ else
+ return;
+ }
+ else
+#endif
+ {
+ if (btm_initiate_rem_name (p_cur->results.remote_bd_addr,
+ p_cur, BTM_RMT_NAME_INQ,
+ BTM_INQ_RMT_NAME_TIMEOUT, NULL) != BTM_CMD_STARTED)
+ p_cur->remote_name_state = BTM_INQ_RMT_NAME_FAILED;
+ else
+ return;
+ }
+ }
+ }
+
+ /* The inquiry has finished so call the callback for the inquiry */
+ p_inq_cb = p_inq->p_inq_cmpl_cb;
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+ p_inq->p_inq_cmpl_cb = NULL;
+
+ /* If we have a callback registered for inquiry complete, call it */
+ if (p_inq_cb)
+ (p_inq_cb)((tBTM_INQUIRY_CMPL *) &p_inq->inq_cmpl_info);
+
+ /* In some cases we can not get name of the device once but will be */
+ /* able to do it next time. Until we have better solution we will */
+ /* try to get name every time */
+ for (p_cur = BTM_InqDbFirst(); p_cur; p_cur = BTM_InqDbNext (p_cur))
+ {
+ if (p_cur->remote_name_state == BTM_INQ_RMT_NAME_FAILED)
+ p_cur->remote_name_state = BTM_INQ_RMT_NAME_EMPTY;
+ }
+ }
+#endif /* BTM_INQ_GET_REMOTE_NAME == TRUE */
+}
+
+/*******************************************************************************
+**
+** 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_ERROR1 ("btm_inq_rmt_name_failed() remname_active=%d", 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);
+
+ btm_sec_rmt_name_request_complete (NULL, NULL, HCI_ERR_UNSPECIFIED);
+}
+/*******************************************************************************
+**
+** 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_EVENT2 ("BTM INQ TX POWER Complete: tx_power %d, hci status 0x%02x",
+ 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
+**
+** Returns BTM_SUCCESS - if successful
+** BTM_MODE_UNSUPPORTED - if local device cannot support it
+**
+*******************************************************************************/
+tBTM_STATUS BTM_WriteEIR( BT_HDR *p_buff )
+{
+#if (BTM_EIR_SERVER_INCLUDED == TRUE)
+ if (HCI_EXT_INQ_RSP_SUPPORTED(btm_cb.devcb.local_features))
+ {
+ BTM_TRACE_API0("Write Extended Inquiry Response to controller");
+ btsnd_hcic_write_ext_inquiry_response (p_buff, BTM_EIR_DEFAULT_FEC_REQUIRED);
+ return BTM_SUCCESS;
+ }
+ else
+ {
+ GKI_freebuf(p_buff);
+ return BTM_MODE_UNSUPPORTED;
+ }
+#else
+ GKI_freebuf(p_buff);
+ return BTM_SUCCESS;
+#endif
+}
+
+/*******************************************************************************
+**
+** 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 )
+{
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+ UINT8 *p = p_eir;
+ UINT8 length;
+ UINT8 eir_type;
+ BTM_TRACE_API1("BTM_CheckEirData type=0x%02X", 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;
+#else
+ return NULL;
+#endif
+}
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+#if (( BTM_EIR_CLIENT_INCLUDED == TRUE )||( BTM_EIR_SERVER_INCLUDED == TRUE ))
+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;
+}
+#endif
+
+/*******************************************************************************
+**
+** 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 )
+{
+#if ((BTM_EIR_SERVER_INCLUDED == TRUE)||(BTM_EIR_CLIENT_INCLUDED == TRUE))
+ 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 );
+#else
+ return( FALSE );
+#endif
+}
+
+/*******************************************************************************
+**
+** 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_EIR_SERVER_INCLUDED == TRUE)||(BTM_EIR_CLIENT_INCLUDED == TRUE))
+ 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;
+#else
+ return BTM_EIR_UNKNOWN;
+#endif
+}
+
+/*******************************************************************************
+**
+** 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 )
+{
+#if ((BTM_EIR_SERVER_INCLUDED == TRUE)||(BTM_EIR_CLIENT_INCLUDED == TRUE))
+ 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 );
+#endif
+}
+
+/*******************************************************************************
+**
+** Function BTM_RemoveEirService
+**
+** 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 )
+{
+#if (BTM_EIR_SERVER_INCLUDED == TRUE)
+ 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 );
+#endif
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+#if (BTM_EIR_SERVER_INCLUDED == TRUE)
+ 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;
+#else
+ return BTM_EIR_COMPLETE_16BITS_UUID_TYPE;
+#endif
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+ 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_WARNING2("BTM_GetEirUuidList number of uuid in EIR = %d, size of uuid list = %d",
+ *p_num_uuid, max_num_uuid );
+ *p_num_uuid = max_num_uuid;
+ }
+
+ BTM_TRACE_DEBUG2("BTM_GetEirUuidList type = %02X, number of uuid = %d", 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_DEBUG1(" 0x%04X", *(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_DEBUG1(" 0x%08X", *(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_DEBUG1(" 0x%s", buff);
+ }
+ }
+
+ return type;
+#else
+ *p_num_uuid = 0;
+ return 0x00;
+#endif
+}
+
+
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** 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_WARNING0("btm_convert_uuid_to_uuid16 invalid uuid size");
+ 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_API1("btm_set_eir_uuid eir_complete_list=0x%02X", 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 );
+ }
+ }
+
+ BTM_TRACE_DEBUG2("btm_set_eir_uuid eir_uuid=0x%08X %08X",
+ p_results->eir_uuid[1], p_results->eir_uuid[0] );
+}
+#endif
+
diff --git a/stack/btm/btm_int.h b/stack/btm/btm_int.h
new file mode 100644
index 0000000..e5f4c15
--- /dev/null
+++ b/stack/btm/btm_int.h
@@ -0,0 +1,1114 @@
+/******************************************************************************
+ *
+ * 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
+
+#include "bt_target.h"
+#include "gki.h"
+#include "hcidefs.h"
+
+#if RFCOMM_INCLUDED == TRUE
+#include "rfcdefs.h"
+#endif
+
+#include "btm_api.h"
+
+#if (BLE_INCLUDED == TRUE)
+#include "btm_ble_int.h"
+#if (SMP_INCLUDED == TRUE)
+#include "smp_api.h"
+#endif
+#endif
+
+#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) != 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)->features) && \
+ HCI_ATOMIC_ENCRYPT_SUPPORTED(btm_cb.devcb.local_features)) \
+ ? TRUE : FALSE)
+
+#define BTM_IS_BRCM_CONTROLLER() (btm_cb.devcb.local_version.manufacturer == LMP_COMPID_BROADCOM)
+
+
+/* Define the ACL Management control structure
+*/
+typedef struct
+{
+ UINT16 hci_handle;
+ UINT16 pkt_types_mask;
+ UINT16 restore_pkt_types; /* when coming in/out of SCO connection restore the packet types */
+ 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 features; /* Features suported by the device */
+ UINT8 lmp_version;
+
+ BOOLEAN in_use;
+ UINT8 link_role;
+ BOOLEAN link_up_issued; /* True if busy_level link up has been issued */
+
+#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;
+ UINT8 change_key_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 BTM_PWR_MGR_INCLUDED == FALSE
+ UINT8 mode;
+#endif /* BTM_PWR_MGR_INCLUDED */
+#if BLE_INCLUDED == TRUE
+ UINT8 is_le_link;
+#endif
+
+} 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; /* Callback function to be called */
+ /* when startup of the device is done */
+ 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 rlinkp_timer;
+ tBTM_CMPL_CB *p_rlinkp_cmpl_cb; /* Callback function to be called when */
+ /* read link policy function completes */
+ 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 */
+
+ tBTM_CHANGE_KEY_CMPL chg_link_key_ref_data;
+ tBTM_CMPL_CB *p_chg_link_key_cb; /* Callback function to be called when */
+ /* change of link key is completed */
+
+ TIMER_LIST_ENT tx_power_timer;
+ tBTM_CMPL_CB *p_tx_power_cmpl_cb; /* Callback function to be called */
+
+ BD_ADDR local_addr; /* BD_ADDR of the local device */
+ tBTM_VERSION_INFO local_version; /* Local Version Information */
+ BD_FEATURES local_features; /* Local features bit mask */
+ DEV_CLASS dev_class; /* Local device class */
+#if BLE_INCLUDED == TRUE
+ BD_ADDR read_tx_pwr_addr; /* read TX power target address */
+
+ tBTM_BLE_LOCAL_ID_KEYS id_keys; /* local BLE ID keys */
+ BT_OCTET16 er; /* 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 */
+
+#define BTM_DEV_STATE_WAIT_RESET_CMPLT 0
+#define BTM_DEV_STATE_WAIT_AFTER_RESET 1
+#define BTM_DEV_STATE_READY 2
+
+ UINT8 state;
+ tBTM_IO_CAP loc_io_caps; /* IO capability of the local device */
+ BOOLEAN loc_auth_req; /* the auth_req flag */
+ BD_FEATURES brcm_features; /* Broadcom specific features bit mask */
+} 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
+
+#if BTM_USE_INQ_RESULTS_FILTER == TRUE
+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;
+#endif
+
+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;
+
+
+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 */
+
+ 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_inqfilter_cmpl_cb; /* Called (if not NULL) after inquiry filter completed */
+ tBTM_INQ_DB_CHANGE_CB *p_inq_change_cb; /* Inquiry database changed callback */
+ 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;
+#if BTM_USE_INQ_RESULTS_FILTER == TRUE
+ 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 */
+#endif
+ 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 */
+} 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;
+
+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
+ BUFFER_Q xmit_data_q; /* SCO data transmitting queue */
+#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 */
+#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
+extern void btm_set_sco_ind_cback( tBTM_SCO_IND_CBACK *sco_ind_cb );
+extern 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);
+extern void btm_reject_sco_link(UINT16 sco_inx );
+extern 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
+*/
+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 ltk; /* peer long term key */
+ BT_OCTET16 csrk; /* peer 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;
+
+#endif /* BLE_INCLUDED */
+
+typedef struct
+{
+ tBLE_ADDR_TYPE ble_addr_type; /* LE device type: public or random address */
+ BD_ADDR reconn_addr; /* reconnect address */
+ BD_ADDR cur_rand_addr; /* current random address */
+ BD_ADDR static_addr; /* static address */
+
+#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 */
+#endif
+} tBTM_SEC_BLE;
+
+/*
+** Define structure for Security Device Record.
+** A record exists for each device authenticated with this device
+*/
+typedef struct
+{
+ 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 */
+
+#define BTM_SEC_AUTHORIZED BTM_SEC_FLAG_AUTHORIZED
+#define BTM_SEC_AUTHENTICATED BTM_SEC_FLAG_AUTHENTICATED
+#define BTM_SEC_ENCRYPTED BTM_SEC_FLAG_ENCRYPTED
+#define BTM_SEC_NAME_KNOWN 0x08
+#define BTM_SEC_LINK_KEY_KNOWN BTM_SEC_FLAG_LKEY_KNOWN
+#define BTM_SEC_LINK_KEY_AUTHED 0x20
+#define BTM_SEC_ROLE_SWITCHED 0x40
+#define BTM_SEC_IN_USE 0x80
+
+ tBTM_BD_NAME sec_bd_name; /* User friendly name of the device. (may be truncated to save space in dev_rec table) */
+ UINT8 sec_flags; /* Current device security state */
+ BD_FEATURES features; /* Features suported by the device */
+
+#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
+#define BTM_SEC_STATE_DELAY_FOR_ENC 7 /* delay to check for encryption to work around controller problems */
+
+ 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_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 */
+ BOOLEAN rmt_auth_req; /* the auth_req flag as in the IO caps rsp evt */
+
+#if (BLE_INCLUDED == TRUE)
+ UINT8 enc_key_size; /* current link encryption key size */
+ tBTM_SEC_BLE ble;
+ tBT_DEVICE_TYPE device_type;
+ tBTM_LE_CONN_PRAMS conn_params;
+#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 --
+} tBTM_SEC_DEV_REC;
+
+#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 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;
+
+#if BTM_PWR_MGR_INCLUDED == TRUE
+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;
+
+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;
+
+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 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;
+#endif /* BTM_PWR_MGR_INCLUDED */
+
+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 cpmplete */
+ 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
+#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 */
+
+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;
+} 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 */
+
+#if (BTM_PCM2_INCLUDED == TRUE)
+/* Define pcm2_action */
+enum
+{
+ BTM_PCM2_ACT_NONE,
+ BTM_PCM2_ACT_SENT_ARC,
+ BTM_PCM2_READ_PARAM,
+ BTM_PCM2_WRITE_PARAM,
+};
+typedef UINT8 tBTM_PCM2_ACTION;
+#endif
+
+typedef struct
+{
+ tBTM_CFG cfg; /* Device configuration */
+
+ /****************************************************
+ ** ACL Management
+ ****************************************************/
+ tACL_CONN acl_db[MAX_L2CAP_LINKS];
+#if( RFCOMM_INCLUDED==TRUE)
+ UINT8 btm_scn[BTM_MAX_SCN]; /* current SCNs: TRUE if SCN is in use */
+#endif
+ UINT16 btm_def_link_policy;
+ UINT16 btm_def_link_super_tout;
+
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ tBTM_BL_EVENT_MASK bl_evt_mask;
+ tBTM_BL_CHANGE_CB *p_bl_changed_cb; /* Callback for when Busy Level changed */
+#else
+ tBTM_ACL_DB_CHANGE_CB *p_acl_changed_cb; /* Callback for when ACL DB changed */
+#endif
+
+ tBTM_LSTO_CBACK *p_lsto_cback; /* for link supervision timeout change event */
+
+ /****************************************************
+ ** Power Management
+ ****************************************************/
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ tBTM_PM_MCB pm_mode_db[MAX_L2CAP_LINKS]; /* per ACL link */
+ tBTM_PM_RCB pm_reg_db[BTM_MAX_PM_RECORDS+1]; /* per application/module */
+ UINT8 pm_pend_link; /* 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 */
+#endif /* BTM_PWR_MGR_INCLUDED == TRUE */
+
+ /*****************************************************
+ ** 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;
+#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;
+ tBTM_FILTER_CB *p_inq_filter_cb; /* Callback that can be set if host */
+ /* wants to verify inquiry filters */
+
+ /*****************************************************
+ ** 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];
+
+ tBTM_FILTER_CB *p_conn_filter_cb; /* Callback that can be set if host */
+ /* wants to verify connectability filters*/
+
+ tBTM_SEC_DEV_REC *p_collided_dev_rec;
+ 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 pin_type_changed; /* pin type changed during bonding */
+ BOOLEAN sec_req_pending; /* TRUE if a request is pending */
+// 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 */
+ 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 */
+ UINT16 disc_handle; /* for legacy devices */
+ UINT8 disc_reason; /* for legacy devices */
+ tBTM_SEC_SERV_REC sec_serv_rec[BTM_SEC_MAX_SERVICE_RECORDS];
+ tBTM_SEC_DEV_REC sec_dev_rec[BTM_SEC_MAX_DEVICE_RECORDS];
+ tBTM_SEC_SERV_REC *p_out_serv;
+ tBTM_MKEY_CALLBACK *mkey_cback;
+
+ BD_ADDR connecting_bda;
+ DEV_CLASS connecting_dc;
+
+ UINT8 first_disabled_channel;
+ UINT8 last_disabled_channel;
+
+ UINT8 acl_disc_reason;
+ UINT8 trace_level;
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ UINT8 num_acl; /* num of active ACL links */
+ 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 */
+#endif
+ BUFFER_Q page_queue;
+ BOOLEAN paging;
+ BOOLEAN discing;
+ BUFFER_Q 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
+
+#if (defined(BTM_PCM2_INCLUDED) && BTM_PCM2_INCLUDED == TRUE)
+ UINT16 sys_features;
+ UINT8 pcm2_params[BRCM_PCM2_SETUP_WRITE_SIZE];
+ tBTM_PCM2_ACTION pcm2_action;
+#endif
+
+} tBTM_CB;
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if BTM_DYNAMIC_MEMORY == FALSE
+BTM_API extern tBTM_CB btm_cb;
+#else
+BTM_API extern tBTM_CB *btm_cb_ptr;
+#define btm_cb (*btm_cb_ptr)
+#endif
+
+/* Internal functions provided by btm_main.c
+********************************************
+*/
+extern void btm_init (void);
+
+/* Internal functions provided by btm_inq.c
+*******************************************
+*/
+extern tBTM_STATUS btm_initiate_rem_name (BD_ADDR remote_bda,
+ tBTM_INQ_INFO *p_cur,
+ UINT8 origin, UINT32 timeout,
+ tBTM_CMPL_CB *p_cb);
+
+extern void btm_process_remote_name (BD_ADDR bda, BD_NAME name, UINT16 evt_len,
+ UINT8 hci_status);
+extern void btm_inq_rmt_name_failed(void);
+
+/* Inquiry related functions */
+extern void btm_clr_inq_db (BD_ADDR p_bda);
+extern void btm_inq_db_init (void);
+extern void btm_process_inq_results (UINT8 *p, UINT8 inq_res_mode);
+extern void btm_process_inq_complete (UINT8 status, UINT8 mode);
+extern void btm_event_filter_complete (UINT8 *p);
+extern void btm_inq_stop_on_ssp(void);
+extern void btm_inq_clear_ssp(void);
+extern tINQ_DB_ENT *btm_inq_db_find (BD_ADDR p_bda);
+extern BOOLEAN btm_inq_find_bdaddr (BD_ADDR p_bda);
+
+#if (BTM_EIR_CLIENT_INCLUDED == TRUE)
+extern BOOLEAN btm_lookup_eir(BD_ADDR_PTR p_rem_addr);
+#endif
+
+/* Internal functions provided by btm_acl.c
+********************************************
+*/
+extern void btm_acl_init (void);
+extern void btm_acl_timeout (TIMER_LIST_ENT *p_tle);
+extern void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn,
+ UINT16 hci_handle, UINT8 link_role, UINT8 is_le_link);
+extern void btm_acl_removed (BD_ADDR bda);
+extern void btm_acl_device_down (void);
+extern void btm_acl_update_busy_level (tBTM_BLI_EVENT event);
+extern void btm_acl_link_key_change (UINT16 handle, UINT8 status);
+
+extern void btm_cont_rswitch_or_chglinkkey (tACL_CONN *p,
+ tBTM_SEC_DEV_REC *p_dev_rec,
+ UINT8 hci_status);
+
+extern UINT8 btm_handle_to_acl_index (UINT16 hci_handle);
+extern void btm_read_link_policy_complete (UINT8 *p);
+extern void btm_read_rssi_complete (UINT8 *p);
+extern void btm_read_tx_power_complete (UINT8 *p, BOOLEAN is_ble);
+extern void btm_read_link_quality_complete (UINT8 *p);
+extern tBTM_STATUS btm_set_packet_types (tACL_CONN *p, UINT16 pkt_types);
+extern void btm_process_clk_off_comp_evt (UINT16 hci_handle, UINT16 clock_offset);
+extern void btm_acl_role_changed (UINT8 hci_status, BD_ADDR bd_addr, UINT8 new_role);
+extern void btm_acl_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable);
+BTM_API extern UINT16 btm_get_acl_disc_reason_code (void);
+BTM_API extern tBTM_STATUS btm_remove_acl (BD_ADDR bd_addr);
+extern void btm_read_remote_features_complete (UINT8 *p);
+extern void btm_read_remote_ext_features_complete (UINT8 *p);
+extern void btm_read_remote_ext_features_failed (UINT8 status);
+extern void btm_read_remote_version_complete (UINT8 *p);
+// btla-specific ++
+extern 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 */
+extern UINT16 btm_get_max_packet_size (BD_ADDR addr);
+extern tACL_CONN *btm_bda_to_acl (BD_ADDR bda);
+extern BOOLEAN btm_acl_notif_conn_collision (BD_ADDR bda);
+
+#if BTM_PWR_MGR_INCLUDED == FALSE
+extern void btm_process_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode,
+ UINT16 interval);
+
+/* Internal functions provided by btm_pm.c
+********************************************
+*/
+#else
+extern void btm_pm_reset(void);
+extern void btm_pm_sm_alloc(UINT8 ind);
+extern void btm_pm_proc_cmd_status(UINT8 status);
+extern void btm_pm_proc_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode,
+ UINT16 interval);
+extern void btm_pm_proc_ssr_evt (UINT8 *p, UINT16 evt_len);
+#if BTM_SCO_INCLUDED == TRUE
+extern void btm_sco_chk_pend_unpark (UINT8 hci_status, UINT16 hci_handle);
+#else
+#define btm_sco_chk_pend_unpark(hci_status, hci_handle)
+#endif /* BTM_SCO_INCLUDED */
+#endif /* BTM_PWR_MGR_INCLUDED == FALSE */
+extern void btm_qos_setup_complete (UINT8 status, UINT16 handle, FLOW_SPEC *p_flow);
+
+
+/* Internal functions provided by btm_sco.c
+********************************************
+*/
+extern void btm_sco_init (void);
+extern void btm_sco_connected (UINT8 hci_status, BD_ADDR bda, UINT16 hci_handle,
+ tBTM_ESCO_DATA *p_esco_data);
+extern void btm_esco_proc_conn_chg (UINT8 status, UINT16 handle, UINT8 tx_interval,
+ UINT8 retrans_window, UINT16 rx_pkt_len,
+ UINT16 tx_pkt_len);
+extern void btm_sco_conn_req (BD_ADDR bda, DEV_CLASS dev_class, UINT8 link_type);
+extern void btm_sco_removed (UINT16 hci_handle, UINT8 reason);
+extern void btm_sco_acl_removed (BD_ADDR bda);
+extern void btm_route_sco_data (BT_HDR *p_msg);
+extern BOOLEAN btm_is_sco_active (UINT16 handle);
+extern void btm_remove_sco_links (BD_ADDR bda);
+extern BOOLEAN btm_is_sco_active_by_bdaddr (BD_ADDR remote_bda);
+
+extern tBTM_SCO_TYPE btm_read_def_esco_mode (tBTM_ESCO_PARAMS *p_parms);
+extern UINT16 btm_find_scb_by_handle (UINT16 handle);
+extern void btm_sco_flush_sco_data(UINT16 sco_inx);
+
+/* Internal functions provided by btm_devctl.c
+**********************************************
+*/
+extern void btm_dev_init (void);
+extern void btm_dev_absent (void);
+extern void btm_dev_timeout (TIMER_LIST_ENT *p_tle);
+extern void btm_reset_complete (void);
+extern void btm_read_local_version_complete (UINT8 *p, UINT16 evt_len);
+extern void btm_read_hci_buf_size_complete (UINT8 *p, UINT16 evt_len);
+extern void btm_read_local_features_complete (UINT8 *p, UINT16 evt_len);
+extern void btm_read_local_name_complete (UINT8 *p, UINT16 evt_len);
+extern void btm_read_local_addr_complete (UINT8 *p, UINT16 evt_len);
+extern void btm_get_local_features (void);
+
+#if (BLE_INCLUDED == TRUE)
+extern void btm_read_ble_buf_size_complete (UINT8 *p, UINT16 evt_len);
+extern void btm_read_white_list_size_complete(UINT8 *p, UINT16 evt_len);
+extern void btm_ble_add_2_white_list_complete(UINT8 *p, UINT16 evt_len);
+extern void btm_ble_remove_from_white_list_complete(UINT8 *p, UINT16 evt_len);
+extern void btm_ble_clear_white_list_complete(UINT8 *p, UINT16 evt_len);
+#endif /* BLE_INCLUDED */
+
+/* Vendor Specific Command complete evt handler */
+extern void btm_vsc_complete (UINT8 *p, UINT16 cc_opcode, UINT16 evt_len,
+ tBTM_CMPL_CB *p_vsc_cplt_cback);
+extern void btm_inq_db_reset (void);
+extern void btm_vendor_specific_evt (UINT8 *p, UINT8 evt_len);
+extern UINT8 btm_get_hci_version (void);
+extern void btm_read_stored_link_key_complete (UINT8 *p);
+extern void btm_write_stored_link_key_complete (UINT8 *p);
+extern void btm_delete_stored_link_key_complete (UINT8 *p);
+extern void btm_return_link_keys_evt (tBTM_RETURN_LINK_KEYS_EVT *result);
+extern void btm_report_device_status (tBTM_DEV_STATUS status);
+
+
+/* Internal functions provided by btm_dev.c
+**********************************************
+*/
+extern BOOLEAN btm_dev_support_switch (BD_ADDR bd_addr);
+extern UINT8 btm_get_voice_coding_support (void);
+
+extern tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr);
+extern void btm_sec_free_dev (tBTM_SEC_DEV_REC *p_dev_rec);
+extern tBTM_SEC_DEV_REC *btm_find_dev (BD_ADDR bd_addr);
+extern tBTM_SEC_DEV_REC *btm_find_or_alloc_dev (BD_ADDR bd_addr);
+extern tBTM_SEC_DEV_REC *btm_find_dev_by_handle (UINT16 handle);
+
+/* Internal functions provided by btm_sec.c
+**********************************************
+*/
+extern BOOLEAN btm_dev_support_switch (BD_ADDR bd_addr);
+extern 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);
+extern 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);
+extern void btm_sec_conn_req (UINT8 *bda, UINT8 *dc);
+extern void btm_create_conn_cancel_complete (UINT8 *p);
+extern void btm_proc_lsto_evt(UINT16 handle, UINT16 timeout);
+extern void btm_read_linq_tx_power_complete (UINT8 *p);
+
+extern void btm_sec_init (UINT8 sec_mode);
+extern void btm_sec_dev_reset (void);
+extern void btm_sec_abort_access_req (BD_ADDR bd_addr);
+extern void btm_sec_auth_complete (UINT16 handle, UINT8 status);
+extern void btm_sec_mkey_comp_event (UINT16 handle, UINT8 status, UINT8 key_flg);
+extern void btm_sec_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable);
+extern void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode);
+extern tBTM_STATUS btm_sec_disconnect (UINT16 handle, UINT8 reason);
+extern void btm_sec_disconnected (UINT16 handle, UINT8 reason);
+extern void btm_sec_rmt_name_request_complete (UINT8 *bd_addr, UINT8 *bd_name, UINT8 status);
+extern void btm_sec_rmt_host_support_feat_evt (UINT8 *p);
+extern void btm_io_capabilities_req (UINT8 *p);
+extern void btm_io_capabilities_rsp (UINT8 *p);
+extern void btm_proc_sp_req_evt (tBTM_SP_EVT event, UINT8 *p);
+extern void btm_keypress_notif_evt (UINT8 *p);
+extern void btm_simple_pair_complete (UINT8 *p);
+extern void btm_sec_link_key_notification (UINT8 *p_bda, UINT8 *p_link_key, UINT8 key_type);
+extern void btm_sec_link_key_request (UINT8 *p_bda);
+extern void btm_sec_pin_code_request (UINT8 *p_bda);
+extern void btm_sec_update_clock_offset (UINT16 handle, UINT16 clock_offset);
+extern void btm_sec_dev_rec_cback_event (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 res);
+
+#if BLE_INCLUDED == TRUE
+extern void btm_sec_clear_ble_keys (tBTM_SEC_DEV_REC *p_dev_rec);
+extern BOOLEAN btm_sec_find_bonded_dev (UINT8 start_idx, UINT8 *p_found_idx, tBTM_SEC_DEV_REC *p_rec);
+extern BOOLEAN btm_sec_is_a_bonded_dev (BD_ADDR bda);
+#endif /* BLE_INCLUDED */
+
+extern tINQ_DB_ENT *btm_inq_db_new (BD_ADDR p_bda);
+
+#if BTM_OOB_INCLUDED == TRUE
+extern void btm_rem_oob_req (UINT8 *p);
+extern void btm_read_local_oob_complete (UINT8 *p);
+#else
+#define btm_rem_oob_req(p)
+#define btm_read_local_oob_complete(p)
+#endif
+
+extern void btm_acl_resubmit_page (void);
+extern void btm_acl_reset_paging (void);
+extern void btm_acl_paging (BT_HDR *p, BD_ADDR dest);
+extern void btm_acl_set_discing (BOOLEAN discing);
+extern UINT8 btm_sec_clr_service_by_psm (UINT16 psm);
+
+#ifdef BRCM_VS
+extern void btm_brcm_feat_init(void);
+extern void btm_vs_reset_complete (void);
+extern void btm_brcm_arc_init (void);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/stack/btm/btm_main.c b/stack/btm/btm_main.c
new file mode 100644
index 0000000..f3037f6
--- /dev/null
+++ b/stack/btm/btm_main.c
@@ -0,0 +1,70 @@
+/******************************************************************************
+ *
+ * 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 "bt_types.h"
+#include "bt_target.h"
+#include <string.h>
+#include "btm_int.h"
+
+/* Global BTM control block structure
+*/
+#if BTM_DYNAMIC_MEMORY == FALSE
+tBTM_CB btm_cb;
+#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)
+{
+ /* All fields are cleared; nonzero fields are reinitialized in appropriate function */
+ memset(&btm_cb, 0, sizeof(tBTM_CB));
+
+#if defined(BTM_INITIAL_TRACE_LEVEL)
+ btm_cb.trace_level = BTM_INITIAL_TRACE_LEVEL;
+#else
+ btm_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+ /* Initialize BTM component structures */
+ btm_inq_db_init(); /* Inquiry Database and Structures */
+ btm_acl_init(); /* ACL Database and Structures */
+ btm_sec_init(BTM_SEC_MODE_SP); /* Security Manager Database and Structures */
+#if BTM_SCO_INCLUDED == TRUE
+ btm_sco_init(); /* SCO Database and Structures (If included) */
+#endif
+
+ btm_dev_init(); /* Device Manager Structures & HCI_Reset */
+}
+
+
diff --git a/stack/btm/btm_pm.c b/stack/btm/btm_pm.c
new file mode 100644
index 0000000..19b90d3
--- /dev/null
+++ b/stack/btm/btm_pm.c
@@ -0,0 +1,998 @@
+/******************************************************************************
+ *
+ * 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.
+ *
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+#include "bt_types.h"
+#include "gki.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "l2c_int.h"
+#include "hcidefs.h"
+
+
+#if BTM_PWR_MGR_INCLUDED == TRUE
+
+/* This compile option is only useful when the FW has a bug
+ * it automatically uses single slot when entering SNIFF mode, but does not restore the setting
+ * This issue was found when A2DP link goes into sniff and existing sniff still has choppy audio.
+ * If this issue is seen, look for FW solution first.
+ * This work around code will be removed later. */
+#ifndef BTM_PM_SNIFF_SLOT_WORK_AROUND
+#define BTM_PM_SNIFF_SLOT_WORK_AROUND FALSE
+#endif
+
+/*****************************************************************************/
+/* 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 int btm_pm_find_acl_ind(BD_ADDR remote_bda);
+static tBTM_STATUS btm_pm_snd_md_req( UINT8 pm_id, int link_ind, tBTM_PM_PWR_MD *p_mode );
+
+/*
+#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
+
+/*****************************************************************************/
+/* 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, acl_ind;
+ tBTM_PM_MCB *p_cb = NULL; /* per ACL link */
+ tBTM_PM_MODE mode;
+ int temp_pm_id;
+
+
+ if(pm_id >= BTM_MAX_PM_RECORDS)
+ pm_id = BTM_PM_SET_ONLY_ID;
+
+ if(p_mode == NULL)
+ return BTM_ILLEGAL_VALUE;
+
+ BTM_TRACE_API3( "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;
+
+ acl_ind = btm_pm_find_acl_ind(remote_bda);
+ if(acl_ind == MAX_L2CAP_LINKS)
+ return (BTM_UNKNOWN_ADDR);
+
+ p_cb = &(btm_cb.pm_mode_db[acl_ind]);
+
+ 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_DEBUG4( "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 != MAX_L2CAP_LINKS)) )
+ {
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG2( "BTM_SetPowerMode: Saving cmd acl_ind %d temp_pm_id %d", acl_ind,temp_pm_id);
+#endif
+ /* 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_DEBUG2( "btm_pm state:0x%x, pm_pend_link: %d", p_cb->state, btm_cb.pm_pend_link);
+#endif
+ /* 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 != MAX_L2CAP_LINKS) ) /* command pending */
+ {
+ if(acl_ind != btm_cb.pm_pend_link)
+ {
+ /* set the stored mask */
+ p_cb->state |= BTM_PM_STORED_MASK;
+ BTM_TRACE_DEBUG1( "btm_pm state stored:%d",acl_ind);
+ }
+ return BTM_CMD_STORED;
+ }
+
+
+
+ return btm_pm_snd_md_req(pm_id, acl_ind, 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)
+{
+ int acl_ind;
+
+ if( (acl_ind = btm_pm_find_acl_ind(remote_bda)) == MAX_L2CAP_LINKS)
+ return (BTM_UNKNOWN_ADDR);
+
+ *p_mode = btm_cb.pm_mode_db[acl_ind].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)
+ int acl_ind;
+ tBTM_PM_MCB *p_cb;
+
+ if( (acl_ind = btm_pm_find_acl_ind(remote_bda)) == MAX_L2CAP_LINKS)
+ return (BTM_UNKNOWN_ADDR);
+
+ if(BTM_PM_STS_ACTIVE == btm_cb.pm_mode_db[acl_ind].state ||
+ BTM_PM_STS_SNIFF == btm_cb.pm_mode_db[acl_ind].state)
+ {
+ if (btsnd_hcic_sniff_sub_rate(btm_cb.acl_db[acl_ind].hci_handle, max_lat,
+ min_rmt_to, min_loc_to))
+ return BTM_SUCCESS;
+ else
+ return BTM_NO_RESOURCES;
+ }
+ p_cb = &btm_cb.pm_mode_db[acl_ind];
+ 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
+}
+
+/*******************************************************************************
+**
+** 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;
+ }
+
+ /* no command pending */
+ btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
+
+ /* 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)
+ (*cb)(btm_cb.acl_db[btm_cb.pm_pend_link].remote_addr, BTM_PM_STS_ERROR, BTM_DEV_RESET, 0);
+}
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+void btm_pm_sm_alloc(UINT8 ind)
+{
+ tBTM_PM_MCB *p_db = &btm_cb.pm_mode_db[ind]; /* per ACL link */
+ memset (p_db, 0, sizeof(tBTM_PM_MCB));
+ p_db->state = BTM_PM_ST_ACTIVE;
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG2( "btm_pm_sm_alloc ind:%d st:%d", ind, p_db->state);
+#endif
+}
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+static int btm_pm_find_acl_ind(BD_ADDR remote_bda)
+{
+ tACL_CONN *p = &btm_cb.acl_db[0];
+ UINT8 xx;
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++)
+ {
+ if ((p->in_use) && (!memcmp (p->remote_addr, remote_bda, BD_ADDR_LEN)))
+ {
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG2( "btm_pm_find_acl_ind ind:%d, st:%d", xx, btm_cb.pm_mode_db[xx].state);
+#endif
+ break;
+ }
+ }
+ return xx;
+}
+
+/*******************************************************************************
+**
+** 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, int link_ind, tBTM_PM_PWR_MD *p_mode)
+{
+ tBTM_PM_PWR_MD md_res;
+ tBTM_PM_MODE mode;
+ tBTM_PM_MCB *p_cb = &btm_cb.pm_mode_db[link_ind];
+ 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_DEBUG2( "btm_pm_snd_md_req link_ind:%d, mode: %d",
+ link_ind, mode);
+#endif
+
+ 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(btm_cb.acl_db[link_ind].hci_handle, p_cb->max_lat,
+ p_cb->min_rmt_to, p_cb->min_loc_to);
+ p_cb->max_lat = 0;
+ }
+#endif
+ /* Default is failure */
+ btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
+
+ /* send the appropriate HCI command */
+ btm_cb.pm_pend_id = pm_id;
+
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG2("btm_pm_snd_md_req state:0x%x, link_ind: %d", p_cb->state, link_ind);
+#endif
+ switch(md_res.mode)
+ {
+ case BTM_PM_MD_ACTIVE:
+ switch(p_cb->state)
+ {
+ case BTM_PM_MD_SNIFF:
+ if (btsnd_hcic_exit_sniff_mode(btm_cb.acl_db[link_ind].hci_handle))
+ {
+ btm_cb.pm_pend_link = link_ind;
+ }
+ break;
+ case BTM_PM_MD_PARK:
+ if (btsnd_hcic_exit_park_mode(btm_cb.acl_db[link_ind].hci_handle))
+ {
+ btm_cb.pm_pend_link = link_ind;
+ }
+ break;
+ default:
+ /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
+ break;
+ }
+ break;
+
+ case BTM_PM_MD_HOLD:
+ if (btsnd_hcic_hold_mode (btm_cb.acl_db[link_ind].hci_handle,
+ md_res.max, md_res.min))
+ {
+ btm_cb.pm_pend_link = link_ind;
+ }
+ break;
+
+ case BTM_PM_MD_SNIFF:
+ if (btsnd_hcic_sniff_mode (btm_cb.acl_db[link_ind].hci_handle,
+ md_res.max, md_res.min, md_res.attempt,
+ md_res.timeout))
+ {
+ btm_cb.pm_pend_link = link_ind;
+ }
+ break;
+
+ case BTM_PM_MD_PARK:
+ if (btsnd_hcic_park_mode (btm_cb.acl_db[link_ind].hci_handle,
+ md_res.max, md_res.min))
+ {
+ btm_cb.pm_pend_link = link_ind;
+ }
+ break;
+ default:
+ /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
+ break;
+ }
+
+ if(btm_cb.pm_pend_link == MAX_L2CAP_LINKS)
+ {
+ /* the command was not sent */
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG1( "pm_pend_link: %d",btm_cb.pm_pend_link);
+#endif
+ 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)
+{
+ int xx;
+ for(xx=0; xx<MAX_L2CAP_LINKS; xx++)
+ {
+ if(btm_cb.pm_mode_db[xx].state & BTM_PM_STORED_MASK)
+ {
+ btm_cb.pm_mode_db[xx].state &= ~BTM_PM_STORED_MASK;
+ BTM_TRACE_DEBUG1( "btm_pm_check_stored :%d", xx);
+ btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, xx, 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;
+
+ if(btm_cb.pm_pend_link >= MAX_L2CAP_LINKS)
+ return;
+
+ p_cb = &btm_cb.pm_mode_db[btm_cb.pm_pend_link];
+
+ if(status == HCI_SUCCESS)
+ {
+ p_cb->state = BTM_PM_ST_PENDING;
+ pm_status = BTM_PM_STS_PENDING;
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG1( "btm_pm_proc_cmd_status new state:0x%x", p_cb->state);
+#endif
+ }
+ 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)(btm_cb.acl_db[btm_cb.pm_pend_link].remote_addr, pm_status, 0, status);
+ }
+
+ /* no pending cmd now */
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG3( "btm_pm_proc_cmd_status state:0x%x, pm_pend_link: %d(new: %d)",
+ p_cb->state, btm_cb.pm_pend_link, MAX_L2CAP_LINKS);
+#endif
+ btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
+
+ 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 xx, yy, zz;
+ tBTM_PM_STATE old_state;
+ tL2C_LCB *p_lcb;
+
+ /* get the index to acl_db */
+ if ((xx = btm_handle_to_acl_index(hci_handle)) >= MAX_L2CAP_LINKS)
+ return;
+
+ p = &btm_cb.acl_db[xx];
+
+ /*** 2035 and 2045 work around: If mode is active and coming out of a SCO disconnect, restore packet types ***/
+ if (mode == HCI_MODE_ACTIVE)
+ {
+ if(BTM_GetNumScoLinks() == 0)
+ {
+ if(p->restore_pkt_types)
+ {
+ BTM_TRACE_DEBUG3("btm mode change AFTER unsniffing; hci hdl 0x%x, types 0x%02x/0x%02x",
+ hci_handle, p->pkt_types_mask, p->restore_pkt_types);
+ p->pkt_types_mask = p->restore_pkt_types;
+ p->restore_pkt_types = 0; /* Only exists while SCO is active */
+ btsnd_hcic_change_conn_type (p->hci_handle, p->pkt_types_mask);
+ }
+#if (BTM_PM_SNIFF_SLOT_WORK_AROUND == TRUE)
+ else
+ {
+ BTM_TRACE_DEBUG2("btm mode change AFTER unsniffing; hci hdl 0x%x, types 0x%02x",
+ hci_handle, btm_cb.btm_acl_pkt_types_supported);
+ btm_set_packet_types (p, btm_cb.btm_acl_pkt_types_supported);
+ }
+#endif
+ }
+#if (BTM_PM_SNIFF_SLOT_WORK_AROUND == TRUE)
+ else
+ {
+ /* Mode changed from Sniff to Active while SCO is open. */
+ /* Packet types of active mode, not sniff mode, should be used for ACL when SCO is closed. */
+ p->restore_pkt_types = btm_cb.btm_acl_pkt_types_supported;
+
+ /* Exclude packet types not supported by the peer */
+ btm_acl_chk_peer_pkt_type_support (p, &p->restore_pkt_types);
+ }
+#endif
+ }
+#if (BTM_PM_SNIFF_SLOT_WORK_AROUND == TRUE)
+ else if (mode == HCI_MODE_SNIFF)
+ {
+ BTM_TRACE_DEBUG1("btm mode change to sniff; hci hdl 0x%x use single slot",
+ hci_handle);
+ btm_set_packet_types (p, (HCI_PKT_TYPES_MASK_DM1 | HCI_PKT_TYPES_MASK_DH1));
+ }
+#endif
+
+ /* update control block */
+ p_cb = &(btm_cb.pm_mode_db[xx]);
+ old_state = p_cb->state;
+ p_cb->state = mode;
+ p_cb->interval = interval;
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG2( "btm_pm_proc_mode_change new state:0x%x (old:0x%x)", p_cb->state, old_state);
+#endif
+
+ if ((p_cb->state == HCI_MODE_ACTIVE) &&
+ ((p_lcb = l2cu_find_lcb_by_bd_addr (p->remote_addr)) != NULL))
+ {
+ /* There might be any pending packets due to SNIFF or PENDING state */
+ /* Trigger L2C to start transmission of the pending packets. */
+ BTM_TRACE_DEBUG0 ("btm mode change to active; check l2c_link for outgoing packets");
+ l2c_link_check_send_pkts (p_lcb, NULL, NULL);
+
+ //btu_stop_timer (&p_lcb->timer_entry);
+ }
+
+ /* 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_DEBUG1( "btm_pm_proc_mode_change: Sending stored req:%d", xx);
+#endif
+ btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, xx, NULL);
+ }
+ else
+ {
+ for(zz=0; zz<MAX_L2CAP_LINKS; zz++)
+ {
+ if(btm_cb.pm_mode_db[zz].chg_ind == TRUE)
+ {
+#if BTM_PM_DEBUG == TRUE
+ BTM_TRACE_DEBUG1( "btm_pm_proc_mode_change: Sending PM req :%d", zz);
+#endif
+ btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, zz, 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_or_chglinkkey(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_tx_lat, max_rx_lat;
+ int xx, yy;
+ tBTM_PM_MCB *p_cb;
+ tACL_CONN *p_acl=NULL;
+ UINT16 use_ssr = TRUE;
+
+ STREAM_TO_UINT8 (status, p);
+
+ STREAM_TO_UINT16 (handle, p);
+ /* get the index to acl_db */
+ if ((xx = btm_handle_to_acl_index(handle)) >= MAX_L2CAP_LINKS)
+ return;
+
+ STREAM_TO_UINT16 (max_tx_lat, p);
+ STREAM_TO_UINT16 (max_rx_lat, p);
+ p_cb = &(btm_cb.pm_mode_db[xx]);
+
+ p_acl = &btm_cb.acl_db[xx];
+ if(p_cb->interval == max_rx_lat)
+ {
+ /* using legacy sniff */
+ use_ssr = FALSE;
+ }
+
+ /* notify registered parties */
+ for(yy=0; yy<BTM_MAX_PM_RECORDS; yy++)
+ {
+ if(btm_cb.pm_reg_db[yy].mask & BTM_PM_REG_NOTIF)
+ {
+ if( p_acl)
+ {
+ (*btm_cb.pm_reg_db[yy].cback)( p_acl->remote_addr, BTM_PM_STS_SSR, use_ssr, status);
+ }
+ }
+ }
+}
+#endif
+#else /* BTM_PWR_MGR_INCLUDED == TRUE */
+
+/*******************************************************************************
+**
+** Functions BTM_PmRegister, BTM_SetPowerMode, and BTM_ReadPowerMode
+**
+** Description Stubbed versions for BTM_PWR_MGR_INCLUDED = FALSE
+**
+** Returns BTM_MODE_UNSUPPORTED.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_PmRegister (UINT8 mask, UINT8 *p_pm_id, tBTM_PM_STATUS_CBACK *p_cb)
+{
+ return BTM_MODE_UNSUPPORTED;
+}
+
+tBTM_STATUS BTM_SetPowerMode (UINT8 pm_id, BD_ADDR remote_bda, tBTM_PM_PWR_MD *p_mode)
+{
+ return BTM_MODE_UNSUPPORTED;
+}
+
+tBTM_STATUS BTM_ReadPowerMode (BD_ADDR remote_bda, tBTM_PM_MODE *p_mode)
+{
+ return BTM_MODE_UNSUPPORTED;
+}
+
+#endif
+
+/*******************************************************************************
+**
+** Function BTM_IsPowerManagerOn
+**
+** Description This function is called to check if power manager is included.
+** in the BTE version.
+**
+** Returns BTM_PWR_MGR_INCLUDED.
+**
+*******************************************************************************/
+BOOLEAN BTM_IsPowerManagerOn (void)
+{
+ return BTM_PWR_MGR_INCLUDED;
+}
diff --git a/stack/btm/btm_sco.c b/stack/btm/btm_sco.c
new file mode 100644
index 0000000..5a11404
--- /dev/null
+++ b/stack/btm/btm_sco.c
@@ -0,0 +1,1750 @@
+/******************************************************************************
+ *
+ * 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 "bt_types.h"
+#include "bt_target.h"
+#include "gki.h"
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "hcidefs.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->xmit_data_q.p_first)
+ {
+ if ((p_buf = (BT_HDR *)GKI_dequeue (&p->xmit_data_q)) != NULL)
+ GKI_freebuf (p_buf);
+ }
+ }
+#endif
+#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
+ /* 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_ERROR0("Could not reject (e)SCO conn: No Buffer!!!");
+ }
+ }
+ else
+ {
+ if (!btsnd_hcic_reject_esco_conn (bda, hci_status))
+ {
+ BTM_TRACE_ERROR0("Could not reject (e)SCO conn: No Buffer!!!");
+ }
+ }
+ }
+ else /* Connection is being accepted */
+ {
+ p_sco->state = SCO_ST_CONNECTING;
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_1_2)
+ {
+ 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;
+
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+ temp_pkt_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
+ }
+ }
+ /* OR in any exception packet types if at least 2.0 version of spec */
+ else if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+ 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_ERROR0("Could not accept SCO conn: No Buffer!!!");
+ }
+ }
+ else /* Controller is version 1.1 or earlier */
+ {
+ btsnd_hcic_accept_conn (bda, 0);
+ }
+ }
+#endif
+}
+
+
+#if BTM_SCO_HCI_INCLUDED == TRUE
+/*******************************************************************************
+**
+** 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)
+{
+ BT_HDR *p_buf;
+ 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 */
+ while (p_ccb->xmit_data_q.p_first != NULL)
+ {
+ p_buf = NULL;
+
+#if BTM_SCO_HCI_DEBUG
+ BTM_TRACE_DEBUG1 ("btm: [%d] buf in xmit_data_q", p_ccb->xmit_data_q.count );
+#endif
+ p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->xmit_data_q);
+
+ HCI_SCO_DATA_TO_LOWER (p_buf);
+ }
+}
+#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);
+
+ 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 */
+ GKI_freebuf (p_msg);
+ else
+ {
+ (*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 */
+ {
+ GKI_freebuf (p_msg);
+ }
+#else
+ GKI_freebuf(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.
+**
+**
+*******************************************************************************/
+tBTM_STATUS BTM_WriteScoData (UINT16 sco_inx, BT_HDR *p_buf)
+{
+#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_ERROR1 ("BTM SCO - cannot send buffer, offset: %d", p_buf->offset);
+ GKI_freebuf (p_buf);
+ 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)
+ {
+ 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;
+
+ GKI_enqueue (&p_ccb->xmit_data_q, p_buf);
+
+ btm_sco_check_send_pkts (sco_inx);
+ }
+ }
+ else
+ {
+ GKI_freebuf(p_buf);
+
+ BTM_TRACE_WARNING2 ("BTM_WriteScoData, invalid sco index: %d at state [%d]",
+ sco_inx, btm_cb.sco_cb.sco_db[sco_inx].state);
+ status = BTM_UNKNOWN_ADDR;
+ }
+
+ return (status);
+
+#else
+ 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;
+ UINT8 xx;
+ 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 if at least 2.0 version of spec */
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+ 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 */
+ btm_handle_to_acl_index(acl_handle);
+ if ((xx = btm_handle_to_acl_index(acl_handle)) < MAX_L2CAP_LINKS)
+ {
+ p_acl = &btm_cb.acl_db[xx];
+ if (!HCI_EDR_ESCO_2MPS_SUPPORTED(p_acl->features))
+ {
+
+ BTM_TRACE_WARNING0("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->features))
+ {
+
+ BTM_TRACE_WARNING0("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);
+ }
+ }
+
+
+ BTM_TRACE_API6(" 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_ERROR1("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_DEBUG1("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_PWR_MGR_INCLUDED == TRUE) && (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+ tBTM_PM_MODE md;
+ tBTM_PM_PWR_MD pm;
+#else
+ UINT8 mode;
+#endif
+
+ *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)) == 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_PWR_MGR_INCLUDED == TRUE) && (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)
+ {
+/* Coverity: FALSE-POSITIVE error from Coverity tool. Please do NOT remove following comment. */
+/* coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode
+ the other data members of tBTM_PM_PWR_MD are ignored
+*/
+ pm.mode = BTM_PM_MD_ACTIVE;
+ BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, remote_bda, &pm);
+ p->state = SCO_ST_PEND_UNPARK;
+ }
+ }
+#elif BTM_PWR_MGR_INCLUDED == TRUE
+ if( (BTM_ReadPowerMode(remote_bda, &mode) == BTM_SUCCESS) && (mode == BTM_PM_MD_PARK) )
+ return (BTM_WRONG_MODE);
+#else
+ if( (BTM_ReadAclMode(remote_bda, &mode) == BTM_SUCCESS) && (mode == BTM_ACL_MODE_PARK) )
+ return (BTM_WRONG_MODE);
+#endif
+ }
+ 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 at least 2.0 version of spec */
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+ 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);
+ if (p_acl && p_acl->switch_role_state != BTM_ACL_SWKEY_STATE_IDLE)
+ {
+ BTM_TRACE_API1("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_API2("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_PWR_MGR_INCLUDED == TRUE) && (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)) == hci_handle))
+
+ {
+ BTM_TRACE_API3("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
+}
+#endif
+
+/*******************************************************************************
+**
+** 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)) == hci_handle))
+
+ {
+ BTM_TRACE_API1("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
+ */
+ if (((p->state == SCO_ST_LISTENING && p->rem_bd_known) || p->state == SCO_ST_CONNECTING)
+ && (!memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN)))
+ {
+ /* 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_WARNING0("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;
+
+#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_API1("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;
+
+ 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;
+ 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 if at least 2.0 version of spec */
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+ p_def->packet_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
+ }
+ }
+ }
+ p_esco->desired_sco_mode = sco_mode;
+ BTM_TRACE_API1("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_API0("BTM_SetEScoMode -> mode SCO (eSCO not supported)");
+ }
+
+ BTM_TRACE_DEBUG6(" 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)
+ BTM_TRACE_API1("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);
+ }
+#endif
+
+ 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_API2("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 if at least 2.0 version of spec */
+ if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+ {
+ 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_API1("BTM_ChangeEScoLinkParms -> eSCO Link for handle 0x%04x", p_sco->hci_handle);
+ BTM_TRACE_API6(" 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_EVENT2("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/stack/btm/btm_sec.c b/stack/btm/btm_sec.c
new file mode 100644
index 0000000..956364e
--- /dev/null
+++ b/stack/btm/btm_sec.c
@@ -0,0 +1,5649 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_int.h"
+#include "l2c_int.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 (GKI_SECS_TO_TICKS(5))
+
+#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 */
+/********************************************************************************/
+static tBTM_SEC_SERV_REC *btm_sec_find_first_serv (BOOLEAN is_originator, UINT16 psm);
+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);
+
+#if (BT_USE_TRACES == TRUE)
+static char *btm_pair_state_descr (tBTM_PAIRING_STATE state);
+#endif
+
+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);
+BOOLEAN btm_sec_are_all_trusted(UINT32 p_mask[]);
+
+static tBTM_STATUS btm_sec_send_hci_disconnect (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 reason);
+tBTM_SEC_DEV_REC *btm_sec_find_dev_by_sec_state (UINT8 state);
+
+static BOOLEAN btm_sec_set_security_level ( CONNECTION_TYPE conn_type, char *p_name, UINT8 service_id,
+ UINT16 sec_level, UINT16 psm, UINT32 mx_proto_id,
+ UINT32 mx_chan_id);
+
+/* 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_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
+ BT_OCTET16 temp_value = {0};
+#endif
+
+ BTM_TRACE_EVENT0 ("BTM_Sec: application registered");
+
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ BTM_TRACE_ERROR1 ("BTM_SecRegister:p_cb_info->p_le_callback == 0x%x ", p_cb_info->p_le_callback);
+
+ if (p_cb_info->p_le_callback)
+ {
+#if SMP_INCLUDED == TRUE
+ BTM_TRACE_EVENT0 ("BTM_Sec: SMP_Register( btm_proc_smp_cback )");
+ SMP_Register(btm_proc_smp_cback);
+#endif
+ /* 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();
+ }
+ }
+ else
+ {
+ BTM_TRACE_ERROR0 ("BTM_SecRegister:p_cb_info->p_le_callback == NULL ");
+ }
+#endif
+
+
+
+ btm_cb.api = *p_cb_info;
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ BTM_TRACE_ERROR1 ("BTM_SecRegister: btm_cb.api.p_le_callback = 0x%x ", btm_cb.api.p_le_callback);
+#endif
+ BTM_TRACE_EVENT0 ("BTM_Sec: application registered");
+ 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
+**
+*******************************************************************************/
+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);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SecDeleteRmtNameNotifyCallback
+**
+** Description Any profile can deregister notification when a new Link Key
+** is generated per connection.
+**
+** Returns TRUE if OK, else FALSE
+**
+*******************************************************************************/
+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);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_SecSetConnectFilterCallback
+**
+** Description Host can register to be asked whenever a HCI connection
+** request is received. In the registered function host
+** suppose to check connectibility filters. Yes/No result
+** should be returned syncronously
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_SecSetConnectFilterCallback (tBTM_FILTER_CB *p_callback)
+{
+ btm_cb.p_conn_filter_cb = p_callback;
+}
+
+/*******************************************************************************
+**
+** Function BTM_GetSecurityMode
+**
+** Description Get security mode for the device
+**
+** Returns void
+**
+*******************************************************************************/
+UINT8 BTM_GetSecurityMode (void)
+{
+ return(btm_cb.security_mode);
+}
+
+/*******************************************************************************
+**
+** 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 = p_dev_rec->sec_flags;
+ return(TRUE);
+ }
+ BTM_TRACE_ERROR0 ("BTM_GetSecurityFlags false");
+ return(FALSE);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetSecurityMode
+**
+** Description Set security mode for the device
+**
+** Returns void
+**
+*******************************************************************************/
+void BTM_SetSecurityMode (UINT8 security_mode)
+{
+ UINT8 old_mode = btm_cb.security_mode;
+
+ UINT8 sp_mode = HCI_SPD_MODE_ENABLED;
+ UINT8 sp_debug_mode = HCI_SPD_MODE_DISABLED;
+
+ switch (security_mode)
+ {
+#if (BTM_PRE_LISBON_INCLUDED == TRUE)
+ case BTM_SEC_MODE_NONE:
+ case BTM_SEC_MODE_SERVICE:
+ case BTM_SEC_MODE_LINK:
+ break;
+#endif
+
+ case BTM_SEC_MODE_SP_DEBUG:
+ sp_debug_mode = HCI_SPD_MODE_ENABLED;
+ break;
+ case BTM_SEC_MODE_SP:
+ /* the default is enabled */
+ break;
+ default:
+ BTM_TRACE_ERROR1 ("BTM_SetSecurityMode: unknown mode:%d", security_mode);
+ return;
+ }
+ btm_cb.security_mode = security_mode;
+
+ if (HCI_SIMPLE_PAIRING_SUPPORTED(btm_cb.devcb.local_features))
+ {
+ /* Lisbon devices and only use BTM_SEC_MODE_SP */
+ btm_cb.security_mode = BTM_SEC_MODE_SP;
+ BTM_TRACE_DEBUG2("BTM_SetSecurityMode: SP:%d, debug:%d", sp_mode, sp_debug_mode);
+ btsnd_hcic_write_simple_pairing_mode(sp_mode);
+ btsnd_hcic_write_simp_pair_debug_mode(sp_debug_mode);
+ return;
+ }
+
+ /* must be a pre-Lisbon device */
+#if (BTM_PRE_LISBON_INCLUDED == TRUE)
+ /* If previously security mode was Link Level and now lesser notify */
+ /* controller not to perform authentication, encryption on startup */
+ if ((old_mode == BTM_SEC_MODE_LINK)
+ && ( security_mode != BTM_SEC_MODE_LINK))
+ {
+ BTM_TRACE_DEBUG0("BTM_SetSecurityMode: Authen Enable -> FALSE");
+ btsnd_hcic_write_auth_enable (FALSE);
+ btsnd_hcic_write_encr_mode (HCI_ENCRYPT_MODE_DISABLED);
+ }
+
+ /* If previously security is increased to Link Level notify */
+ /* controller to perform authentication, encryption on startup */
+ if ((old_mode != BTM_SEC_MODE_LINK)
+ && ( security_mode == BTM_SEC_MODE_LINK))
+ {
+ BTM_TRACE_DEBUG0("BTM_SetSecurityMode: Authen Enable -> TRUE");
+ btsnd_hcic_write_auth_enable (TRUE);
+ btsnd_hcic_write_encr_mode (HCI_ENCRYPT_MODE_POINT_TO_POINT);
+ }
+#endif /* BTM_PRE_LISBON_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_API3 ("BTM_SetPinType: pin type %d [variable-0, fixed-1], code %s, length %d",
+ 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)
+ && (btm_cb.devcb.state > BTM_DEV_STATE_WAIT_AFTER_RESET) )
+ {
+ 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);
+}
+
+/*******************************************************************************
+**
+** 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_API2 ("BTM_SetPairableMode() allow_pairing: %u connect_only_paired: %u", allow_pairing, connect_only_paired);
+
+ btm_cb.pairing_disabled = !allow_pairing;
+ btm_cb.connect_only_paired = connect_only_paired;
+}
+
+
+#define BTM_NO_AVAIL_SEC_SERVICES ((UINT16) 0xffff)
+
+/*******************************************************************************
+**
+** Function BTM_SetUCDSecurityLevel
+**
+** Description Register UCD 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_SetUCDSecurityLevel (BOOLEAN is_originator, 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 = CONNLESS_ORIG;
+ else
+ conn_type = CONNLESS_TERM;
+
+ return(btm_sec_set_security_level (conn_type, p_name, service_id,
+ sec_level, psm, mx_proto_id, mx_chan_id));
+#else
+ return FALSE;
+#endif
+}
+
+/*******************************************************************************
+**
+** 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, 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, char *p_name, UINT8 service_id,
+ UINT16 sec_level, UINT16 psm, UINT32 mx_proto_id,
+ UINT32 mx_chan_id)
+{
+ 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
+
+ /* 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_WARNING1("BTM_SEC_REG: Out of Service Records (%d)", 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, sizeof(p_srec->orig_service_name), p_name, BTM_SEC_SERVICE_NAME_LEN);
+#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);
+
+ if (btm_cb.security_mode == BTM_SEC_MODE_SP)
+ {
+ 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, sizeof(p_srec->term_service_name), p_name, BTM_SEC_SERVICE_NAME_LEN);
+#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);
+ }
+ 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);
+ }
+
+ /* 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)
+ {
+ 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_API6("BTM_SEC_REG[%d]: id %d, conn_type 0x%x, psm 0x%04x, proto_id %d, chan_id %d",
+ index, service_id, conn_type, psm, mx_proto_id, mx_chan_id);
+
+ BTM_TRACE_API2(" : security_flags: 0x%04x, ucd_security_flags: 0x%04x",
+ p_srec->security_flags, p_srec->ucd_security_flags);
+
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ BTM_TRACE_API2(" : service name [%s] (up to %d chars saved)",
+ p_name, BTM_SEC_SERVICE_NAME_LEN);
+#endif
+#else
+ p_srec->security_flags |= (UINT16)(sec_level | BTM_SEC_IN_USE);
+
+ BTM_TRACE_API6("BTM_SEC_REG[%d]: id %d, is_orig %d, psm 0x%04x, proto_id %d, chan_id %d",
+ index, service_id, is_originator, psm, mx_proto_id, mx_chan_id);
+
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ BTM_TRACE_API3(" : sec: 0x%x, service name [%s] (up to %d chars saved)",
+ p_srec->security_flags, p_name, BTM_SEC_SERVICE_NAME_LEN);
+#endif
+#endif
+
+
+ return(record_allocated);
+}
+
+/*******************************************************************************
+**
+** 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.
+**
+*******************************************************************************/
+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_API2("BTM_SEC_CLR[%d]: id %d", 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);
+}
+
+/*******************************************************************************
+**
+** 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.
+**
+*******************************************************************************/
+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_API2("BTM_SEC_CLR[%d]: id %d ", i, p_srec->service_id);
+ p_srec->security_flags = 0;
+ num_freed++;
+ }
+ }
+ BTM_TRACE_API2("btm_sec_clr_service_by_psm psm:0x%x num_freed:%d", psm, num_freed);
+
+ return(num_freed);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SecClrUCDService
+**
+** Description
+**
+** Parameters Service ID - Id of the service to remove.
+** ('0' removes all service records )
+**
+** Returns Number of records that were cleared.
+**
+*******************************************************************************/
+UINT8 BTM_SecClrUCDService (UINT8 service_id)
+{
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ tBTM_SEC_SERV_REC *p_srec = &btm_cb.sec_serv_rec[0];
+ UINT8 num_cleared = 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) &&
+ (!service_id || (service_id == (UINT32)p_srec->service_id)))
+ {
+ BTM_TRACE_API2("BTM_UCD_SEC_CLR[%d]: id %d", i, service_id);
+ p_srec->ucd_security_flags = 0;
+ num_cleared++;
+ }
+ }
+
+ return(num_cleared);
+#else
+ return(0);
+#endif
+}
+
+/*******************************************************************************
+**
+** 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)
+**
+*******************************************************************************/
+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;
+
+ BTM_TRACE_API4 ("BTM_PINCodeReply(): PairState: %s PairFlags: 0x%02x PinLen:%d Result:%d",
+ btm_pair_state_descr(btm_cb.pairing_state), btm_cb.pairing_flags, pin_len, res);
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_PIN)
+ {
+ BTM_TRACE_WARNING1 ("BTM_PINCodeReply() - Wrong State: %d", btm_cb.pairing_state);
+ return;
+ }
+
+ if (memcmp (bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) != 0)
+ {
+ BTM_TRACE_ERROR0 ("BTM_PINCodeReply() - Wrong BD Addr");
+ return;
+ }
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL)
+ {
+ BTM_TRACE_ERROR0 ("BTM_PINCodeReply() - no dev CB");
+ 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 ( (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;
+ 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_WARNING0 ("BTM_PINCodeReply(): waiting HCI_Connection_Complete after rejected incoming connection");
+ /* 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_WARNING0 ("BTM_PINCodeReply(): link is connecting so wait pin code request from peer");
+ 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;
+
+ (*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_EVENT2("BTM_PINCodeReply(): Saving pin_len: %d btm_cb.pin_code_len: %d", 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);
+}
+
+
+/*******************************************************************************
+**
+** Function BTM_DeviceAuthorized
+**
+** Description This function is called after Security Manager submitted
+** authorization 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
+**
+*******************************************************************************/
+void BTM_DeviceAuthorized (BD_ADDR bd_addr, UINT8 res, UINT32 trusted_mask[])
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL)
+ {
+ BTM_TRACE_WARNING6 ("Security Manager: Attempting Authorization of Unknown Device Address [%02x%02x%02x%02x%02x%02x]",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+ return;
+ }
+
+ BTM_TRACE_EVENT4 ("Security Manager: authorized status:%d State:%d Trusted:%08x %08x",
+ res, (p_dev_rec) ? p_dev_rec->sec_state : 0, trusted_mask[0], trusted_mask[1]);
+
+ if (res == BTM_SUCCESS)
+ {
+ p_dev_rec->sec_flags |= BTM_SEC_AUTHORIZED;
+ if (trusted_mask)
+ BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
+ }
+
+ if (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHORIZING)
+ return;
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+
+ if (res != BTM_SUCCESS)
+ {
+ btm_sec_dev_rec_cback_event (p_dev_rec, res);
+ return;
+ }
+
+ if ((res = (UINT8)btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED)
+ {
+ btm_sec_dev_rec_cback_event (p_dev_rec, res);
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** 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
+*******************************************************************************/
+tBTM_STATUS BTM_SecBond (BD_ADDR bd_addr, UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[])
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_STATUS status;
+#if SMP_INCLUDED == TRUE
+ tACL_CONN *p=NULL;
+ BOOLEAN is_le_slave_role=FALSE;
+#endif
+ BTM_TRACE_API6 ("BTM_SecBond BDA: %02x:%02x:%02x:%02x:%02x:%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+ /* Other security process is in progress */
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ {
+ BTM_TRACE_ERROR1 ("BTM_SecBond: already busy in state: %s", btm_pair_state_descr(btm_cb.pairing_state));
+ return(BTM_WRONG_MODE);
+ }
+
+
+ p_dev_rec = btm_find_or_alloc_dev (bd_addr);
+ BTM_TRACE_DEBUG1 ("before update sec_flags=0x%x", p_dev_rec->sec_flags);
+
+
+#if SMP_INCLUDED == TRUE
+ p = btm_bda_to_acl(bd_addr);
+ if (p && p->is_le_link )
+ {
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING)
+ {
+ BTM_TRACE_ERROR1 ("BTM_SecBond: LE already busy in state: %x", p_dev_rec->sec_state );
+ return(BTM_WRONG_MODE);
+ }
+
+ if (p->link_role == BTM_ROLE_SLAVE)
+ {
+ is_le_slave_role = TRUE;
+ BTM_TRACE_DEBUG0 ("LE Link Slave" );
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0 ("LE Link Maste" );
+ }
+ }
+ else
+ {
+ BTM_TRACE_DEBUG0 ("No LE Link" );
+ }
+
+ if (!is_le_slave_role)
+ {
+ /* Finished if connection is active and already paired */
+ if ( (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)
+ && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED) )
+ {
+ BTM_TRACE_WARNING0("BTM_SecBond -> Already Paired");
+ return(BTM_SUCCESS);
+ }
+ }
+#else
+ /* Finished if connection is active and already paired */
+ if ( (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)
+ && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED) )
+ {
+ BTM_TRACE_WARNING0("BTM_SecBond -> Already Paired");
+ return(BTM_SUCCESS);
+ }
+#endif
+
+ /* 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);
+
+ /* 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;
+ memcpy (btm_cb.pin_code, p_pin, PIN_CODE_LEN);
+ }
+
+ 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 SMP_INCLUDED == TRUE
+
+ if (!is_le_slave_role)
+ {
+ 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);
+
+ }
+
+ /* LE device, do SMP pairing */
+ if (p_dev_rec->device_type == BT_DEVICE_TYPE_BLE)
+ {
+ if (SMP_Pair(p_dev_rec->bd_addr) == SMP_STARTED)
+ {
+ p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+ return BTM_CMD_STARTED;
+ }
+ else
+ return(BTM_NO_RESOURCES);
+ }
+#else
+ 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);
+#endif
+
+ BTM_TRACE_DEBUG1 ("after update sec_flags=0x%x", p_dev_rec->sec_flags);
+ if (!HCI_SIMPLE_PAIRING_SUPPORTED(btm_cb.devcb.local_features))
+ {
+ /* 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);
+ }
+ }
+
+ BTM_TRACE_EVENT1("BTM_SecBond: Local device supports SSP=%d", HCI_SIMPLE_PAIRING_SUPPORTED(btm_cb.devcb.local_features));
+
+ BTM_TRACE_EVENT4(" remote_features=%02x-%02x-%02x-%02x",
+ p_dev_rec->features[0], p_dev_rec->features[1], p_dev_rec->features[2], p_dev_rec->features[3]);
+ BTM_TRACE_EVENT4(" %02x-%02x-%02x-%02x",
+ p_dev_rec->features[4], p_dev_rec->features[5], p_dev_rec->features[6], p_dev_rec->features[7]);
+
+ BTM_TRACE_EVENT2 ("BTM_SecBond: Remote sm4: 0x%x HCI Handle: 0x%04x", 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_dev_rec->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_DEBUG2 ("sec mode: %d sm4:x%x", btm_cb.security_mode, p_dev_rec->sm4);
+ if (!HCI_SIMPLE_PAIRING_SUPPORTED(btm_cb.devcb.local_features)
+ || (p_dev_rec->sm4 == BTM_SM4_KNOWN))
+ {
+ if ( btm_sec_check_prefetch_pin (p_dev_rec) )
+ return(BTM_CMD_STARTED);
+ }
+ if (BTM_SEC_MODE_SP == btm_cb.security_mode && 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);
+ }
+ else
+ {
+ /* We are accepting connection request from peer */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
+ }
+ BTM_TRACE_DEBUG3 ("State:%s sm4: 0x%x sec_state:%d", btm_pair_state_descr (btm_cb.pairing_state), p_dev_rec->sm4, p_dev_rec->sec_state);
+ 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_SecBondCancel
+**
+** Description This function is called to cancel ongoing bonding process
+** with peer device.
+**
+** Parameters: bd_addr - Address of the peer device
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SecBondCancel (BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+#if SMP_INCLUDED == TRUE
+ tACL_CONN *p=NULL;
+#endif
+
+ BTM_TRACE_API2 ("BTM_SecBondCancel() State: %s flags:0x%x",
+ btm_pair_state_descr (btm_cb.pairing_state), btm_cb.pairing_flags);
+
+ 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
+ p = btm_bda_to_acl(bd_addr);
+ if (p && p->is_le_link &&
+ (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING))
+ {
+ BTM_TRACE_DEBUG0 ("Cancel LE pairing");
+ if (SMP_PairCancel(bd_addr))
+ {
+ return BTM_CMD_STARTED;
+ }
+ else
+ {
+ return BTM_WRONG_MODE;
+ }
+ }
+
+#endif
+ BTM_TRACE_DEBUG2 ("hci_handle:0x%x sec_state:%d", 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)
+ 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);
+ 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;
+ }
+
+ return BTM_NOT_AUTHORIZED;
+ }
+ }
+
+ return BTM_WRONG_MODE;
+}
+
+/*******************************************************************************
+**
+** Function BTM_SecUseMasterLinkKey
+**
+** Description This function is called to tell master of the piconet to
+** switch to master link key
+**
+** Parameters: use_master_key - If true Master Link Key shoul be used
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SecUseMasterLinkKey (BOOLEAN use_master_key)
+{
+ return(btsnd_hcic_master_link_key (use_master_key) ? BTM_SUCCESS :
+ BTM_NO_RESOURCES);
+}
+
+/*******************************************************************************
+**
+** Function BTM_SetMasterKeyCompCback
+**
+** Description This function is called to register for the master key complete
+** status event.
+**
+** Parameters: mkey_cback - callback registered with the security manager
+**
+*******************************************************************************/
+void BTM_SetMasterKeyCompCback( tBTM_MKEY_CALLBACK *mkey_cback )
+{
+ btm_cb.mkey_cback = mkey_cback;
+}
+
+/*******************************************************************************
+**
+** 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);
+}
+
+
+/*******************************************************************************
+**
+** 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.
+**
+** 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.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetEncryption (BD_ADDR bd_addr, tBTM_SEC_CBACK *p_callback,
+ void *p_ref_data)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_STATUS rc;
+
+#if BLE_INCLUDED == TRUE
+ tACL_CONN *p;
+ p = btm_bda_to_acl(bd_addr);
+#endif
+
+ p_dev_rec = btm_find_dev (bd_addr);
+ if (!p_dev_rec || (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE))
+ {
+ /* Connection should be up and runnning */
+ BTM_TRACE_WARNING0 ("Security Manager: BTM_SetEncryption not connected");
+
+ if (p_callback)
+ (*p_callback) (bd_addr, p_ref_data, BTM_WRONG_MODE);
+
+ return(BTM_WRONG_MODE);
+ }
+
+
+ if (
+#if BLE_INCLUDED == TRUE
+ !p->is_le_link &&
+#endif
+ (p_dev_rec->sec_flags & (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED))
+ == (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED))
+ {
+ BTM_TRACE_EVENT0 ("Security Manager: BTM_SetEncryption already encrypted");
+
+ if (p_callback)
+ (*p_callback) (bd_addr, p_ref_data, BTM_SUCCESS);
+
+ return(BTM_SUCCESS);
+ }
+
+ if (p_dev_rec->p_callback)
+ {
+ /* Connection should be up and runnning */
+ BTM_TRACE_WARNING0 ("Security Manager: BTM_SetEncryption busy");
+
+ if (p_callback)
+ (*p_callback) (bd_addr, p_ref_data, BTM_BUSY);
+
+ return(BTM_BUSY);
+ }
+
+ 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_API4 ("Security Manager: BTM_SetEncryption Handle:%d State:%d Flags:0x%x Required:0x%x",
+ 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 (p->is_le_link)
+ {
+ rc = btm_ble_set_encryption(bd_addr, p_ref_data, p->link_role);
+ }
+ else
+#endif
+
+ rc = btm_sec_execute_procedure (p_dev_rec);
+
+ if ( rc != BTM_CMD_STARTED)
+ {
+ if (p_callback)
+ {
+ p_dev_rec->p_callback = NULL;
+ (*p_callback) (bd_addr, 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)
+{
+ UINT8 old_state = p_dev_rec->sec_state;
+
+ BTM_TRACE_EVENT2 ("btm_sec_send_hci_disconnect: handle:0x%x, reason=0x%x",
+ p_dev_rec->hci_handle, reason);
+
+ /* if some other thread disconnecting, we do not send second command */
+ if (BTM_SEC_STATE_DISCONNECTING != old_state)
+ {
+ p_dev_rec->sec_state = BTM_SEC_STATE_DISCONNECTING;
+
+#if BTM_DISC_DURING_RS == TRUE
+ /* If a Role Switch is in progress, delay the HCI Disconnect to avoid controller problem (4329B1) */
+ if (p_dev_rec->rs_disc_pending == BTM_SEC_RS_PENDING)
+ {
+ BTM_TRACE_ERROR0("RS in progress - Set DISC Pending flag in btm_sec_send_hci_disconnect to delay disconnect");
+ p_dev_rec->rs_disc_pending = BTM_SEC_DISC_PENDING;
+ return BTM_SUCCESS;
+ }
+#endif
+ /* Tear down the HCI link */
+ if (!btsnd_hcic_disconnect (p_dev_rec->hci_handle, reason))
+ {
+ /* could not send disconnect. restore old state */
+ p_dev_rec->sec_state = old_state;
+ return(BTM_NO_RESOURCES);
+ }
+ }
+ return(BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+void BTM_ConfirmReqReply(tBTM_STATUS res, BD_ADDR bd_addr)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_EVENT2 ("BTM_ConfirmReqReply() State: %s Res: %u",
+ btm_pair_state_descr(btm_cb.pairing_state), res);
+
+ /* 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;
+ }
+
+ 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);
+ }
+}
+
+/*******************************************************************************
+**
+** 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 (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+void BTM_PasskeyReqReply(tBTM_STATUS res, BD_ADDR bd_addr, UINT32 passkey)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ BTM_TRACE_API2 ("BTM_PasskeyReqReply: State: %s res:%d",
+ btm_pair_state_descr(btm_cb.pairing_state), res);
+
+ 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) )
+ {
+ if ((p_dev_rec = btm_find_dev (bd_addr)) != 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);
+ 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
+
+/*******************************************************************************
+**
+** 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 (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+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
+
+#if BTM_OOB_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)
+{
+ BTM_TRACE_EVENT3 ("BTM_IoCapRsp: state: %s oob: %d io_cap: %d",
+ btm_pair_state_descr(btm_cb.pairing_state), oob, io_cap);
+
+ 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)
+{
+ BTM_TRACE_EVENT2 ("BTM_RemoteOobDataReply(): State: %s res:%d",
+ btm_pair_state_descr(btm_cb.pairing_state), res);
+
+ /* 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;
+ UINT16 delta;
+#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, btm_cb.devcb.local_addr);
+
+ len = BTM_OOB_MANDATORY_SIZE;
+ max_len -= len;
+
+ /* now optional part */
+
+ /* add Hash C */
+ 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
+
+/*******************************************************************************
+**
+** 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];
+ int i;
+
+ btm_cb.p_out_serv = p_serv_rec;
+ p_dev_rec = btm_find_dev (bd_addr);
+
+ 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->service_id == service_id)
+ && (p_serv_rec->orig_mx_chan_id == mx_chan_id))
+ {
+ BTM_TRACE_API4("BTM_SetOutService p_out_serv id %d, psm 0x%04x, proto_id %d, chan_id %d",
+ 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;
+ }
+ }
+}
+
+/************************************************************************
+** I N T E R N A L F U N C T I O N S
+*************************************************************************/
+/*******************************************************************************
+**
+** Function btm_sec_check_upgrade
+**
+** Description This function is called to check if the existing link key
+** needs to be upgraded.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btm_sec_check_upgrade(tBTM_SEC_DEV_REC *p_dev_rec, BOOLEAN is_originator)
+{
+ tBTM_SP_UPGRADE evt_data;
+ UINT16 mtm_check = is_originator ? BTM_SEC_OUT_MITM : BTM_SEC_IN_MITM;
+
+ if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)
+ {
+
+ BTM_TRACE_DEBUG5 ("btm_sec_check_upgrade id:%d, link_key_typet:%d, rmt_io_caps:%d, chk flags:x%x, flags:x%x",
+ 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);
+ /* 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) /* 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 */
+ {
+ BTM_TRACE_DEBUG1 ("need upgrade!! sec_flags:0x%x", 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 */
+ 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_DEBUG1 ("evt_data.upgrade:0x%x", 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_DEBUG1 ("sec_flags:0x%x", p_dev_rec->sec_flags);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+#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)
+
+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_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;
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (conn_type & CONNECTION_TYPE_ORIG_MASK)
+ is_originator = TRUE;
+ else
+ is_originator = FALSE;
+
+ BTM_TRACE_DEBUG2 ("btm_sec_l2cap_access_req conn_type:0x%x, 0x%x", conn_type, p_ref_data);
+#else
+ is_originator = conn_type;
+
+ BTM_TRACE_DEBUG2 ("btm_sec_l2cap_access_req is_originator:%d, 0x%x", 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_WARNING1 ("btm_sec_l2cap_access_req() PSM:%d no application registerd", psm);
+
+ (*p_callback) (bd_addr, p_ref_data, BTM_MODE_UNSUPPORTED);
+
+ return(BTM_MODE_UNSUPPORTED);
+ }
+
+ /* SDP connection we will always let through */
+ if (BT_PSM_SDP == psm)
+ {
+ (*p_callback) (bd_addr, p_ref_data, BTM_SUCCESS_NO_SECURITY);
+
+ return(BTM_SUCCESS);
+ }
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if ( conn_type & CONNECTION_TYPE_CONNLESS_MASK )
+ {
+ 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))) )
+ {
+ rc = BTM_SUCCESS;
+ }
+ }
+
+ if (rc == BTM_SUCCESS)
+ {
+ if (p_callback)
+ (*p_callback) (bd_addr, (void *)p_ref_data, BTM_SUCCESS);
+
+ return(BTM_SUCCESS);
+ }
+ }
+ else
+#endif
+ {
+ security_required = p_serv_rec->security_flags;
+ }
+
+ /* 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) )
+ {
+ BTM_TRACE_EVENT2 ("btm_sec_l2cap_access_req() - busy - PSM:%d delayed state: %s",
+ psm, btm_pair_state_descr(btm_cb.pairing_state));
+ rc = BTM_CMD_STARTED;
+ if ((BTM_SEC_MODE_SP != btm_cb.security_mode)
+ || ((BTM_SEC_MODE_SP == btm_cb.security_mode) && (BTM_SM4_KNOWN == p_dev_rec->sm4))
+ )
+ {
+ BTM_TRACE_EVENT2 ("security_flags:x%x, sec_flags:x%x", security_required, p_dev_rec->sec_flags);
+ /* legacy mode - local is legacy or local is lisbon/peer is legacy */
+ 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))) )
+ {
+ rc = BTM_SUCCESS;
+ }
+ }
+
+ if (rc == BTM_SUCCESS)
+ {
+ if (p_callback)
+ (*p_callback) (bd_addr, (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;
+
+
+ /* mess /w security_required in btm_sec_l2cap_access_req for Lisbon */
+ if (btm_cb.security_mode == BTM_SEC_MODE_SP)
+ {
+ if (is_originator)
+ {
+ if (BTM_SEC_IS_SM4(p_dev_rec->sm4))
+ {
+ /* SM4 to SM4 -> always authenticate & encrypt */
+ security_required |= (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT);
+ }
+ else
+ {
+ if ( !(BTM_SM4_KNOWN & p_dev_rec->sm4))
+ {
+ BTM_TRACE_DEBUG1 ("remote features unknown!!sec_flags:0x%x", p_dev_rec->sec_flags);
+ /* the remote features are not known yet */
+ p_dev_rec->sm4 |= BTM_SM4_REQ_PEND;
+
+ return(BTM_CMD_STARTED);
+ }
+ }
+ }
+ else
+ {
+ /* responder */
+ if (BTM_SEC_IS_SM4(p_dev_rec->sm4))
+ {
+ /* 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))
+ {
+ BTM_TRACE_DEBUG1 ("(rsp) remote features unknown!!sec_flags:0x%x", p_dev_rec->sec_flags);
+ /* the remote features are not known yet */
+ p_dev_rec->sm4 |= BTM_SM4_REQ_PEND;
+
+ return(BTM_CMD_STARTED);
+ }
+ }
+ }
+ }
+
+ BTM_TRACE_DEBUG4 ("btm_sec_l2cap_access_req() sm4:0x%x, sec_flags:0x%x, security_required:0x%x chk:%d",
+ 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_DEBUG2 ("no next_serv sm4:0x%x, chk:%d", p_dev_rec->sm4, chk_acp_auth_done);
+ if (!BTM_SEC_IS_SM4(p_dev_rec->sm4))
+ {
+ BTM_TRACE_EVENT1 ("Security Manager: l2cap_access_req PSM:%d postponed for multiplexer", 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, 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_SP || !BTM_SEC_IS_SM4(p_dev_rec->sm4)) && (psm >= 0x1001))
+ {
+ BTM_TRACE_EVENT1 ("dynamic PSM:0x%x in legacy mode - postponed for upper layer", 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, p_ref_data, BTM_SUCCESS);
+
+ return(BTM_SUCCESS);
+ }
+
+ if (chk_acp_auth_done)
+ {
+ BTM_TRACE_DEBUG2 ("(SM4 to SM4) btm_sec_l2cap_access_req rspd. authenticated: x%x, enc: x%x",
+ (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_ERROR0 ("peer should have initiated security process by now (SM4 to SM4)");
+ p_dev_rec->p_callback = p_callback;
+ p_dev_rec->sec_state = BTM_SEC_STATE_DELAY_FOR_ENC;
+ (*p_callback) (bd_addr, p_ref_data, rc);
+
+ return(BTM_SUCCESS);
+ }
+ }
+
+ p_dev_rec->p_callback = p_callback;
+
+ /* 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 we already have a link key to the connected peer, is the link key secure enough ? */
+ btm_sec_check_upgrade(p_dev_rec, is_originator);
+ }
+
+ BTM_TRACE_EVENT6 ("Security Manager: l2cap_access_req PSM:%d Handle:%d State:%d Flags:0x%x Required:0x%x Service ID:%d",
+ 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, p_dev_rec->p_ref_data, (UINT8)rc);
+ }
+
+ return(rc);
+}
+
+/*******************************************************************************
+**
+** 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)
+
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ tBTM_SEC_SERV_REC *p_serv_rec;
+ tBTM_STATUS rc;
+
+ BTM_TRACE_DEBUG1 ("btm_sec_mx_access_request is_originator:%d", 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, p_ref_data, BTM_MODE_UNSUPPORTED);
+
+ BTM_TRACE_ERROR3 ("Security Manager: MX service not found PSM:%d Proto:%d SCN:%d",
+ psm, mx_proto_id, mx_chan_id);
+ return BTM_NO_RESOURCES;
+ }
+
+ /* 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) )
+ {
+ BTM_TRACE_EVENT4 ("btm_sec_mx_access_request service PSM:%d Proto:%d SCN:%d delayed state: %s",
+ psm, mx_proto_id, mx_chan_id, btm_pair_state_descr(btm_cb.pairing_state));
+
+ btm_sec_queue_mx_request (bd_addr, psm, is_originator, mx_proto_id, mx_chan_id, p_callback, p_ref_data);
+ return BTM_CMD_STARTED;
+ }
+
+ p_dev_rec->p_cur_service = p_serv_rec;
+ p_dev_rec->security_required = p_serv_rec->security_flags;
+
+ if (BTM_SEC_MODE_SP == btm_cb.security_mode)
+ {
+ if (BTM_SEC_IS_SM4(p_dev_rec->sm4))
+ {
+ /* 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_EVENT6 ("Security Manager: mx_access_req proto_id:%d chan_id:%d State:%d Flags:0x%x Required:0x%x Service ID:%d",
+ 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, p_ref_data, (UINT8)rc);
+ }
+ }
+
+ return rc;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_conn_req
+**
+** Description This function is when the peer device is requesting
+** connection
+**
+** Returns void
+**
+*******************************************************************************/
+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 (btm_cb.devcb.state != BTM_DEV_STATE_READY)
+ {
+ BTM_TRACE_EVENT0 ("Security Manager: connect request when device not ready");
+ 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_EVENT0 ("Security Manager: connect request from non-paired device");
+ 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_EVENT0 ("Security Manager: connect request from not paired device");
+ btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE);
+ return;
+ }
+ }
+#endif
+
+ /* Host can be registered to verify comming BDA or DC */
+ if (btm_cb.p_conn_filter_cb)
+ {
+ if (!(* btm_cb.p_conn_filter_cb) (bda, dc))
+ {
+ BTM_TRACE_EVENT0 ("Security Manager: connect request did not pass filter");
+
+ /* incomming call did not pass connection filters. Reject */
+ btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE);
+ return;
+ }
+ }
+
+ 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_EVENT0 ("Security Manager: reject connect request from bonding device");
+
+ /* 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;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_bond_cancel_complete
+**
+** Description This function is called to report bond cancel complete
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+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))
+ {
+ /* 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);
+ }
+}
+
+/*******************************************************************************
+**
+** 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_EVENT2 ("btm_create_conn_cancel_complete(): in State: %s status:%d",
+ 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:
+ btm_sec_bond_cancel_complete();
+ 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
+**
+*******************************************************************************/
+void btm_sec_check_pending_reqs (void)
+{
+ tBTM_SEC_QUEUE_ENTRY *p_e;
+ BUFFER_Q 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;
+ l2cu_resubmit_pending_sec_req (NULL);
+ }
+
+ /* Now, re-submit anything in the mux queue */
+ bq = btm_cb.sec_pending_q;
+
+ GKI_init_q (&btm_cb.sec_pending_q);
+
+ while ((p_e = (tBTM_SEC_QUEUE_ENTRY *)GKI_dequeue (&bq)) != NULL)
+ {
+ /* Check that the ACL is still up before starting security procedures */
+ if (btm_bda_to_acl(p_e->bd_addr) != NULL)
+ {
+ BTM_TRACE_EVENT4 ("btm_sec_check_pending_reqs() submitting PSM: 0x%04x Is_Orig: %u mx_proto_id: %u mx_chan_id: %u",
+ 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);
+ }
+
+ GKI_freebuf (p_e);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_init
+**
+** Description This function is on the SEC startup
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_init (UINT8 sec_mode)
+{
+#if 0 /* cleared in btm_init; put back in if calling from anywhere else! */
+ int i;
+
+ memset (btm_cb.sec_serv_rec, 0, sizeof (btm_cb.sec_serv_rec));
+ memset (btm_cb.sec_dev_rec, 0, sizeof (btm_cb.sec_dev_rec));
+ memset (&btm_cb.pairing_tle, 0, sizeof(TIMER_LIST_ENT));
+
+#endif
+ 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;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_device_down
+**
+** Description This function should be called when device is disabled or
+** turned off
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_device_down (void)
+{
+ BTM_TRACE_EVENT1 ("btm_sec_device_down() State: %s", btm_pair_state_descr(btm_cb.pairing_state));
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_dev_reset
+**
+** Description This function should be called after device reset
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_dev_reset (void)
+{
+#if (BTM_PRE_LISBON_INCLUDED == TRUE)
+ if (btm_cb.security_mode == BTM_SEC_MODE_LINK)
+ {
+ btsnd_hcic_write_auth_enable (TRUE);
+ btsnd_hcic_write_encr_mode (HCI_ENCRYPT_MODE_POINT_TO_POINT);
+ }
+#endif
+#if (BTM_PRE_LISBON_INCLUDED == TRUE)
+ else
+#endif
+ /* this function is only called from btm_read_local_features_complete()
+ * right now. */
+ if (HCI_SIMPLE_PAIRING_SUPPORTED(btm_cb.devcb.local_features))
+ {
+ btsnd_hcic_write_simple_pairing_mode(HCI_SP_MODE_ENABLED);
+#if BLE_INCLUDED == TRUE
+ btsnd_hcic_set_event_mask(LOCAL_BR_EDR_CONTROLLER_ID,
+ (UINT8 *)HCI_DUMO_EVENT_MASK_EXT);
+#else
+ btsnd_hcic_set_event_mask(LOCAL_BR_EDR_CONTROLLER_ID,
+ (UINT8 *)HCI_LISBON_EVENT_MASK_EXT);
+#endif
+ /* set the default IO capabilities */
+ btm_cb.devcb.loc_io_caps = BTM_LOCAL_IO_CAPS;
+ /* add mx service to use no security */
+#if (RFCOMM_INCLUDED == TRUE)
+ BTM_SetSecurityLevel(FALSE, "RFC_MUX", BTM_SEC_SERVICE_RFC_MUX,
+ BTM_SEC_NONE, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 0);
+#endif
+ }
+ else
+ {
+ btm_cb.security_mode = BTM_SEC_MODE_SERVICE;
+ }
+
+ BTM_TRACE_DEBUG1 ("btm_sec_dev_reset sec mode: %d", 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 (btm_cb.api.p_abort_callback)
+ (*btm_cb.api.p_abort_callback)(bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name);
+
+ 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
+**
+*******************************************************************************/
+static tBTM_STATUS btm_sec_dd_create_conn (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ tL2C_LCB *p_lcb;
+
+ /* Make sure an L2cap link control block is available */
+ if ((p_lcb = l2cu_allocate_lcb (p_dev_rec->bd_addr, TRUE)) == NULL)
+ {
+ BTM_TRACE_WARNING6 ("Security Manager: failed allocate LCB [%02x%02x%02x%02x%02x%02x]",
+ 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) == FALSE)
+ {
+ BTM_TRACE_WARNING6 ("Security Manager: failed create [%02x%02x%02x%02x%02x%02x]",
+ 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);
+ }
+
+#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE)
+ btm_acl_update_busy_level (BTM_BLI_PAGE_EVT);
+#endif
+
+ BTM_TRACE_DEBUG6 ("Security Manager: btm_sec_dd_create_conn [%02x%02x%02x%02x%02x%02x]",
+ 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);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_rmt_name_request_complete
+**
+** Description This function is called when remote name was obtained from
+** the peer device
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_rmt_name_request_complete (UINT8 *p_bd_addr, UINT8 *p_bd_name, UINT8 status)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ int i;
+ DEV_CLASS dev_class;
+ UINT8 old_sec_state;
+
+ BTM_TRACE_EVENT0 ("btm_sec_rmt_name_request_complete");
+ 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
+ {
+ p_dev_rec = &btm_cb.sec_dev_rec[0];
+
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++)
+ {
+ 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 (i == BTM_SEC_MAX_DEVICE_RECORDS)
+ p_dev_rec = NULL;
+ }
+
+
+ /* Commenting out trace due to obf/compilation problems.
+ */
+#if (BT_USE_TRACES == TRUE)
+ if (!p_bd_name)
+ p_bd_name = (UINT8 *)"";
+
+ if (p_dev_rec)
+ {
+ BTM_TRACE_EVENT5 ("Security Manager: rmt_name_complete PairState: %s RemName: %s status: %d State:%d p_dev_rec: 0x%08x ",
+ btm_pair_state_descr (btm_cb.pairing_state), p_bd_name,
+ status, p_dev_rec->sec_state, p_dev_rec);
+ }
+ else
+ {
+ BTM_TRACE_EVENT3 ("Security Manager: rmt_name_complete PairState: %s RemName: %s status: %d",
+ 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, sizeof (p_dev_rec->sec_bd_name), (char *)p_bd_name, BTM_MAX_REM_BD_NAME_LEN);
+ p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
+ BTM_TRACE_EVENT1 ("setting BTM_SEC_NAME_KNOWN sec_flags:0x%x", 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])
+ (*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])
+ (*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_EVENT2 ("btm_sec_rmt_name_request_complete() delayed pin now being requested flags:0x%x, (p_pin_callback=0x%p)", 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_EVENT0 ("btm_sec_rmt_name_request_complete() calling pin_callback");
+ 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);
+ }
+
+ /* 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_EVENT2 ("btm_sec_rmt_name_request_complete() continue bonding sm4: 0x%04x, status:0x%x", p_dev_rec->sm4, status);
+ if (status != HCI_SUCCESS)
+ {
+ btm_sec_change_pairing_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;
+ }
+
+ /* 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_EVENT1 ("btm_sec_rmt_name_request_complete IS_SM4_UNKNOWN Flags:0x%04x", btm_cb.pairing_flags);
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) == 0)
+ {
+ p_dev_rec->sm4 |= BTM_SM4_KNOWN;
+ }
+ }
+
+ /* 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_WARNING0 ("btm_sec_rmt_name_request_complete: waiting HCI_Connection_Complete after rejecting connection");
+ }
+ /* 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_WARNING0 ("btm_sec_rmt_name_request_complete: failed to start connection");
+
+ btm_sec_change_pairing_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, HCI_ERR_MEMORY_FULL);
+ }
+ }
+ return;
+ }
+ else
+ {
+ BTM_TRACE_WARNING0 ("btm_sec_rmt_name_request_complete: wrong BDA, retry with pairing BDA");
+
+ BTM_ReadRemoteDeviceName (btm_cb.pairing_bda, NULL);
+ 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)
+ (*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 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_WARNING0 ("btm_sec_rmt_name_request_complete (none/ce)");
+ 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);
+ return;
+ }
+
+ if (p_dev_rec->sm4 & BTM_SM4_REQ_PEND)
+ {
+ BTM_TRACE_EVENT0 ("waiting for remote features!!");
+ 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);
+}
+
+/*******************************************************************************
+**
+** 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_EVENT2 ("btm_sec_rmt_host_support_feat_evt sm4: 0x%x p[0]: 0x%x", 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, BD_FEATURES_LEN);
+ if (HCI_SSP_HOST_SUPPORTED(features))
+ {
+ p_dev_rec->sm4 = BTM_SM4_TRUE;
+ }
+ BTM_TRACE_EVENT2 ("btm_sec_rmt_host_support_feat_evt sm4: 0x%x features[0]: 0x%x", 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
+**
+*******************************************************************************/
+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;
+
+ BTM_TRACE_EVENT1 ("btm_io_capabilities_req() State: %s", btm_pair_state_descr(btm_cb.pairing_state));
+
+ p_dev_rec = btm_find_or_alloc_dev (evt_data.bd_addr);
+ p_dev_rec->sm4 |= BTM_SM4_TRUE;
+
+ BTM_TRACE_EVENT3 ("btm_io_capabilities_req() State: %s Flags: 0x%04x p_cur_service: 0x%08x",
+ btm_pair_state_descr(btm_cb.pairing_state), btm_cb.pairing_flags, p_dev_rec->p_cur_service);
+
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+ {
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_INCOMING_SSP)
+ {
+ /* received IO capability response already-> not the originator of SSP */
+ is_orig = FALSE;
+
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_PEER_STARTED_DD)
+ evt_data.auth_req = BTM_DEFAULT_DD_AUTH_REQ;
+ }
+ /* security is already in progress */
+ else if (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ)
+ {
+/* 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);
+*/
+ if (memcmp (evt_data.bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN))
+ {
+ /* and it's not the device in bonding -> reject it */
+ err_code = HCI_ERR_HOST_BUSY_PAIRING;
+ }
+ else
+ {
+ /* local device initiated dedicated bonding */
+ evt_data.auth_req = BTM_DEFAULT_DD_AUTH_REQ;
+ }
+ }
+ else
+ {
+ err_code = HCI_ERR_HOST_BUSY_PAIRING;
+ }
+ }
+
+ /* paring is not allowed */
+ if (btm_cb.pairing_disabled)
+ 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))
+ {
+ 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 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;
+
+ BTM_TRACE_EVENT4 ("btm_io_capabilities_req: State: %s IO_CAP:%d oob_data:%d auth_req:%d",
+ btm_pair_state_descr(btm_cb.pairing_state), evt_data.io_cap,
+ evt_data.oob_data, evt_data.auth_req);
+
+ 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
+**
+*******************************************************************************/
+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);
+
+ BTM_TRACE_EVENT4 ("btm_proc_sp_req_evt() BDA: %08x%04x event: 0x%x, State: %s",
+ (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));
+
+ 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_STRNCPY_S ((char *)evt_data.cfm_req.bd_name, sizeof(evt_data.cfm_req.bd_name), (char *)p_dev_rec->sec_bd_name, BTM_MAX_REM_BD_NAME_LEN);
+
+ 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_DEBUG5 ("btm_proc_sp_req_evt() just_works:%d, io loc:%d, rmt:%d, auth loc:%d, rmt:%d",
+ 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_DEBUG1 ("BTM_SP_KEY_NOTIF_EVT: passkey: %u", evt_data.key_notif.passkey);
+
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ break;
+
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ case BTM_SP_KEY_REQ_EVT:
+ /* HCI_USER_PASSKEY_REQUEST_EVT */
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_KEY_ENTRY);
+ break;
+#endif
+ }
+
+ 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_DEBUG1 ("calling BTM_ConfirmReqReply with status: %d", status);
+ BTM_ConfirmReqReply (status, p_bda);
+ }
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ else if (event == BTM_SP_KEY_REQ_EVT)
+ {
+ BTM_PasskeyReqReply(status, p_bda, 0);
+ }
+#endif
+ 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);
+ }
+ }
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ else
+ {
+ btsnd_hcic_user_passkey_neg_reply(p_bda);
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** 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_ERROR2 ("btm_simple_pair_complete() with unknown BDA: %08x%04x",
+ (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;
+ }
+
+ BTM_TRACE_EVENT3 ("btm_simple_pair_complete() Pair State: %s Status:%d sec_state: %u",
+ btm_pair_state_descr(btm_cb.pairing_state), status, p_dev_rec->sec_state);
+
+ 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 */
+ btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE);
+ }
+}
+
+#if BTM_OOB_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_EVENT6 ("btm_rem_oob_req() BDA: %02x:%02x:%02x:%02x:%02x:%02x",
+ 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, sizeof(evt_data.bd_name), (char *)p_dev_rec->sec_bd_name, BTM_MAX_REM_BD_NAME_LEN+1);
+
+ 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_EVENT1 ("btm_read_local_oob_complete:%d", 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
+**
+*******************************************************************************/
+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 = GKI_get_tick_count ();
+
+ if ((GKI_get_tick_count () - 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_DEBUG1 ("btm_sec_auth_collision: state %d (retrying in a moment...)", 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);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_auth_complete
+**
+** Description This function is when authentication of the connection is
+** completed by the LM
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_auth_complete (UINT16 handle, UINT8 status)
+{
+ 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)
+ if (p_dev_rec)
+ {
+ BTM_TRACE_EVENT6 ("Security Manager: auth_complete PairState: %s handle:%u status:%d dev->sec_state: %u Bda:%08x, RName:%s",
+ 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_EVENT3 ("Security Manager: auth_complete PairState: %s handle:%u status:%d",
+ 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;
+
+ 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 asleap. Let her try */
+ if (btm_cb.api.p_auth_complete_callback)
+ {
+ /* report the suthentication status */
+ if (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);
+ }
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+
+ /* 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)
+ btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_PEER_USER);
+ else
+ 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_DEBUG2 ("Collision retry sm4:x%x sec_flags:0x%x", 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_DEBUG2 ("Retry for missing key sm4:x%x sec_flags:0x%x", 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);
+
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE)
+ {
+ btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE);
+ }
+ return;
+ }
+
+ p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED;
+
+ /* 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);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_mkey_comp_event
+**
+** Description This function is when encryption of the connection is
+** completed by the LM
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_mkey_comp_event (UINT16 handle, UINT8 status, UINT8 key_flg)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
+ UINT8 bd_addr[BD_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} ;
+
+ BTM_TRACE_EVENT2 ("Security Manager: mkey comp status:%d State:%d",
+ status, (p_dev_rec) ? p_dev_rec->sec_state : 0);
+
+ /* If encryption setup failed, notify the waiting layer */
+ /* There is no next procedure or start of procedure failed, notify the waiting layer */
+ if (btm_cb.mkey_cback)
+ {
+ if (!p_dev_rec)
+ (btm_cb.mkey_cback)(bd_addr, status, key_flg );
+ else
+ (btm_cb.mkey_cback)(p_dev_rec->bd_addr, status, key_flg );
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_encrypt_change
+**
+** Description This function is when encryption of the connection is
+** completed by the LM
+**
+** Returns void
+**
+*******************************************************************************/
+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);
+
+ BTM_TRACE_EVENT3 ("Security Manager: encrypt_change status:%d State:%d, encr_enable = %d",
+ status, (p_dev_rec) ? p_dev_rec->sec_state : 0, encr_enable);
+ BTM_TRACE_DEBUG1 ("before update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags );
+
+ /* 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)
+ p_dev_rec->sec_flags |= (BTM_SEC_AUTHENTICATED | BTM_SEC_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)
+ p_dev_rec->sec_flags &= ~BTM_SEC_ENCRYPTED;
+
+ BTM_TRACE_DEBUG1 ("after update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags );
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ if (p_dev_rec->device_type == BT_DEVICE_TYPE_BLE)
+ {
+ btm_ble_link_encrypted(p_dev_rec->bd_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;
+#endif
+
+ /* 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;
+ l2cu_resubmit_pending_sec_req (p_dev_rec->bd_addr);
+ }
+ 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);
+ 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);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_create_conn
+**
+** Description This function records current role and forwards request to
+** HCI
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN btm_sec_create_conn (BD_ADDR bda, UINT16 packet_types,
+ UINT8 page_scan_rep_mode, UINT8 page_scan_mode,
+ UINT16 clock_offset, UINT8 allow_switch)
+{
+ tBTM_SEC_DEV_REC *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);
+
+ btm_cb.acl_disc_reason = 0xff ;
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ p_dev_rec->role_master = TRUE;
+
+ /* If any SCO link up, do not allow a switch */
+ if (BTM_GetNumScoLinks() != 0)
+ allow_switch = HCI_CR_CONN_NOT_ALLOW_SWITCH;
+
+ return(btsnd_hcic_create_conn (bda, packet_types, page_scan_rep_mode,
+ page_scan_mode, clock_offset, allow_switch));
+}
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+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;
+
+ BTM_TRACE_EVENT0 ("btm_sec_connect_after_reject_timeout()");
+ 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_WARNING0 ("Security Manager: btm_sec_connect_after_reject_timeout: failed to start connection");
+
+ btm_sec_change_pairing_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, HCI_ERR_MEMORY_FULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_connected
+**
+** Description This function is when a connection to the peer device is
+** establsihed
+**
+** Returns void
+**
+*******************************************************************************/
+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;
+ BOOLEAN is_pairing_device = FALSE;
+ tACL_CONN *p_acl_cb;
+
+ btm_acl_resubmit_page();
+
+ /* Commenting out trace due to obf/compilation problems.
+ */
+#if (BT_USE_TRACES == TRUE)
+ if (p_dev_rec)
+ {
+ BTM_TRACE_EVENT6 ("Security Manager: btm_sec_connected in state: %s handle:%d status:%d enc_mode:%d bda:%x RName:%s",
+ 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_EVENT5 ("Security Manager: btm_sec_connected in state: %s handle:%d status:%d enc_mode:%d bda:%x ",
+ 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
+ {
+ /* can not find the device record and the status is error,
+ * just ignore it */
+ return;
+ }
+ }
+ else /* Update the timestamp for this device */
+ {
+ 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_WARNING0 ("Security Manager: btm_sec_connected: incoming connection failed without asking PIN");
+
+ 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);
+ }
+#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 BTM_DISC_DURING_RS == TRUE
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+#endif
+
+ 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_WARNING2 ("Security Manager: btm_sec_connected: HCI_Conn_Comp Flags:0x%04x, sm4: 0x%x",
+ 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);
+ 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_WARNING0 ("Security Manager: btm_sec_connected: Wait for incoming connection");
+ 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);
+ BTM_TRACE_DEBUG1 ("security_required:%x ", 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)
+ {
+ (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, status);
+ }
+ }
+ else if ((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_LINK_KEY_KNOWN;
+
+ /* We need to notify host that the key is not known any more */
+ 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);
+ }
+ }
+
+ 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);
+ else
+ btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING);
+
+ 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)
+ (*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);
+
+ 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);
+ 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_SetLinkSuperTout (p_acl_cb->remote_addr, btm_cb.btm_def_link_super_tout);
+ }
+ btm_acl_created (bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, handle, HCI_ROLE_SLAVE, FALSE);
+
+ /* 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);
+
+ if (enc_mode != HCI_ENCRYPT_MODE_DISABLED)
+ p_dev_rec->sec_flags |= (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED);
+
+ if (btm_cb.security_mode == BTM_SEC_MODE_LINK)
+ p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED;
+
+ 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_DEBUG1 ("is_originator:%d ", 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);
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_role_changed
+**
+** Description This function is colled when controller reports role
+** changed, or failed command status for Role Change request
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_sec_role_changed (void *p_ref_data)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = (tBTM_SEC_DEV_REC *)p_ref_data;
+ UINT8 res;
+
+ BTM_TRACE_EVENT0 ("Security Manager: role changed");
+
+ /* If this role switch was started by peer do not need to do anything */
+ if (p_dev_rec->sec_state != BTM_SEC_STATE_SWITCHING_ROLE)
+ return;
+
+ /* If serurity required was to FORCE switch and it failed, notify the waiting layer */
+ if (((p_dev_rec->security_required & BTM_SEC_FORCE_MASTER) && !p_dev_rec->role_master)
+ || ((p_dev_rec->security_required & BTM_SEC_FORCE_SLAVE) && p_dev_rec->role_master))
+ {
+ btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING);
+ return;
+ }
+
+ p_dev_rec->sec_flags |= BTM_SEC_ROLE_SWITCHED;
+
+ p_dev_rec->security_required &= ~(BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER |
+ BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+
+ if ((res = (UINT8)btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED)
+ {
+ btm_sec_dev_rec_cback_event (p_dev_rec, res);
+ }
+}
+
+/*******************************************************************************
+**
+** 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));
+}
+
+/*******************************************************************************
+**
+** 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;
+
+ /* If page was delayed for disc complete, can do it now */
+ btm_cb.discing = FALSE;
+
+ btm_acl_resubmit_page();
+
+ if (!p_dev_rec)
+ return;
+
+#if BTM_DISC_DURING_RS == TRUE
+ BTM_TRACE_ERROR0("btm_sec_disconnected - Clearing Pending flag");
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+#endif
+
+ /* clear unused flags */
+ p_dev_rec->sm4 &= BTM_SM4_TRUE;
+
+ BTM_TRACE_EVENT6("btm_sec_disconnected() sec_req:x%x State: %s reason:%d bda:%04x%08x RName:%s",
+ p_dev_rec->security_required, btm_pair_state_descr(btm_cb.pairing_state), reason, (p_dev_rec->bd_addr[0]<<8)+p_dev_rec->bd_addr[1],
+ (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);
+
+ BTM_TRACE_EVENT1("before Update sec_flags=0x%x", 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);
+ }
+ }
+
+ p_dev_rec->hci_handle = BTM_SEC_INVALID_HANDLE;
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+
+#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+ p_dev_rec->enc_key_size = 0;
+ btm_ble_resume_bg_conn(NULL, TRUE);
+ /* see sec_flags processing in btm_acl_removed */
+#endif
+ p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED);
+
+ p_dev_rec->security_required = BTM_SEC_NONE;
+ p_dev_rec->p_callback = NULL; /* when the peer device time out the authentication before we do, this call back must be reset here */
+ BTM_TRACE_EVENT1("after Update sec_flags=0x%x", p_dev_rec->sec_flags);
+}
+
+/*******************************************************************************
+**
+** 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;
+
+ BTM_TRACE_EVENT3 ("btm_sec_link_key_notification() BDA:%04x%08x, TYPE: %d",
+ (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 connection was made to do bonding restore link security if changed */
+ btm_restore_mode();
+
+ /* Override the key type if version is pre-1.1 */
+ if (btm_cb.devcb.local_version.hci_version < HCI_VERSION_1_1)
+ p_dev_rec->link_key_type = BTM_LKEY_TYPE_IGNORE;
+ 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;
+
+ 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);
+ }
+
+ /* 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)) )
+ {
+ BTM_TRACE_EVENT3 ("btm_sec_link_key_notification() Delayed BDA: %08x%04x Type:%d",
+ (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_EVENT3 ("rmt_io_caps:%d, sec_flags:x%x, dev_class[1]:x%02x", 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))
+ {
+ 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_SUCCESS);
+ }
+
+ /* 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)
+ {
+ (*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);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** 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_EVENT6 ("btm_sec_link_key_request() BDA: %02x:%02x:%02x:%02x:%02x:%02x",
+ p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
+
+ 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);
+
+ /* Only ask the host for a key if this guy is not already bonding */
+ if ( (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE)
+ || (memcmp (p_bda, btm_cb.pairing_bda, BD_ADDR_LEN) != 0) )
+ {
+ if (btm_cb.api.p_link_key_req_callback)
+ {
+ if ((*btm_cb.api.p_link_key_req_callback)(p_bda, p_dev_rec->link_key) == BTM_SUCCESS)
+ {
+ btsnd_hcic_link_key_req_reply (p_bda, p_dev_rec->link_key);
+ return;
+ }
+ }
+ }
+
+ /* The link key is not in the database and it is not known to the manager */
+ btsnd_hcic_link_key_neg_reply (p_bda);
+}
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+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];
+
+ 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);
+
+ BTM_TRACE_EVENT2 ("btm_sec_pairing_timeout() State: %s Flags: %u",
+ btm_pair_state_descr(p_cb->pairing_state), p_cb->pairing_flags);
+
+ 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 (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ 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 /* !BTM_IO_CAP_NONE */
+
+#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_ERROR2 ("btm_sec_pairing_timeout() BTM_PAIR_STATE_WAIT_DISCONNECT unknown BDA: %08x%04x",
+ (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);
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ break;
+
+ case BTM_PAIR_STATE_WAIT_AUTH_COMPLETE:
+ /* 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:
+ BTM_TRACE_WARNING1 ("btm_sec_pairing_timeout() not processed state: %s", btm_pair_state_descr(btm_cb.pairing_state));
+ btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** 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;
+
+ BTM_TRACE_EVENT3 ("btm_sec_pin_code_request() State: %s, BDA:%04x%08x",
+ 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] );
+
+ 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)
+ {
+ BTM_TRACE_WARNING1 ("btm_sec_pin_code_request() rejected - state: %s",
+ btm_pair_state_descr(btm_cb.pairing_state));
+
+#ifdef PORCHE_PAIRING_CONFLICT
+ /* reply pin code again due to counter in_rand when local initiates pairing */
+ BTM_TRACE_EVENT0 ("btm_sec_pin_code_request from remote dev. for local initiated pairing");
+ if(! btm_cb.pin_code_len_saved)
+ {
+ btsnd_hcic_pin_code_neg_reply (p_bda);
+ }
+ 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_EVENT0 ("btm_sec_pin_code_request fixed pin replying");
+ 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_EVENT0 ("btm_sec_pin_code_request bonding sending reply");
+ 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_WARNING3("btm_sec_pin_code_request(): Pairing disabled:%d; PIN callback:%x, Dev Rec:%x!",
+ 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);
+
+ /* Check if the name is known */
+ /* Even if name is not known we might not be able to get one */
+ /* this is the case when we are already getting something from the */
+ /* device, so HCI level is flow controlled */
+ /* Also cannot send remote name request while paging, i.e. connection is not completed */
+ if (p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN)
+ {
+ BTM_TRACE_EVENT0 ("btm_sec_pin_code_request going for callback");
+
+ 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);
+ }
+ else
+ {
+ BTM_TRACE_EVENT0 ("btm_sec_pin_code_request going for remote name");
+
+ /* We received PIN code request for the device with unknown name */
+ /* it is not user friendly just to ask for the PIN without name */
+ /* try to get name at first */
+ if (!btsnd_hcic_rmt_name_req (p_dev_rec->bd_addr,
+ HCI_PAGE_SCAN_REP_MODE_R1,
+ HCI_MANDATARY_PAGE_SCAN_MODE, 0))
+ {
+ p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
+ p_dev_rec->sec_bd_name[0] = 'f';
+ p_dev_rec->sec_bd_name[1] = '0';
+ BTM_TRACE_ERROR0 ("can not send rmt_name_req?? fake a name and call callback");
+
+ 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);
+ }
+ }
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+static tBTM_STATUS btm_sec_execute_procedure (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ BTM_TRACE_EVENT3 ("btm_sec_execute_procedure: Required:0x%x Flags:0x%x State:%d",
+ 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_EVENT0 ("Security Manager: Start get name");
+ if (!btm_sec_start_get_name (p_dev_rec))
+ {
+ return(BTM_NO_RESOURCES);
+ }
+ return(BTM_CMD_STARTED);
+ }
+
+ /* 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->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_EVENT0 ("Security Manager: Start authentication");
+
+ 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_EVENT0 ("Security Manager: Start encryption");
+
+ if (!btm_sec_start_encryption (p_dev_rec))
+ {
+ return(BTM_NO_RESOURCES);
+ }
+ return(BTM_CMD_STARTED);
+ }
+
+ /* 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_EVENT2 ("service id:%d, is trusted:%d",
+ 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_EVENT0 ("Security Manager: Start authorization");
+ 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_EVENT2 ("Security Manager: trusted:0x%04x%04x", p_dev_rec->trusted_mask[1], p_dev_rec->trusted_mask[0]);
+ BTM_TRACE_EVENT0 ("Security Manager: access granted");
+
+ 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;
+
+ 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);
+ if (result == BTM_SUCCESS)
+ {
+ p_dev_rec->sec_flags |= BTM_SEC_AUTHORIZED;
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ }
+ return(result);
+ }
+ btm_sec_start_get_name (p_dev_rec);
+ return(BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+**
+** 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[])
+{
+ int 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
+**
+*******************************************************************************/
+static 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_DEBUG0 ("btm_sec_find_mx_serv");
+ 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);
+}
+
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+static void btm_sec_collision_timeout (TIMER_LIST_ENT *p_tle)
+{
+ tBTM_STATUS status;
+
+ BTM_TRACE_EVENT0 ("btm_sec_collision_timeout()");
+ btm_cb.sec_collision_tle.param = 0;
+
+ 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);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_link_key_request
+**
+** 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);
+}
+
+/*******************************************************************************
+**
+** 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;
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL)
+ {
+ return(p_dev_rec->trusted_mask);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btm_restore_mode
+**
+** Description This function returns the security mode to previous setting
+** if it was changed during bonding.
+**
+**
+** Parameters: void
+**
+*******************************************************************************/
+static void btm_restore_mode(void)
+{
+ if (btm_cb.security_mode_changed)
+ {
+ btm_cb.security_mode_changed = FALSE;
+ BTM_TRACE_DEBUG1("btm_restore_mode: Authen Enable -> %d", (btm_cb.security_mode == BTM_SEC_MODE_LINK));
+ btsnd_hcic_write_auth_enable ((UINT8)(btm_cb.security_mode == BTM_SEC_MODE_LINK));
+ }
+
+ if (btm_cb.pin_type_changed)
+ {
+ btm_cb.pin_type_changed = FALSE;
+ btsnd_hcic_write_pin_type (btm_cb.cfg.pin_type);
+ }
+}
+
+
+/*******************************************************************************
+**
+** 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)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = &btm_cb.sec_dev_rec[0];
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++)
+ {
+ if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE)
+ && (p_dev_rec->sec_state == state))
+ return(p_dev_rec);
+ }
+ return(NULL);
+}
+
+/*******************************************************************************
+**
+** Function BTM_snd_conn_encrypt
+**
+** Description This function is called to start/stop encryption
+** Used by JSR-82
+**
+** Returns TRUE if request started
+**
+*******************************************************************************/
+BOOLEAN BTM_snd_conn_encrypt (UINT16 handle, BOOLEAN enable)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
+
+ BTM_TRACE_EVENT2 ("BTM_snd_conn_encrypt Security Manager: encrypt_change p_dev_rec : 0x%x, enable = %s", p_dev_rec, (enable == TRUE) ? "TRUE" : "FALSE");
+
+ if (!p_dev_rec)
+ {
+ BTM_TRACE_EVENT1 ("BTM_snd_conn_encrypt Error no p_dev_rec : 0x%x\n", p_dev_rec);
+ return(FALSE);
+ }
+
+ if ( p_dev_rec->sec_state == BTM_SEC_STATE_IDLE)
+ {
+ if (!btsnd_hcic_set_conn_encrypt (handle, enable))
+ return(FALSE);
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_ENCRYPTING;
+
+ return(TRUE);
+ }
+ else
+ return(FALSE);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_change_pairing_state
+**
+** Description This function is called to change pairing state
+**
+*******************************************************************************/
+static void btm_sec_change_pairing_state (tBTM_PAIRING_STATE new_state)
+{
+ tBTM_PAIRING_STATE old_state = btm_cb.pairing_state;
+
+ BTM_TRACE_EVENT1 ("btm_sec_change_pairing_state Old: %s", btm_pair_state_descr(btm_cb.pairing_state));
+ BTM_TRACE_EVENT2 ("btm_sec_change_pairing_state New: %s pairing_flags:0x%x",btm_pair_state_descr(new_state), btm_cb.pairing_flags);
+
+ 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;
+ btm_cb.pin_code_len = 0;
+
+ /* 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);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btm_pair_state_descr
+**
+** Description Return state description for tracing
+**
+*******************************************************************************/
+#if (BT_USE_TRACES == 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,"%hu",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)
+{
+ tBTM_SEC_CALLBACK *p_callback = p_dev_rec->p_callback;
+
+ if (p_dev_rec->p_callback)
+ {
+ p_dev_rec->p_callback = NULL;
+
+ (*p_callback) (p_dev_rec->bd_addr, p_dev_rec->p_ref_data, res);
+
+ }
+ btm_sec_check_pending_reqs();
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_queue_mx_request
+**
+** Description Return state description for tracing
+**
+*******************************************************************************/
+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;
+
+ p_e = (tBTM_SEC_QUEUE_ENTRY *)GKI_getbuf (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;
+
+ memcpy (p_e->bd_addr, bd_addr, BD_ADDR_LEN);
+
+ BTM_TRACE_EVENT4 ("btm_sec_queue_mx_request() PSM: 0x%04x Is_Orig: %u mx_proto_id: %u mx_chan_id: %u",
+ psm, is_orig, mx_proto_id, mx_chan_id);
+
+ GKI_enqueue (&btm_cb.sec_pending_q, p_e);
+
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+static BOOLEAN btm_sec_check_prefetch_pin (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+ 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);
+ BOOLEAN rv = FALSE;
+
+ if ((major == BTM_COD_MAJOR_AUDIO)
+ && ((minor == BTM_COD_MINOR_CONFM_HANDSFREE) || (minor == BTM_COD_MINOR_CAR_AUDIO)) )
+ {
+ BTM_TRACE_EVENT2 ("btm_sec_check_prefetch_pin: Skipping pre-fetch PIN for carkit COD Major: 0x%02x Minor: 0x%02x", 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_DEBUG0("btm_sec_check_prefetch_pin: PIN code callback called");
+ if (btm_bda_to_acl(p_dev_rec->bd_addr) == 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);
+ }
+ }
+
+ rv = TRUE;
+ }
+
+ return rv;
+}
+
+#if (BLE_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
+**
+*******************************************************************************/
+void btm_sec_clear_ble_keys (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+
+ BTM_TRACE_DEBUG0 ("btm_sec_clear_ble_keys: Clearing BLE Keys");
+#if (SMP_INCLUDED== TRUE)
+ p_dev_rec->ble.key_type = 0;
+ memset (&p_dev_rec->ble.keys, 0, sizeof(tBTM_SEC_BLE_KEYS));
+#endif
+ gatt_delete_dev_from_srv_chg_clt_list(p_dev_rec->bd_addr);
+}
+
+
+/*******************************************************************************
+**
+** 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 (SMP_INCLUDED== TRUE)
+ if (p_dev_rec && (p_dev_rec->ble.key_type || (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)))
+ {
+ is_bonded = TRUE;
+ }
+#endif
+ BTM_TRACE_DEBUG1 ("btm_sec_is_a_bonded_dev is_bonded=%d", is_bonded);
+ return(is_bonded);
+}
+
+/*******************************************************************************
+**
+** Function btm_sec_find_bonded_dev
+**
+** Description Find a bonded device starting from the specified index
+**
+** Returns TRUE - found a bonded device
+**
+*******************************************************************************/
+BOOLEAN btm_sec_find_bonded_dev (UINT8 start_idx, UINT8 *p_found_idx, tBTM_SEC_DEV_REC *p_rec)
+{
+ BOOLEAN found= FALSE;
+
+#if (SMP_INCLUDED== TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ int i;
+ if (start_idx >= BTM_SEC_MAX_DEVICE_RECORDS)
+ {
+ BTM_TRACE_DEBUG0 ("LE bonded device not found");
+ return found;
+ }
+
+ p_dev_rec = &btm_cb.sec_dev_rec[start_idx];
+ for (i = start_idx; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++)
+ {
+ if (p_dev_rec->ble.key_type || (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN))
+ {
+ *p_found_idx = i;
+ p_rec = p_dev_rec;
+ break;
+ }
+ }
+ BTM_TRACE_DEBUG1 ("btm_sec_find_bonded_dev=%d", found);
+#endif
+ return(found);
+}
+#endif /* BLE_INCLUDED */
+