#include "btm_int.h"
#include "btu.h"
#include "device/include/controller.h"
+#include "device/include/interop.h"
#include "hcidefs.h"
#include "hcimsgs.h"
+ #include "log/log.h"
#include "l2c_int.h"
#include "osi/include/osi.h"
BD_ADDR_LEN);
#endif
+ p->switch_role_failed_attempts = 0;
p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
btm_pm_sm_alloc(xx);
/* Finished if already in desired role */
if (p->link_role == new_role) return (BTM_SUCCESS);
+ if (interop_match_addr(INTEROP_DISABLE_ROLE_SWITCH,
+ (const bt_bdaddr_t*)&remote_bd_addr)) {
+ return BTM_DEV_BLACKLISTED;
+ }
+
#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);
return (BTM_BUSY);
}
+ if (interop_match_addr(INTEROP_DYNAMIC_ROLE_SWITCH,
+ (const bt_bdaddr_t*)&remote_bd_addr)) {
+ BTM_TRACE_DEBUG("%s, Device blacklisted under INTEROP_DYNAMIC_ROLE_SWITCH.",
+ __func__);
+ return BTM_DEV_BLACKLISTED;
+ }
+
status = BTM_ReadPowerMode(p->remote_addr, &pwr_mode);
if (status != BTM_SUCCESS) return (status);
* Returns void
*
******************************************************************************/
- void btm_read_remote_ext_features_complete(uint8_t* p) {
+ void btm_read_remote_ext_features_complete(uint8_t* p, uint8_t evt_len) {
tACL_CONN* p_acl_cb;
uint8_t page_num, max_page;
uint16_t handle;
BTM_TRACE_DEBUG("btm_read_remote_ext_features_complete");
+ if (evt_len < HCI_EXT_FEATURES_SUCCESS_EVT_LEN) {
+ android_errorWriteLog(0x534e4554, "141552859");
+ BTM_TRACE_ERROR(
+ "btm_read_remote_ext_features_complete evt length too short. length=%d",
+ evt_len);
+ return;
+ }
+
++p;
STREAM_TO_UINT16(handle, p);
STREAM_TO_UINT8(page_num, p);
return;
}
+ if (page_num > HCI_EXT_FEATURES_PAGE_MAX) {
+ android_errorWriteLog(0x534e4554, "141552859");
+ BTM_TRACE_ERROR("btm_read_remote_ext_features_complete num_page=%d invalid",
+ page_num);
+ return;
+ }
+
+ if (page_num > max_page) {
+ BTM_TRACE_WARNING(
+ "btm_read_remote_ext_features_complete num_page=%d, max_page=%d "
+ "invalid", page_num, max_page);
+ }
+
p_acl_cb = &btm_cb.acl_db[acl_idx];
/* Copy the received features page */
}
/*******************************************************************************
+*
+* Function btm_blacklist_role_change_device
+*
+* Description This function is used to blacklist the device if the role
+* switch fails for maximum number of times. It also removes
+* the device from the black list if the role switch succeeds.
+*
+* Input Parms bd_addr - remote BD addr
+* hci_status - role switch status
+*
+* Returns void
+*
+*******************************************************************************/
+void btm_blacklist_role_change_device(BD_ADDR bd_addr, uint8_t hci_status) {
+ tACL_CONN* p = btm_bda_to_acl(bd_addr, BT_TRANSPORT_BR_EDR);
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+
+ if (!p || !p_dev_rec) {
+ return;
+ }
+ if (hci_status == HCI_SUCCESS) {
+ p->switch_role_failed_attempts = 0;
+ return;
+ }
+
+ /* check for carkits */
+ const uint32_t cod_audio_device =
+ (BTM_COD_SERVICE_AUDIO | BTM_COD_MAJOR_AUDIO) << 8;
+ const uint32_t cod =
+ ((p_dev_rec->dev_class[0] << 16) | (p_dev_rec->dev_class[1] << 8) |
+ p_dev_rec->dev_class[2]) &
+ 0xffffff;
+ if ((hci_status != HCI_SUCCESS) &&
+ ((p->switch_role_state == BTM_ACL_SWKEY_STATE_SWITCHING) ||
+ (p->switch_role_state == BTM_ACL_SWKEY_STATE_IN_PROGRESS)) &&
+ ((cod & cod_audio_device) == cod_audio_device) &&
+ (!interop_match_addr(INTEROP_DYNAMIC_ROLE_SWITCH,
+ (const bt_bdaddr_t*)&bd_addr))) {
+ p->switch_role_failed_attempts++;
+ if (p->switch_role_failed_attempts == BTM_MAX_SW_ROLE_FAILED_ATTEMPTS) {
+ BTM_TRACE_WARNING(
+ "%s: Device %02x:%02x:%02x:%02x:%02x:%02x blacklisted for role "
+ "switching - multiple role switch failed attempts: %u",
+ __func__, bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4],
+ bd_addr[5], p->switch_role_failed_attempts);
+ interop_database_add(INTEROP_DYNAMIC_ROLE_SWITCH,
+ (const bt_bdaddr_t*)&bd_addr, 3);
+ }
+ }
+}
+
+/*******************************************************************************
*
* Function btm_acl_role_changed
*
#include <base/callback.h>
#include <base/location.h>
#include <base/logging.h>
-#include <log/log.h>
+#include <base/threading/thread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using tracked_objects::Location;
-// TODO(zachoverflow): remove this horrible hack
-extern fixed_queue_t* btu_hci_msg_queue;
-
extern void btm_process_cancel_complete(uint8_t status, uint8_t mode);
extern void btm_ble_test_command_complete(uint8_t* p);
static void btu_hcif_rmt_name_request_comp_evt(uint8_t* p, uint16_t evt_len);
static void btu_hcif_encryption_change_evt(uint8_t* p);
static void btu_hcif_read_rmt_features_comp_evt(uint8_t* p);
- static void btu_hcif_read_rmt_ext_features_comp_evt(uint8_t* p);
+ static void btu_hcif_read_rmt_ext_features_comp_evt(uint8_t* p,
+ uint8_t evt_len);
static void btu_hcif_read_rmt_version_comp_evt(uint8_t* p);
static void btu_hcif_qos_setup_comp_evt(uint8_t* p);
static void btu_hcif_command_complete_evt(BT_HDR* response, void* context);
static void btu_ble_proc_enhanced_conn_cmpl(uint8_t* p, uint16_t evt_len);
#endif
+static void do_in_hci_thread(const tracked_objects::Location& from_here,
+ const base::Closure& task) {
+ base::MessageLoop* hci_message_loop = get_message_loop();
+ if (!hci_message_loop || !hci_message_loop->task_runner().get()) {
+ LOG_ERROR(LOG_TAG, "%s: HCI message loop not running, accessed from %s",
+ __func__, from_here.ToString().c_str());
+ return;
+ }
+
+ hci_message_loop->task_runner()->PostTask(from_here, task);
+}
+
/*******************************************************************************
*
* Function btu_hcif_process_event
btu_hcif_read_rmt_features_comp_evt(p);
break;
case HCI_READ_RMT_EXT_FEATURES_COMP_EVT:
- btu_hcif_read_rmt_ext_features_comp_evt(p);
+ btu_hcif_read_rmt_ext_features_comp_evt(p, hci_evt_len);
break;
case HCI_READ_RMT_VERSION_COMP_EVT:
btu_hcif_read_rmt_version_comp_evt(p);
cb_wrapper->posted_from.~Location();
}
-static void btu_hcif_command_complete_evt_with_cb_on_task(BT_HDR* event) {
- command_complete_hack_t* hack = (command_complete_hack_t*)&event->data[0];
-
+static void btu_hcif_command_complete_evt_with_cb_on_task(BT_HDR* event,
+ void* context) {
command_opcode_t opcode;
uint8_t* stream =
- hack->response->data + hack->response->offset +
+ event->data + event->offset +
3; // 2 to skip the event headers, 1 to skip the command credits
STREAM_TO_UINT16(opcode, stream);
- cmd_with_cb_data* cb_wrapper = (cmd_with_cb_data*)hack->context;
+ cmd_with_cb_data* cb_wrapper = (cmd_with_cb_data*)context;
HCI_TRACE_DEBUG("command complete for: %s",
cb_wrapper->posted_from.ToString().c_str());
- cb_wrapper->cb.Run(stream, hack->response->len - 5);
+ cb_wrapper->cb.Run(stream, event->len - 5);
cmd_with_cb_data_cleanup(cb_wrapper);
osi_free(cb_wrapper);
- osi_free(hack->response);
osi_free(event);
}
static void btu_hcif_command_complete_evt_with_cb(BT_HDR* response,
void* context) {
- BT_HDR* event = static_cast<BT_HDR*>(
- osi_calloc(sizeof(BT_HDR) + sizeof(command_complete_hack_t)));
- command_complete_hack_t* hack = (command_complete_hack_t*)&event->data[0];
-
- hack->callback = btu_hcif_command_complete_evt_with_cb_on_task;
- hack->response = response;
- hack->context = context;
- event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK;
-
- fixed_queue_enqueue(btu_hci_msg_queue, event);
+ do_in_hci_thread(FROM_HERE,
+ base::Bind(btu_hcif_command_complete_evt_with_cb_on_task,
+ response, context));
}
-static void btu_hcif_command_status_evt_with_cb_on_task(BT_HDR* event) {
- command_status_hack_t* hack = (command_status_hack_t*)&event->data[0];
-
+static void btu_hcif_command_status_evt_with_cb_on_task(uint8_t status,
+ BT_HDR* event,
+ void* context) {
command_opcode_t opcode;
- uint8_t* stream = hack->command->data + hack->command->offset;
+ uint8_t* stream = event->data + event->offset;
STREAM_TO_UINT16(opcode, stream);
- CHECK(hack->status != 0);
+ CHECK(status != 0);
// report command status error
- cmd_with_cb_data* cb_wrapper = (cmd_with_cb_data*)hack->context;
+ cmd_with_cb_data* cb_wrapper = (cmd_with_cb_data*)context;
HCI_TRACE_DEBUG("command status for: %s",
cb_wrapper->posted_from.ToString().c_str());
- cb_wrapper->cb.Run(&hack->status, sizeof(uint16_t));
+ cb_wrapper->cb.Run(&status, sizeof(uint16_t));
cmd_with_cb_data_cleanup(cb_wrapper);
osi_free(cb_wrapper);
- osi_free(hack->command);
osi_free(event);
}
return;
}
- BT_HDR* event = static_cast<BT_HDR*>(
- osi_calloc(sizeof(BT_HDR) + sizeof(command_status_hack_t)));
- command_status_hack_t* hack = (command_status_hack_t*)&event->data[0];
-
- hack->callback = btu_hcif_command_status_evt_with_cb_on_task;
- hack->status = status;
- hack->command = command;
- hack->context = context;
-
- event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK;
-
- fixed_queue_enqueue(btu_hci_msg_queue, event);
+ do_in_hci_thread(
+ FROM_HERE, base::Bind(btu_hcif_command_status_evt_with_cb_on_task, status,
+ command, context));
}
/* This function is called to send commands to the Host Controller. |cb| is
btm_sec_rmt_name_request_complete(bd_addr, p, status);
}
-constexpr uint8_t MIN_KEY_SIZE = 7;
-
-static void read_encryption_key_size_complete_after_encryption_change(
- uint8_t status, uint16_t handle, uint8_t key_size) {
- if (status == HCI_ERR_INSUFFCIENT_SECURITY) {
- /* If remote device stop the encryption before we call "Read Encryption Key
- * Size", we might receive Insufficient Security, which means that link is
- * no longer encrypted. */
- HCI_TRACE_WARNING("%s encryption stopped on link: 0x%02x", __func__,
- handle);
- return;
- }
-
- if (status != HCI_SUCCESS) {
- HCI_TRACE_WARNING("%s: disconnecting, status: 0x%02x", __func__, status);
- btsnd_hcic_disconnect(handle, HCI_ERR_PEER_USER);
- return;
- }
-
- if (key_size < MIN_KEY_SIZE) {
- android_errorWriteLog(0x534e4554, "124301137");
- HCI_TRACE_ERROR(
- "%s encryption key too short, disconnecting. handle: 0x%02x, key_size: "
- "%d",
- __func__, handle, key_size);
-
- btsnd_hcic_disconnect(handle, HCI_ERR_HOST_REJECT_SECURITY);
- return;
- }
-
- // good key size - succeed
- btm_acl_encrypt_change(handle, status, 1 /* enable */);
- btm_sec_encrypt_change(handle, status, 1 /* enable */);
-}
/*******************************************************************************
*
* Function btu_hcif_encryption_change_evt
STREAM_TO_UINT16(handle, p);
STREAM_TO_UINT8(encr_enable, p);
- if (status != HCI_SUCCESS || encr_enable == 0 ||
- BTM_IsBleConnection(handle)) {
- btm_acl_encrypt_change(handle, status, encr_enable);
- btm_sec_encrypt_change(handle, status, encr_enable);
- } else {
- btsnd_hcic_read_encryption_key_size(
- handle,
- base::Bind(&read_encryption_key_size_complete_after_encryption_change));
- }
+ btm_acl_encrypt_change(handle, status, encr_enable);
+ btm_sec_encrypt_change(handle, status, encr_enable);
}
/*******************************************************************************
* Returns void
*
******************************************************************************/
- static void btu_hcif_read_rmt_ext_features_comp_evt(uint8_t* p) {
+ static void btu_hcif_read_rmt_ext_features_comp_evt(uint8_t* p,
+ uint8_t evt_len) {
uint8_t* p_cur = p;
uint8_t status;
uint16_t handle;
STREAM_TO_UINT8(status, p_cur);
if (status == HCI_SUCCESS)
- btm_read_remote_ext_features_complete(p);
+ btm_read_remote_ext_features_complete(p, evt_len);
else {
STREAM_TO_UINT16(handle, p_cur);
btm_read_remote_ext_features_failed(status, handle);
* Returns void
*
******************************************************************************/
-static void btu_hcif_command_complete_evt_on_task(BT_HDR* event) {
- command_complete_hack_t* hack = (command_complete_hack_t*)&event->data[0];
-
+static void btu_hcif_command_complete_evt_on_task(BT_HDR* event,
+ void* context) {
command_opcode_t opcode;
uint8_t* stream =
- hack->response->data + hack->response->offset +
+ event->data + event->offset +
3; // 2 to skip the event headers, 1 to skip the command credits
STREAM_TO_UINT16(opcode, stream);
btu_hcif_hdl_command_complete(
opcode, stream,
- hack->response->len -
+ event->len -
5, // 3 for the command complete headers, 2 for the event headers
- hack->context);
+ context);
- osi_free(hack->response);
osi_free(event);
}
static void btu_hcif_command_complete_evt(BT_HDR* response, void* context) {
- BT_HDR* event = static_cast<BT_HDR*>(
- osi_calloc(sizeof(BT_HDR) + sizeof(command_complete_hack_t)));
- command_complete_hack_t* hack = (command_complete_hack_t*)&event->data[0];
-
- hack->callback = btu_hcif_command_complete_evt_on_task;
- hack->response = response;
- hack->context = context;
-
- event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK;
-
- fixed_queue_enqueue(btu_hci_msg_queue, event);
+ do_in_hci_thread(FROM_HERE, base::Bind(btu_hcif_command_complete_evt_on_task,
+ response, context));
}
/*******************************************************************************
* Returns void
*
******************************************************************************/
-static void btu_hcif_command_status_evt_on_task(BT_HDR* event) {
- command_status_hack_t* hack = (command_status_hack_t*)&event->data[0];
-
+static void btu_hcif_command_status_evt_on_task(uint8_t status, BT_HDR* event,
+ void* context) {
command_opcode_t opcode;
- uint8_t* stream = hack->command->data + hack->command->offset;
+ uint8_t* stream = event->data + event->offset;
STREAM_TO_UINT16(opcode, stream);
- btu_hcif_hdl_command_status(opcode, hack->status, stream, hack->context);
-
- osi_free(hack->command);
+ btu_hcif_hdl_command_status(opcode, status, stream, context);
osi_free(event);
}
static void btu_hcif_command_status_evt(uint8_t status, BT_HDR* command,
void* context) {
- BT_HDR* event = static_cast<BT_HDR*>(
- osi_calloc(sizeof(BT_HDR) + sizeof(command_status_hack_t)));
- command_status_hack_t* hack = (command_status_hack_t*)&event->data[0];
-
- hack->callback = btu_hcif_command_status_evt_on_task;
- hack->status = status;
- hack->command = command;
- hack->context = context;
-
- event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK;
-
- fixed_queue_enqueue(btu_hci_msg_queue, event);
+ do_in_hci_thread(FROM_HERE, base::Bind(btu_hcif_command_status_evt_on_task,
+ status, command, context));
}
/*******************************************************************************
STREAM_TO_BDADDR(bda, p);
STREAM_TO_UINT8(role, p);
+ btm_blacklist_role_change_device(bda, status);
l2c_link_role_changed(bda, role, status);
btm_acl_role_changed(status, bda, role);
}
* End of Simple Pairing Events
**********************************************/
-static void read_encryption_key_size_complete_after_key_refresh(
- uint8_t status, uint16_t handle, uint8_t key_size) {
- if (status == HCI_ERR_INSUFFCIENT_SECURITY) {
- /* If remote device stop the encryption before we call "Read Encryption Key
- * Size", we might receive Insufficient Security, which means that link is
- * no longer encrypted. */
- HCI_TRACE_WARNING("%s encryption stopped on link: 0x%02x", __func__,
- handle);
- return;
- }
-
- if (status != HCI_SUCCESS) {
- HCI_TRACE_WARNING("%s: disconnecting, status: 0x%02x", __func__, status);
- btsnd_hcic_disconnect(handle, HCI_ERR_PEER_USER);
- return;
- }
-
- if (key_size < MIN_KEY_SIZE) {
- android_errorWriteLog(0x534e4554, "124301137");
- HCI_TRACE_ERROR(
- "%s encryption key too short, disconnecting. handle: 0x%02x, key_size: "
- "%d",
- __func__, handle, key_size);
-
- btsnd_hcic_disconnect(handle, HCI_ERR_HOST_REJECT_SECURITY);
- return;
- }
-
- btm_sec_encrypt_change(handle, status, 1 /* enc_enable */);
-}
-
+/**********************************************
+ * BLE Events
+ **********************************************/
static void btu_hcif_encryption_key_refresh_cmpl_evt(uint8_t* p) {
uint8_t status;
+ uint8_t enc_enable = 0;
uint16_t handle;
STREAM_TO_UINT8(status, p);
STREAM_TO_UINT16(handle, p);
- if (status != HCI_SUCCESS || BTM_IsBleConnection(handle)) {
- btm_sec_encrypt_change(handle, status, (status == HCI_SUCCESS) ? 1 : 0);
- } else {
- btsnd_hcic_read_encryption_key_size(
- handle,
- base::Bind(&read_encryption_key_size_complete_after_key_refresh));
- }
-}
+ if (status == HCI_SUCCESS) enc_enable = 1;
-/**********************************************
- * BLE Events
- **********************************************/
+ btm_sec_encrypt_change(handle, status, enc_enable);
+}
static void btu_ble_ll_conn_complete_evt(uint8_t* p, uint16_t evt_len) {
btm_ble_conn_complete(p, evt_len, false);