OSDN Git Service

HID: Enhance blacklist logic for restricting SDP
authorHemant Gupta <hemantg@codeaurora.org>
Sun, 26 Apr 2015 05:02:57 +0000 (10:32 +0530)
committerLinux Build Service Account <lnxbuild@localhost>
Wed, 24 Aug 2016 14:09:45 +0000 (08:09 -0600)
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

btif/src/btif_dm.c
btif/src/btif_hh.c
device/include/interop.h
device/include/interop_database.h
device/src/interop.c
stack/hid/hidh_conn.c

index c3e129f..052f785 100644 (file)
@@ -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
index f461e48..a4057cc 100644 (file)
@@ -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;
index 05778a8..9021530 100644 (file)
@@ -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).
index 49cb8a5..f371f44 100644 (file)
@@ -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},
 };
 
index 50020f7..81cbf91 100644 (file)
@@ -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";
index a58929a..96fc5bd 100644 (file)
@@ -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
     {