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

Commit e9a3bd3d authored by Himanshu Rawat's avatar Himanshu Rawat
Browse files

Allow multiple service discoveries in HID

BTA HID host maintains a common SDP database instance for all
connections. This means that only one connection attempt can be made a
time.
This change makes the SDP database instance a part of connection control
block and uses returned address to find the relevant connection control
block.

Test: mmm packages/modules/Bluetooth
Test: Manual | Change preferred HID transport on pairing with earbuds
supporting both DSA 1.0 and DSA 2.0
Flag: EXEMPT bugfix
Bug: 347241319

Change-Id: Ie9c1eebb6ced858ea7781e8536a4f3a83cd40724
parent bde1dad7
Loading
Loading
Loading
Loading
+57 −44
Original line number Diff line number Diff line
@@ -199,22 +199,30 @@ void bta_hh_disc_cmpl(void) {
 * Returns          void
 *
 ******************************************************************************/
static void bta_hh_sdp_cback(tSDP_STATUS result, uint16_t attr_mask, tHID_DEV_SDP_INFO* sdp_rec) {
  tBTA_HH_DEV_CB* p_cb = bta_hh_cb.p_cur;
  uint8_t hdl = 0;
static void bta_hh_sdp_cback(const RawAddress& bd_addr, tSDP_STATUS result, uint16_t attr_mask,
                             tHID_DEV_SDP_INFO* sdp_rec) {
  tBTA_HH_STATUS status = BTA_HH_ERR_SDP;
  tAclLinkSpec link_spec = {
          .addrt = {.type = BLE_ADDR_PUBLIC, .bda = bd_addr},
          .transport = BT_TRANSPORT_BR_EDR,
  };
  tBTA_HH_DEV_CB* p_cb = bta_hh_find_cb(link_spec);
  if (p_cb == nullptr) {
    log::error("Unknown device {}", bd_addr);
    return;
  }

  /* make sure sdp succeeded and hh has not been disabled */
  if ((result == SDP_SUCCESS) && (p_cb != NULL)) {
  if (result == SDP_SUCCESS) {
    /* security is required for the connection, add attr_mask bit*/
    attr_mask |= HID_SEC_REQUIRED;

    log::verbose("p_cb:{} result:0x{:02x}, attr_mask:0x{:02x}, handle:0x{:x}", fmt::ptr(p_cb),
                 result, attr_mask, p_cb->hid_handle);
    log::verbose("Device:{} result:0x{:02x}, attr_mask:0x{:02x}, handle:0x{:x}", bd_addr, result,
                 attr_mask, p_cb->hid_handle);

    /* check to see type of device is supported , and should not been added
     * before */
    if (bta_hh_tod_spt(p_cb, sdp_rec->sub_class)) {
      uint8_t hdl = 0;
      /* if not added before */
      if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) {
        /*  add device/update attr_mask information */
@@ -247,14 +255,12 @@ static void bta_hh_sdp_cback(tSDP_STATUS result, uint16_t attr_mask, tHID_DEV_SD
  }

  /* free disc_db when SDP is completed */
  osi_free_and_reset((void**)&bta_hh_cb.p_disc_db);
  osi_free_and_reset((void**)&p_cb->p_disc_db);

  /* send SDP_CMPL_EVT into state machine */
  tBTA_HH_DATA bta_hh_data;
  bta_hh_data.status = status;
  bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, &bta_hh_data);

  return;
}
/*******************************************************************************
 *
@@ -265,12 +271,19 @@ static void bta_hh_sdp_cback(tSDP_STATUS result, uint16_t attr_mask, tHID_DEV_SD
 * Returns          void
 *
 ******************************************************************************/
static void bta_hh_di_sdp_cback(const RawAddress& /* bd_addr */, tSDP_RESULT result) {
  tBTA_HH_DEV_CB* p_cb = bta_hh_cb.p_cur;
static void bta_hh_di_sdp_cback(const RawAddress& bd_addr, tSDP_RESULT result) {
  tBTA_HH_STATUS status = BTA_HH_ERR_SDP;
  tSDP_DI_GET_RECORD di_rec;
  tHID_STATUS ret;
  log::verbose("p_cb:{} result:0x{:02x}", fmt::ptr(p_cb), result);
  tAclLinkSpec link_spec = {
          .addrt = {.type = BLE_ADDR_PUBLIC, .bda = bd_addr},
          .transport = BT_TRANSPORT_BR_EDR,
  };
  tBTA_HH_DEV_CB* p_cb = bta_hh_find_cb(link_spec);
  if (p_cb == nullptr) {
    log::error("Unknown device {}", bd_addr);
    return;
  }

  log::verbose("device:{} result:0x{:02x}", bd_addr, result);

  /* if DI record does not exist on remote device, vendor_id in
   * tBTA_HH_DEV_DSCP_INFO will be set to 0xffff and we will allow the
@@ -278,11 +291,13 @@ static void bta_hh_di_sdp_cback(const RawAddress& /* bd_addr */, tSDP_RESULT res
   * HID devices do not set this. So for IOP purposes, we allow the connection
   * to go through and update the DI record to invalid DI entry.
   */
  if (((result == SDP_SUCCESS) || (result == SDP_NO_RECS_MATCH)) && (p_cb != NULL)) {
  if (result == SDP_SUCCESS || result == SDP_NO_RECS_MATCH) {
    if (result == SDP_SUCCESS &&
        get_legacy_stack_sdp_api()->device_id.SDP_GetNumDiRecords(bta_hh_cb.p_disc_db) != 0) {
        get_legacy_stack_sdp_api()->device_id.SDP_GetNumDiRecords(p_cb->p_disc_db) != 0) {
      tSDP_DI_GET_RECORD di_rec;

      /* always update information with primary DI record */
      if (get_legacy_stack_sdp_api()->device_id.SDP_GetDiRecord(1, &di_rec, bta_hh_cb.p_disc_db) ==
      if (get_legacy_stack_sdp_api()->device_id.SDP_GetDiRecord(1, &di_rec, p_cb->p_disc_db) ==
          SDP_SUCCESS) {
        bta_hh_update_di_info(p_cb, di_rec.rec.vendor, di_rec.rec.product, di_rec.rec.version, 0,
                              0);
@@ -292,23 +307,22 @@ static void bta_hh_di_sdp_cback(const RawAddress& /* bd_addr */, tSDP_RESULT res
      bta_hh_update_di_info(p_cb, BTA_HH_VENDOR_ID_INVALID, 0, 0, 0, 0);
    }

    ret = HID_HostGetSDPRecord(p_cb->link_spec.addrt.bda, bta_hh_cb.p_disc_db,
    tHID_STATUS ret = HID_HostGetSDPRecord(p_cb->link_spec.addrt.bda, p_cb->p_disc_db,
                                           p_bta_hh_cfg->sdp_db_size, bta_hh_sdp_cback);
    if (ret == HID_SUCCESS) {
      status = BTA_HH_OK;
    } else {
      log::verbose("failure Status 0x{:2x}", ret);
      log::warn("failure Status 0x{:2x}", ret);
    }
  }

  if (status != BTA_HH_OK) {
    osi_free_and_reset((void**)&bta_hh_cb.p_disc_db);
    osi_free_and_reset((void**)&p_cb->p_disc_db);
    /* send SDP_CMPL_EVT into state machine */
    tBTA_HH_DATA bta_hh_data;
    bta_hh_data.status = status;
    bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, &bta_hh_data);
  }
  return;
}

/*******************************************************************************
@@ -324,34 +338,34 @@ static void bta_hh_di_sdp_cback(const RawAddress& /* bd_addr */, tSDP_RESULT res
 *
 ******************************************************************************/
static void bta_hh_start_sdp(tBTA_HH_DEV_CB* p_cb) {
  if (!bta_hh_cb.p_disc_db) {
    bta_hh_cb.p_disc_db = (tSDP_DISCOVERY_DB*)osi_malloc(p_bta_hh_cfg->sdp_db_size);
  if (p_cb->p_disc_db != nullptr) {
    /* Incoming/outgoing collision case. DUT initiated HID connection at the
     * same time as the remote connected HID control channel.
     * When flow reaches here due to remote initiated connection, DUT may be
     * doing SDP. In such case, just do nothing and the ongoing SDP completion
     * or failure will handle this case.
     */
    log::warn("Ignoring as SDP already in progress");
    return;
  }

  p_cb->p_disc_db = (tSDP_DISCOVERY_DB*)osi_malloc(p_bta_hh_cfg->sdp_db_size);

  /* Do DI discovery first */
  if (get_legacy_stack_sdp_api()->device_id.SDP_DiDiscover(
                p_cb->link_spec.addrt.bda, bta_hh_cb.p_disc_db, p_bta_hh_cfg->sdp_db_size,
              p_cb->link_spec.addrt.bda, p_cb->p_disc_db, p_bta_hh_cfg->sdp_db_size,
              bta_hh_di_sdp_cback) == SDP_SUCCESS) {
      /* SDP search started successfully
       * Connection will be triggered at the end of successful SDP search
       */
    // SDP search started successfully. Connection will be triggered at the end of successful SDP
    // search
  } else {
    log::error("SDP_DiDiscover failed");

      osi_free_and_reset((void**)&bta_hh_cb.p_disc_db);
    osi_free_and_reset((void**)&p_cb->p_disc_db);

    tBTA_HH_DATA bta_hh_data;
    bta_hh_data.status = BTA_HH_ERR_SDP;
    bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, &bta_hh_data);
  }
  } else if (bta_hh_cb.p_disc_db) {
    /* Incoming/outgoing collision case. DUT initiated HID connection at the
     * same time as the remote connected HID control channel.
     * When flow reaches here due to remote initiated connection, DUT may be
     * doing SDP. In such case, just do nothing and the ongoing SDP completion
     * or failure will handle this case.
     */
    log::warn("Ignoring as SDP already in progress");
  }
}

/*******************************************************************************
@@ -485,7 +499,6 @@ static void bta_hh_bredr_conn(tBTA_HH_DEV_CB* p_cb) {
 ******************************************************************************/
void bta_hh_connect(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
  p_cb->mode = p_data->api_conn.mode;
  bta_hh_cb.p_cur = p_cb;

  // Initiate HID host connection
  if (p_cb->link_spec.transport == BT_TRANSPORT_LE) {
+2 −3
Original line number Diff line number Diff line
@@ -223,6 +223,8 @@ typedef struct {
#define BTA_HH_LE_SCPS_NOTIFY_ENB 0x02
  uint8_t scps_notify; /* scan refresh supported/notification enabled */
  bool security_pending;

  tSDP_DISCOVERY_DB* p_disc_db;
} tBTA_HH_DEV_CB;

/******************************************************************************
@@ -230,15 +232,12 @@ typedef struct {
 ******************************************************************************/
typedef struct {
  tBTA_HH_DEV_CB kdev[BTA_HH_MAX_DEVICE];   /* device control block */
  tBTA_HH_DEV_CB* p_cur;                    /* current device control
                                                   block idx, used in sdp */
  uint8_t cb_index[BTA_HH_MAX_KNOWN];       /* maintain a CB index
                                          map to dev handle */
  uint8_t le_cb_index[BTA_HH_LE_MAX_KNOWN]; /* maintain a CB index map to LE dev
                                             handle */
  tGATT_IF gatt_if;
  tBTA_HH_CBACK* p_cback; /* Application callbacks */
  tSDP_DISCOVERY_DB* p_disc_db;
  uint8_t cnt_num; /* connected device number */
  bool w4_disable; /* w4 disable flag */
} tBTA_HH_CB;
+16 −19
Original line number Diff line number Diff line
@@ -171,6 +171,18 @@ tBTA_HH_DEV_CB* bta_hh_find_cb_by_handle(uint8_t hid_handle) {
  return &bta_hh_cb.kdev[index];
}

static void bta_hh_reset_cb(tBTA_HH_DEV_CB* p_cb) {
  // Free buffer for report descriptor info
  osi_free_and_reset((void**)&p_cb->dscp_info.descriptor.dsc_list);

  // Cancel SDP if it had been started
  if (p_cb->p_disc_db != nullptr) {
    (void)get_legacy_stack_sdp_api()->service.SDP_CancelServiceSearch(p_cb->p_disc_db);
    osi_free_and_reset((void**)&p_cb->p_disc_db);
  }
  *p_cb = {};
}

/*******************************************************************************
 *
 * Function         bta_hh_clean_up_kdev
@@ -182,8 +194,6 @@ tBTA_HH_DEV_CB* bta_hh_find_cb_by_handle(uint8_t hid_handle) {
 *
 ******************************************************************************/
void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB* p_cb) {
  uint8_t index;

  if (p_cb->link_spec.transport == BT_TRANSPORT_LE) {
    uint8_t le_hid_handle = BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle);
    if (le_hid_handle >= BTA_HH_LE_MAX_KNOWN) {
@@ -199,14 +209,8 @@ void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB* p_cb) {
    }
  }

  /* reset device control block */
  index = p_cb->index; /* Preserve index for this control block */

  /* Free buffer for report descriptor info */
  osi_free_and_reset((void**)&p_cb->dscp_info.descriptor.dsc_list);

  memset(p_cb, 0, sizeof(tBTA_HH_DEV_CB)); /* Reset control block */

  uint8_t index = p_cb->index;  // Preserve index for this control block
  bta_hh_reset_cb(p_cb);        // Reset control block
  p_cb->index = index; /* Restore index for this control block */
  p_cb->state = BTA_HH_IDLE_ST;
  p_cb->hid_handle = BTA_HH_INVALID_HANDLE;
@@ -370,16 +374,9 @@ tBTA_HH_STATUS bta_hh_read_ssr_param(const tAclLinkSpec& link_spec, uint16_t* p_
 *
 ******************************************************************************/
void bta_hh_cleanup_disable(tBTA_HH_STATUS status) {
  uint8_t xx;
  /* free buffer in CB holding report descriptors */
  for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
    osi_free_and_reset((void**)&bta_hh_cb.kdev[xx].dscp_info.descriptor.dsc_list);
  }

  if (bta_hh_cb.p_disc_db) {
    /* Cancel SDP if it had been started. */
    (void)get_legacy_stack_sdp_api()->service.SDP_CancelServiceSearch(bta_hh_cb.p_disc_db);
    osi_free_and_reset((void**)&bta_hh_cb.p_disc_db);
  for (uint8_t i = 0; i < BTA_HH_MAX_DEVICE; i++) {
    bta_hh_reset_cb(&bta_hh_cb.kdev[i]);
  }

  if (bta_hh_cb.p_cback) {
+5 −5
Original line number Diff line number Diff line
@@ -110,7 +110,7 @@ void hidh_get_str_attr(tSDP_DISC_REC* p_rec, uint16_t attr_id, uint16_t max_len,
  }
}

static void hidh_search_callback(const RawAddress& /* bd_addr */, tSDP_RESULT sdp_result) {
static void hidh_search_callback(const RawAddress& bd_addr, tSDP_RESULT sdp_result) {
  tSDP_DISCOVERY_DB* p_db = hh_cb.p_sdp_db;
  tSDP_DISC_REC* p_rec;
  tSDP_DISC_ATTR *p_attr, *p_subattr1, *p_subattr2, *p_repdesc;
@@ -120,14 +120,14 @@ static void hidh_search_callback(const RawAddress& /* bd_addr */, tSDP_RESULT sd
  hh_cb.sdp_busy = false;

  if (sdp_result != SDP_SUCCESS) {
    hh_cb.sdp_cback(sdp_result, 0, NULL);
    hh_cb.sdp_cback(bd_addr, sdp_result, 0, NULL);
    return;
  }

  Uuid hid_uuid = Uuid::From16Bit(UUID_SERVCLASS_HUMAN_INTERFACE);
  p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceUUIDInDb(p_db, hid_uuid, NULL);
  if (p_rec == NULL) {
    hh_cb.sdp_cback(HID_SDP_NO_SERV_UUID, 0, NULL);
    hh_cb.sdp_cback(bd_addr, HID_SDP_NO_SERV_UUID, 0, NULL);
    return;
  }

@@ -142,7 +142,7 @@ static void hidh_search_callback(const RawAddress& /* bd_addr */, tSDP_RESULT sd
      ((p_subattr2 = p_subattr1->attr_value.v.p_sub_attr) == NULL) ||
      ((p_repdesc = p_subattr2->p_next_attr) == NULL) ||
      (SDP_DISC_ATTR_TYPE(p_repdesc->attr_len_type) != TEXT_STR_DESC_TYPE)) {
    hh_cb.sdp_cback(HID_SDP_MANDATORY_MISSING, 0, NULL);
    hh_cb.sdp_cback(bd_addr, HID_SDP_MANDATORY_MISSING, 0, NULL);
    return;
  }

@@ -255,7 +255,7 @@ static void hidh_search_callback(const RawAddress& /* bd_addr */, tSDP_RESULT sd
  }

  hh_cb.sdp_rec.p_sdp_layer_rec = p_rec;
  hh_cb.sdp_cback(SDP_SUCCESS, attr_mask, &hh_cb.sdp_rec);
  hh_cb.sdp_cback(bd_addr, SDP_SUCCESS, attr_mask, &hh_cb.sdp_rec);
}

/*******************************************************************************
+2 −2
Original line number Diff line number Diff line
@@ -47,8 +47,8 @@
 *  Type Definitions
 ****************************************************************************/

typedef void(tHID_HOST_SDP_CALLBACK)(tSDP_STATUS result, uint16_t attr_mask,
                                     tHID_DEV_SDP_INFO* sdp_rec);
typedef void(tHID_HOST_SDP_CALLBACK)(const RawAddress& bd_add, tSDP_STATUS result,
                                     uint16_t attr_mask, tHID_DEV_SDP_INFO* sdp_rec);

/* HID-HOST returns the events in the following table to the application via
 * tHID_HOST_DEV_CALLBACK