uint64_t energy_used;
} btif_activity_energy_info_cb_t;
-typedef struct
-{
- unsigned int manufact_id;
-}skip_sdp_entry_t;
-
typedef enum
{
BTIF_DM_FUNC_CREATE_BOND,
#define MAX_BTIF_BOND_EVENT_ENTRIES 15
-static skip_sdp_entry_t sdp_blacklist[] = {{76}}; //Apple Mouse and Keyboard
-
/* This flag will be true if HCI_Inquiry is in progress */
static BOOLEAN btif_dm_inquiry_in_progress = FALSE;
/*****************************************************************************
**
-** Function check_sdp_bl
+** Function interop_skip_authentication
+**
+** Description Checks if a given device is blacklisted to skip authentication
+**
+** Parameters remote_bdaddr
+**
+** Returns TRUE if the device is present in blacklist, else FALSE
+**
+*******************************************************************************/
+static bool interop_skip_authentication(bt_bdaddr_t * remote_bdaddr)
+{
+ if (remote_bdaddr == NULL)
+ {
+ LOG_WARN(LOG_TAG, "%s: remote_bdaddr = NULL, returning false", __func__);
+ return FALSE;
+ }
+
+ if (interop_match_addr(INTEROP_DISABLE_AUTH_FOR_HID_POINTING, remote_bdaddr))
+ return TRUE;
+
+ bt_property_t prop_name;
+ bt_bdname_t bdname;
+
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME,
+ sizeof(bt_bdname_t), &bdname);
+ if (btif_storage_get_remote_device_property((bt_bdaddr_t *)remote_bdaddr,
+ &prop_name) != BT_STATUS_SUCCESS)
+ {
+ LOG_WARN(LOG_TAG, "%s: BT_PROPERTY_BDNAME failed, returning false", __func__);
+ return FALSE;
+ }
+
+ if (strlen((const char *)bdname.name) != 0 &&
+ interop_match_name(INTEROP_DISABLE_SDP_AFTER_PAIRING, (const char *)bdname.name))
+ return TRUE;
+
+ return FALSE;
+}
+
+/*****************************************************************************
+**
+** Function interop_skip_sdp
**
** Description Checks if a given device is blacklisted to skip sdp
**
-** Parameters skip_sdp_entry
+** Parameters remote_bdaddr
**
** Returns TRUE if the device is present in blacklist, else FALSE
**
*******************************************************************************/
-BOOLEAN check_sdp_bl(const bt_bdaddr_t *remote_bdaddr)
+BOOLEAN interop_skip_sdp(const bt_bdaddr_t *remote_bdaddr)
{
- UINT16 manufacturer = 0;
- UINT8 lmp_ver = 0;
- UINT16 lmp_subver = 0;
+ if (remote_bdaddr == NULL) {
+ LOG_WARN(LOG_TAG, "%s: remote_bdaddr = NULL, returning false", __func__);
+ return FALSE;
+ }
+
+ if (interop_match_addr(INTEROP_DISABLE_SDP_AFTER_PAIRING, remote_bdaddr)) {
+ LOG_WARN(LOG_TAG, "%s: device is in blacklist for skipping sdp", __func__);
+ return TRUE;
+ }
+
bt_property_t prop_name;
- bt_remote_version_t info;
+ bt_bdname_t bdname;
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME,
+ sizeof(bt_bdname_t), &bdname);
+ if (btif_storage_get_remote_device_property((bt_bdaddr_t *)remote_bdaddr,
+ &prop_name) != BT_STATUS_SUCCESS)
+ {
+ LOG_WARN(LOG_TAG, "%s: BT_PROPERTY_BDNAME failed, returning false", __func__);
+ return FALSE;
+ }
+
+ if (strlen((const char *)bdname.name) != 0 &&
+ interop_match_name(INTEROP_DISABLE_SDP_AFTER_PAIRING, (const char *)bdname.name))
+ return TRUE;
if (remote_bdaddr == NULL)
return FALSE;
-/* fetch additional info about remote device used in iop query */
+ UINT16 manufacturer = 0;
+ UINT8 lmp_ver = 0;
+ UINT16 lmp_subver = 0;
+
+ /* fetch additional info about remote device used in iop query */
BTM_ReadRemoteVersion(*(BD_ADDR*)remote_bdaddr, &lmp_ver,
&manufacturer, &lmp_subver);
- /* if not available yet, try fetching from config database */
+ bt_remote_version_t info;
+
+ /* if not available yet, try fetching from config database */
BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_REMOTE_VERSION_INFO,
sizeof(bt_remote_version_t), &info);
&prop_name) != BT_STATUS_SUCCESS)
{
+ APPL_TRACE_WARNING("%s: BT_PROPERTY_REMOTE_VERSION_INFO failed, returning false", __func__);
return FALSE;
}
manufacturer = info.manufacturer;
- for (unsigned int i = 0; i < ARRAY_SIZE(sdp_blacklist); i++)
- {
- if (manufacturer == sdp_blacklist[i].manufact_id)
- return TRUE;
- }
+ if (manufacturer != 0 &&
+ interop_match_manufacturer(INTEROP_DISABLE_SDP_AFTER_PAIRING, manufacturer))
+ return TRUE;
+
return FALSE;
}
bt_bdaddr_t bd_addr;
bt_status_t status = BT_STATUS_FAIL;
bt_bond_state_t state = BT_BOND_STATE_NONE;
- BOOLEAN skip_sdp = FALSE;
BTIF_TRACE_DEBUG("%s: bond state=%d", __func__, pairing_cb.state);
btif_update_remote_properties(p_auth_cmpl->bd_addr,
p_auth_cmpl->bd_name, NULL, p_auth_cmpl->dev_type);
pairing_cb.timeout_retries = 0;
- status = BT_STATUS_SUCCESS;
- state = BT_BOND_STATE_BONDED;
- bdcpy(bd_addr.address, p_auth_cmpl->bd_addr);
- if (check_sdp_bl(&bd_addr) && check_cod_hid(&bd_addr))
+ if (interop_skip_sdp(&bd_addr) && check_cod_hid(&bd_addr))
{
- LOG_WARN(LOG_TAG, "%s:skip SDP", __FUNCTION__);
- skip_sdp = TRUE;
- }
- if(!pairing_cb.is_local_initiated && skip_sdp)
- {
- bond_state_changed(status, &bd_addr, state);
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDED);
- LOG_WARN(LOG_TAG, "%s: Incoming HID Connection",__FUNCTION__);
+ BTIF_TRACE_DEBUG("%s: HID Connection from "
+ "blacklisted device, skipping sdp",__FUNCTION__);
bt_property_t prop;
- bt_bdaddr_t bd_addr;
bt_uuid_t uuid;
char uuid_str[128] = UUID_HUMAN_INTERFACE_DEVICE;
prop.val = uuid.uu;
prop.len = MAX_UUID_SIZE;
+ /* Also write this to the NVRAM */
+ status = btif_storage_set_remote_device_property(&bd_addr, &prop);
/* Send the event to the BTIF */
HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
BT_STATUS_SUCCESS, &bd_addr, 1, &prop);
}
else
{
+ status = BT_STATUS_SUCCESS;
+ state = BT_BOND_STATE_BONDED;
+
+ /* Trigger SDP on the device */
+ pairing_cb.sdp_attempts = 1;
+
#if BLE_INCLUDED == TRUE
BOOLEAN is_crosskey = FALSE;
/* If bonded due to cross-key, save the static address too*/
/*******************************************************************************
**
+** Function btif_dm_hh_open_success
+**
+** Description informs the upper layers if the HH conneciton is successfully opened.
+**
+** Returns none
+**
+*******************************************************************************/
+
+void btif_dm_hh_open_success(bt_bdaddr_t *bdaddr)
+{
+ if (pairing_cb.state != BT_BOND_STATE_BONDING ||
+ bdcmp(bdaddr->address, pairing_cb.bd_addr))
+ return;
+
+ if (interop_skip_authentication(bdaddr) && check_cod_hid(bdaddr))
+ {
+ bt_status_t status;
+ LINK_KEY link_key = {0};
+ bond_state_changed(BT_STATUS_SUCCESS, bdaddr, BT_BOND_STATE_BONDED);
+ BTIF_TRACE_DEBUG("%s: Device is blacklisted for authentication", __func__);
+ bt_property_t prop;
+ bt_uuid_t uuid;
+ char uuid_str[128] = UUID_HUMAN_INTERFACE_DEVICE;
+ string_to_uuid(uuid_str, &uuid);
+ prop.type = BT_PROPERTY_UUIDS;
+ prop.val = uuid.uu;
+ prop.len = MAX_UUID_SIZE;
+ // Also write this to the NVRAM
+ status = btif_storage_set_remote_device_property(bdaddr, &prop);
+ ASSERTC(status == BT_STATUS_SUCCESS, "storing remote services failed", status);
+ // Store fake link for device as bonded in nvram,
+ // otherwise on device reboot/bt off-on device will not be shown in paired list.
+ btif_storage_add_bonded_device(bdaddr, link_key, HCI_LKEY_TYPE_UNAUTH_COMB, 0);
+ // Send the event to the BTIF
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+ BT_STATUS_SUCCESS, bdaddr, 1, &prop);
+ }
+}
+
+/*******************************************************************************
+**
** Function btif_dm_hh_open_failed
**
** Description informs the upper layers if the HH have failed during bonding
extern void btif_dm_cb_remove_bond(bt_bdaddr_t *bd_addr);
extern BOOLEAN check_cod_hid(const bt_bdaddr_t *remote_bdaddr);
extern int scru_ascii_2_hex(char *p_ascii, int len, UINT8 *p_hex);
+extern void btif_dm_hh_open_success(bt_bdaddr_t *bdaddr);
extern void btif_dm_hh_open_failed(bt_bdaddr_t *bdaddr);
/*****************************************************************************
BTA_HhClose(p_data->conn.handle);
}
else {
+ btif_dm_hh_open_success((bt_bdaddr_t*)p_data->conn.bda);
BTIF_TRACE_WARNING("BTA_HH_OPEN_EVT: Found device...Getting dscp info for handle ... %d",p_data->conn.handle);
memcpy(&(p_dev->bd_addr), p_data->conn.bda, BD_ADDR_LEN);
btif_hh_cb.status = BTIF_HH_DEV_CONNECTED;
// re-transmissions after switching to 2DH packets.
//
// Disable 3Mbps packets and use only 2Mbps packets for ACL links when streaming audio.
- INTEROP_2MBPS_LINK_ONLY
+ INTEROP_2MBPS_LINK_ONLY,
+
+ // Some HID devices have proven problematic behaviour if SDP is initiated again
+ // while HID connection is in progress or if more than 1 SDP connection is created
+ // with those HID devices rsulting in issues of connection failure with such devices.
+ // To avoid degrading the user experience with those devices, SDP is not attempted
+ // as part of pairing process.
+ INTEROP_DISABLE_SDP_AFTER_PAIRING,
+
+ // Some HID pointing devices have proven problematic behaviour if pairing is initiated with
+ // them, resulting in no response for authentication request and ultimately resulting
+ // in connection failure.
+ // To avoid degrading the user experience with those devices, authentication request
+ // is not requested explictly.
+ INTEROP_DISABLE_AUTH_FOR_HID_POINTING,
} interop_feature_t;
// Check if a given |addr| matches a known interoperability workaround as identified
// |name| cannot be null and must be null terminated.
bool interop_match_name(const interop_feature_t feature, const char *name);
+// Check if a given remote device |name| matches a known interoperability workaround.
+// Name comparisons are case sensitive and do not allow for partial matches. As in, if
+// |name| is "TEST" and a workaround exists for "TESTING", then this function will
+// return false. But, if |name| is "TESTING" and a workaround exists for "TEST", this
+// function will return true.
+// |name| cannot be null and must be null terminated.
+bool interop_match_name(const interop_feature_t feature, const char *name);
+
+// Check if a given |manufacturer| matches a known interoperability workaround as identified
+// by the |interop_feature_t| enum. This API is used for manufacturer based lookups
+// where more information is not available.
+bool interop_match_manufacturer(const interop_feature_t feature, uint16_t manufacturer);
+
// Add a dynamic interop database entry for a device matching the first |length| bytes
// of |addr|, implementing the workaround identified by |feature|. |addr| may not be
// null and |length| must be greater than 0 and less than sizeof(bt_bdaddr_t).
// Unknown keyboard (carried over from auto_pair_devlist.conf)
{{{0x00, 0x0F, 0xF6, 0,0,0}}, 3, INTEROP_KEYBOARD_REQUIRES_FIXED_PIN},
+
+ // Apple Magic Mouse
+ {{{0x04, 0x0C, 0xCE, 0,0,0}}, 3, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ // Bluetooth Laser Travel Mouse
+ {{{0x00, 0x07, 0x61, 0,0,0}}, 3, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ // Microsoft Bluetooth Notebook Mouse 5000
+ {{{0x00, 0x1d, 0xd8, 0,0,0}}, 3, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ // Logitech MX Revolution Mouse
+ {{{0x00, 0x1f, 0x20, 0,0,0}}, 3, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ // Rapoo 6080 mouse
+ {{{0x6c, 0x5d, 0x63, 0,0,0}}, 3, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ // Microsoft Sculpt Touch Mouse
+ {{{0x28, 0x18, 0x78, 0,0,0}}, 3, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+
+ // Targus BT Laser Notebook Mouse
+ {{{0x00, 0x12, 0xA1, 0,0,0}}, 3, INTEROP_DISABLE_AUTH_FOR_HID_POINTING},
};
typedef struct {
- char name[20];
+ char name[40];
size_t length;
interop_feature_t feature;
} interop_name_entry_t;
// Subaru car kits ("CAR M_MEDIA")
{"CAR", 3, INTEROP_DISABLE_AUTO_PAIRING},
+
+ // HID SDP Blacklist
+ {"Apple Magic Mouse", 17, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ {"Bluetooth Laser Travel Mouse", 28, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ {"Microsoft Bluetooth Notebook Mouse 5000", 39, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ {"Logitech MX Revolution Mouse", 28, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+ {"Microsoft Sculpt Touch Mouse", 28, INTEROP_DISABLE_SDP_AFTER_PAIRING},
+
+ // HID Authentication Blacklist
+ {"Targus BT Laser Notebook Mouse", 30, INTEROP_DISABLE_AUTH_FOR_HID_POINTING},
+};
+
+typedef struct {
+ uint16_t manufacturer;
+ interop_feature_t feature;
+} interop_manufacturer_t;
+
+static const interop_manufacturer_t interop_manufacturer_database[] = {
+ // Apple Devices
+ {76, INTEROP_DISABLE_SDP_AFTER_PAIRING},
};
if (feature == interop_name_database[i].feature &&
strlen(name) >= interop_name_database[i].length &&
strncmp(name, interop_name_database[i].name, interop_name_database[i].length) == 0) {
+ LOG_WARN(LOG_TAG, "%s() Device with name: %s is a match for interop workaround %s", __func__,
+ name, interop_feature_string_(feature));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool interop_match_manufacturer(const interop_feature_t feature, uint16_t manufacturer) {
+ const size_t db_size = sizeof(interop_manufacturer_database) / sizeof(interop_manufacturer_t);
+
+ for (size_t i = 0; i != db_size; ++i) {
+ if (feature == interop_manufacturer_database[i].feature &&
+ manufacturer == interop_manufacturer_database[i].manufacturer) {
+ LOG_WARN(LOG_TAG, "%s() Device with manufacturer id: %d is a match for interop "
+ "workaround %s", __func__, manufacturer, interop_feature_string_(feature));
return true;
}
}
CASE_RETURN_STR(INTEROP_DISABLE_AUTO_PAIRING)
CASE_RETURN_STR(INTEROP_KEYBOARD_REQUIRES_FIXED_PIN)
CASE_RETURN_STR(INTEROP_2MBPS_LINK_ONLY)
+ CASE_RETURN_STR(INTEROP_DISABLE_SDP_AFTER_PAIRING)
+ CASE_RETURN_STR(INTEROP_DISABLE_AUTH_FOR_HID_POINTING)
}
return "UNKNOWN";
#include "osi/include/osi.h"
+#include "device/include/interop.h"
extern fixed_queue_t *btu_general_alarm_queue;
p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* In case disconnection occurs before security is completed, then set CLOSE_EVT reason code to 'connection failure' */
p_hcon->conn_state = HID_CONN_STATE_SECURITY;
- if(btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
- FALSE, BTM_SEC_PROTO_HID,
- (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
- &hidh_sec_check_complete_term, p_dev) == BTM_CMD_STARTED)
+ if (!interop_match_addr(INTEROP_DISABLE_AUTH_FOR_HID_POINTING, (bt_bdaddr_t*)p_dev->addr))
{
+ if(btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
+ FALSE, BTM_SEC_PROTO_HID,
+ (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
+ &hidh_sec_check_complete_term, p_dev) == BTM_CMD_STARTED)
+ {
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
+ }
+ }
+ else
+ {
+ /* device is blacklisted, don't perform authentication */
L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
+ hidh_sec_check_complete_term(p_dev->addr, BT_TRANSPORT_BR_EDR,
+ p_dev, BTM_SUCCESS);
}
return;
p_hcon->conn_state = HID_CONN_STATE_SECURITY;
p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* In case disconnection occurs before security is completed, then set CLOSE_EVT reason code to "connection failure" */
- btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
- TRUE, BTM_SEC_PROTO_HID,
- (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
- &hidh_sec_check_complete_orig, p_dev);
+ if (!interop_match_addr(INTEROP_DISABLE_AUTH_FOR_HID_POINTING, (bt_bdaddr_t *)p_dev->addr))
+ {
+ btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
+ TRUE, BTM_SEC_PROTO_HID,
+ (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
+ &hidh_sec_check_complete_orig, p_dev);
+ }
+ else
+ {
+ /* device is blacklisted, don't perform authentication */
+ hidh_sec_check_complete_orig(p_dev->addr, BT_TRANSPORT_BR_EDR,
+ p_dev, BTM_SUCCESS);
+ }
}
else
{