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

Commit 8a66f448 authored by Himanshu Rawat's avatar Himanshu Rawat Committed by Android Build Coastguard Worker
Browse files

Skip ATT Read Blob request for name discovery before MTU exchange

Some LE devices cannot handle the ATT Read Blob request. They expect that ATT MTU should be large enough to avoid ATT Read Blob request. Their companion apps are expected to send their MTU preferences.
However, LE name discovery may happen earlier than MTU exchange is performed. In such case, ATT Read Blob request is used if the remote device is larger than 20 octets.

This change introduces an intermediary IOP fix for such devices by skipping ATT Read Blob request for LE name discovery if their companion app had request MTU exchange but it was not performed yet.

Test: mmm packages/modules/Bluetooth
Flag: EXEMPT IOP fix
Bug: 369329192
(cherry picked from https://android-review.googlesource.com/q/commit:cc53561d4ec107b0d1ed354ccdda8270c542b0ee)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:6fe01049bea49ba10ef7c581d6f49a32c9d6aa4f)
Merged-In: I59021fc5530bbaeffefa3c70f46218276a759bbf
Change-Id: I59021fc5530bbaeffefa3c70f46218276a759bbf
parent 19dd867e
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -1454,7 +1454,7 @@ bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, tBTM_BLE_CONN_TYP

bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type,
                  tBTM_BLE_CONN_TYPE connection_type, tBT_TRANSPORT transport, bool opportunistic,
                  uint8_t initiating_phys, uint16_t /* preferred_mtu */) {
                  uint8_t initiating_phys, uint16_t preferred_mtu) {
  /* Make sure app is registered */
  tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
  if (!p_reg) {
@@ -1541,6 +1541,15 @@ bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, tBLE_ADDR_TYPE ad
    }
  }

  if (ret) {
    // Save the current MTU preference for this app
    p_reg->mtu_prefs.erase(bd_addr);
    if (preferred_mtu > GATT_DEF_BLE_MTU_SIZE) {
      log::verbose("Saving MTU preference from app {} for {}", gatt_if, bd_addr);
      p_reg->mtu_prefs.insert({bd_addr, preferred_mtu});
    }
  }

  return ret;
}

+18 −0
Original line number Diff line number Diff line
@@ -913,7 +913,25 @@ void gatt_process_read_by_type_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, uint8_t o
    else if (p_clcb->operation == GATTC_OPTYPE_READ && p_clcb->op_subtype == GATT_READ_BY_TYPE) {
      p_clcb->counter = len - 2;
      p_clcb->s_handle = handle;

      if (p_clcb->counter == (payload_size - 4)) {
        /* IOP: Some devices can't handle Read Blob request. Apps for such devices send their MTU
         * preference with the connect request. Expectation is that the stack would exchange MTU
         * immediately on connection and thereby avoid using Read Blob request.
         * However, the stack does not support exchanging MTU immediately on connection at present.
         * As a workaround, GATT client instead just avoids sending Read Blob request when certain
         * conditions are met. */
        tGATT_TCB* p_tcb = p_clcb->p_tcb;
        if (p_tcb->transport == BT_TRANSPORT_LE && p_tcb->att_lcid == L2CAP_ATT_CID &&
            p_tcb->app_mtu_pref > GATT_DEF_BLE_MTU_SIZE &&
            p_tcb->payload_size <= GATT_DEF_BLE_MTU_SIZE && p_clcb->uuid.Is16Bit() &&
            p_clcb->uuid.As16Bit() == GATT_UUID_GAP_DEVICE_NAME) {
          log::warn("Skipping Read Blob request for reading device name {}", p_tcb->peer_bda);
          gatt_end_operation(p_clcb, GATT_SUCCESS, (void*)p);
          return;
        }

        /* Continue reading rest of value */
        p_clcb->op_subtype = GATT_READ_BY_HANDLE;
        if (!p_clcb->p_attr_buf) {
          p_clcb->p_attr_buf = (uint8_t*)osi_malloc(GATT_MAX_ATTR_LEN);
+6 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@

#include <deque>
#include <list>
#include <map>
#include <unordered_set>
#include <vector>

@@ -194,6 +195,7 @@ typedef struct {
  bool eatt_support{false};
  std::string name;
  std::set<RawAddress> direct_connect_request;
  std::map<RawAddress, uint16_t> mtu_prefs;
} tGATT_REG;

struct tGATT_CLCB;
@@ -340,7 +342,7 @@ typedef struct {
  std::list<tCONN_ID> conn_ids_waiting_for_mtu_exchange;
  /* Used to set proper TX DATA LEN on the controller*/
  uint16_t max_user_mtu;

  uint16_t app_mtu_pref;  // Holds consolidated MTU preference from apps at the time of connection
} tGATT_TCB;

/* logic channel */
@@ -634,6 +636,9 @@ tGATT_TCB* gatt_allocate_tcb_by_bdaddr(const RawAddress& bda, tBT_TRANSPORT tran
tGATT_TCB* gatt_get_tcb_by_idx(uint8_t tcb_idx);
tGATT_TCB* gatt_find_tcb_by_addr(const RawAddress& bda, tBT_TRANSPORT transport);
bool gatt_send_ble_burst_data(const RawAddress& remote_bda, BT_HDR* p_buf);
uint16_t gatt_get_mtu_pref(const tGATT_REG* p_reg, const RawAddress& bda);
uint16_t gatt_get_apps_preferred_mtu(const RawAddress& bda);
void gatt_remove_apps_mtu_prefs(const RawAddress& bda);

/* GATT client functions */
void gatt_dequeue_sr_cmd(tGATT_TCB& tcb, uint16_t cid);
+9 −0
Original line number Diff line number Diff line
@@ -595,6 +595,15 @@ static void gatt_le_connect_cback(uint16_t /* chan */, const RawAddress& bd_addr
    log::info("Start EATT before encryption");
    EattExtension::GetInstance()->Connect(bd_addr);
  }

  /* TODO: This preference should be used to exchange MTU with the peer device before the apps are
   * notified of the connection. */
  uint16_t app_mtu_pref = gatt_get_apps_preferred_mtu(bd_addr);
  gatt_remove_apps_mtu_prefs(bd_addr);
  p_tcb->app_mtu_pref = app_mtu_pref;
  if (app_mtu_pref > GATT_DEF_BLE_MTU_SIZE) {
    log::verbose("Combined app MTU prefs for {}: {}", bd_addr, app_mtu_pref);
  }
}

bool check_cached_model_name(const RawAddress& bd_addr) {
+49 −0
Original line number Diff line number Diff line
@@ -1990,3 +1990,52 @@ tCONN_ID gatt_create_conn_id(tTCB_IDX tcb_idx, tGATT_IF gatt_if) {
tTCB_IDX gatt_get_tcb_idx(tCONN_ID conn_id) { return (uint8_t)(conn_id >> 8); }

tGATT_IF gatt_get_gatt_if(tCONN_ID conn_id) { return (tGATT_IF)conn_id; }

uint16_t gatt_get_mtu_pref(const tGATT_REG* p_reg, const RawAddress& bda) {
  auto mtu_pref = p_reg->mtu_prefs.find(bda);
  if (mtu_pref != p_reg->mtu_prefs.cend()) {
    return mtu_pref->second;
  }
  return 0;
}

uint16_t gatt_get_apps_preferred_mtu(const RawAddress& bda) {
  uint16_t preferred_mtu = 0;
  if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) {
    for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) {
      if (!p_reg->in_use) {
        continue;
      }

      preferred_mtu = std::max(preferred_mtu, gatt_get_mtu_pref(p_reg.get(), bda));
    }
  } else {
    for (auto& reg : gatt_cb.cl_rcb) {
      if (!reg.in_use) {
        continue;
      }

      preferred_mtu = std::max(preferred_mtu, gatt_get_mtu_pref(&reg, bda));
    }
  }

  return preferred_mtu;
}

void gatt_remove_apps_mtu_prefs(const RawAddress& bda) {
  if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) {
    for (auto& [i, p_reg] : gatt_cb.cl_rcb_map) {
      if (!p_reg->in_use) {
        continue;
      }
      p_reg.get()->mtu_prefs.erase(bda);
    }
  } else {
    for (auto& reg : gatt_cb.cl_rcb) {
      if (!reg.in_use) {
        continue;
      }
      reg.mtu_prefs.erase(bda);
    }
  }
}
Loading