From: Hemant Gupta Date: Sun, 26 Apr 2015 05:02:57 +0000 (+0530) Subject: HID: Enhance blacklist logic for restricting SDP X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=69cb7c420ccc53ad0f0d5601707d5414bcea734a;p=android-x86%2Fsystem-bt.git HID: Enhance blacklist logic for restricting SDP Enhance existing blacklist logic for restricting SDP for HID devices, by adding BD address and name support in addition to manufacturer id. Also blacklist logic is added for HID devices not supporting authentication. - Targus mouse does not support authentication, so blacklist logic added to disable authentication for such HID devices. - Many HID mice return an out of resource error for incoming connections when more than 1 SDP connection is made to them. Current implementaion in BD stack performs SDP from 2 layers HID BTA layer to determine HID desritors for HID device and btif layer for determining uuid's supported. Blacklist logic is enhanced for such devices to not perform SDP from btif layer after authentication and directly inform upper layers that SDP is complete by adding support for BD address and name based addition to blacklist. Change-Id: I4fe1e016549bb55ad176cd014bf1d5da85b38353 CRs-Fixed: 465421, 568114 --- diff --git a/btif/src/btif_dm.c b/btif/src/btif_dm.c index c3e129f50..052f785e3 100644 --- a/btif/src/btif_dm.c +++ b/btif/src/btif_dm.c @@ -167,11 +167,6 @@ typedef struct 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, @@ -194,8 +189,6 @@ typedef struct #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; @@ -513,31 +506,97 @@ BOOLEAN check_hid_le(const bt_bdaddr_t *remote_bdaddr) /***************************************************************************** ** -** 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); @@ -545,15 +604,15 @@ BOOLEAN check_sdp_bl(const bt_bdaddr_t *remote_bdaddr) &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; } @@ -1144,7 +1203,6 @@ static void btif_dm_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl) 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); @@ -1189,22 +1247,14 @@ static void btif_dm_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl) 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; @@ -1214,12 +1264,20 @@ static void btif_dm_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl) 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*/ @@ -2526,6 +2584,47 @@ bt_status_t btif_dm_cancel_bond(const bt_bdaddr_t *bd_addr) /******************************************************************************* ** +** 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 diff --git a/btif/src/btif_hh.c b/btif/src/btif_hh.c index f461e4828..a4057cca5 100644 --- a/btif/src/btif_hh.c +++ b/btif/src/btif_hh.c @@ -150,6 +150,7 @@ extern BOOLEAN check_cod(const bt_bdaddr_t *remote_bdaddr, uint32_t cod); 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); /***************************************************************************** @@ -793,6 +794,7 @@ static void btif_hh_upstreams_evt(UINT16 event, char* p_param) 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; diff --git a/device/include/interop.h b/device/include/interop.h index 05778a8f0..9021530b9 100644 --- a/device/include/interop.h +++ b/device/include/interop.h @@ -63,7 +63,21 @@ typedef enum { // 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 @@ -80,6 +94,19 @@ bool interop_match_addr(const interop_feature_t feature, const bt_bdaddr_t *addr // |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). diff --git a/device/include/interop_database.h b/device/include/interop_database.h index 49cb8a5d4..f371f4491 100644 --- a/device/include/interop_database.h +++ b/device/include/interop_database.h @@ -90,10 +90,26 @@ static const interop_addr_entry_t interop_addr_database[] = { // 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; @@ -110,5 +126,25 @@ static const interop_name_entry_t interop_name_database[] = { // 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}, }; diff --git a/device/src/interop.c b/device/src/interop.c index 50020f7c7..81cbf91e4 100644 --- a/device/src/interop.c +++ b/device/src/interop.c @@ -62,6 +62,23 @@ bool interop_match_name(const interop_feature_t feature, const char *name) { 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; } } @@ -115,6 +132,8 @@ static const char* interop_feature_string_(const interop_feature_t feature) { 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"; diff --git a/stack/hid/hidh_conn.c b/stack/hid/hidh_conn.c index a58929ab5..96fc5bdca 100644 --- a/stack/hid/hidh_conn.c +++ b/stack/hid/hidh_conn.c @@ -45,6 +45,7 @@ #include "osi/include/osi.h" +#include "device/include/interop.h" extern fixed_queue_t *btu_general_alarm_queue; @@ -279,12 +280,22 @@ static void hidh_l2cif_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 p 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; @@ -451,10 +462,19 @@ static void hidh_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result) 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 {