Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b7ef1fda authored by Srinu Jella's avatar Srinu Jella Committed by Pavlin Radoslavov
Browse files

Dynamic blacklist device for role switch

- Blacklist the device if it's rejected the role switch for
   max number of times. Same is added to the interop_database.

- Maximum number of failed (BTM_MAX_SW_ROLE_FAILED_ATTEMPTS)
  attempts set to 3 and it is configurable.

- Same blacklisted device is referred by the BTM module when
  any other module like profile is requesting for role switch
  and BTM module returns BTM_REPEATED_ATTEMPTS as the switch
  role status.

Test: Code compilation
Bug: 32999957
Change-Id: Ie999104a2c8ca507605ef3e1d454865cee98dcd2
parent 5e767d46
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -79,6 +79,12 @@ typedef enum {
  // Some A2DP Sink devices report SUCCESS to the AVDTP RECONFIGURE command,
  // but fail to play the reconfigured audio stream.
  INTEROP_DISABLE_AVDTP_RECONFIGURE,

  // Create dynamic blacklist to disable role switch.
  // Some car kits indicate that role switch is supported, but then reject
  // role switch attempts. After rejecting several role switch attempts,
  // such car kits will go into bad state.
  INTEROP_DYNAMIC_ROLE_SWITCH
} interop_feature_t;

// Check if a given |addr| matches a known interoperability workaround as
+1 −0
Original line number Diff line number Diff line
@@ -127,6 +127,7 @@ static const char* interop_feature_string_(const interop_feature_t feature) {
    CASE_RETURN_STR(INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S)
    CASE_RETURN_STR(INTEROP_GATTC_NO_SERVICE_CHANGED_IND)
    CASE_RETURN_STR(INTEROP_DISABLE_AVDTP_RECONFIGURE)
    CASE_RETURN_STR(INTEROP_DYNAMIC_ROLE_SWITCH)
  }

  return "UNKNOWN";
+58 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@
#include "btm_int.h"
#include "btu.h"
#include "device/include/controller.h"
#include "device/include/interop.h"
#include "hcidefs.h"
#include "hcimsgs.h"
#include "l2c_int.h"
@@ -224,6 +225,7 @@ void btm_acl_created(const RawAddress& bda, DEV_CLASS dc, BD_NAME bdn,
      p->conn_addr = *controller_get_interface()->get_address();

#endif
      p->switch_role_failed_attempts = 0;
      p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;

      btm_pm_sm_alloc(xx);
@@ -569,6 +571,12 @@ tBTM_STATUS BTM_SwitchRole(const RawAddress& remote_bd_addr, uint8_t new_role,
    return (BTM_BUSY);
  }

  if (interop_match_addr(INTEROP_DYNAMIC_ROLE_SWITCH, &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);

@@ -1351,6 +1359,56 @@ void btm_process_clk_off_comp_evt(uint16_t hci_handle, uint16_t clock_offset) {
  if (xx < MAX_L2CAP_LINKS) btm_cb.acl_db[xx].clock_offset = clock_offset;
}

/*******************************************************************************
*
* 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(const RawAddress& 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, &bd_addr))) {
    p->switch_role_failed_attempts++;
    if (p->switch_role_failed_attempts == BTM_MAX_SW_ROLE_FAILED_ATTEMPTS) {
      BTM_TRACE_WARNING(
          "%s: Device %s blacklisted for role switching - "
          "multiple role switch failed attempts: %u",
          __func__, to_string(bd_addr).c_str(), p->switch_role_failed_attempts);
      interop_database_add(INTEROP_DYNAMIC_ROLE_SWITCH, &bd_addr, 3);
    }
  }
}

/*******************************************************************************
 *
 * Function         btm_acl_role_changed
+2 −0
Original line number Diff line number Diff line
@@ -103,6 +103,8 @@ extern void btm_process_clk_off_comp_evt(uint16_t hci_handle,
                                         uint16_t clock_offset);
extern void btm_acl_role_changed(uint8_t hci_status, const RawAddress* bd_addr,
                                 uint8_t new_role);
extern void btm_blacklist_role_change_device(const RawAddress& bd_addr,
                                             uint8_t hci_status);
extern void btm_acl_encrypt_change(uint16_t handle, uint8_t status,
                                   uint8_t encr_enable);
extern uint16_t btm_get_acl_disc_reason_code(void);
+3 −0
Original line number Diff line number Diff line
@@ -89,6 +89,9 @@ typedef struct {
#define BTM_ACL_SWKEY_STATE_IN_PROGRESS 5
  uint8_t switch_role_state;

#define BTM_MAX_SW_ROLE_FAILED_ATTEMPTS 3
  uint8_t switch_role_failed_attempts;

#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 \
Loading