summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jayden Kim <jaydenk@google.com> 2024-11-20 09:10:45 +0000
committer Jayden Kim <jaydenk@google.com> 2024-12-03 17:17:17 +0000
commit762667bd766f21123ea8b9913764202cb8c33bc0 (patch)
treec3e256903937c7a7a8a6e968ad4bde58c83c5fe4
parent40710b64cfaf517967290887d1dec71214207819 (diff)
Add helper functions to get LE L2CAP channel and ACL handle information
Bug: 342012881 Bug: 367419086 Test: m -j Change-Id: I5babc03bac5f7c7c3d6c5565dce044e96ac0154c
-rw-r--r--system/stack/gap/gap_conn.cc94
-rw-r--r--system/stack/include/gap_api.h37
-rw-r--r--system/stack/include/l2cap_interface.h17
-rw-r--r--system/stack/l2cap/internal/l2c_api.h17
-rw-r--r--system/stack/l2cap/l2c_api.cc32
-rw-r--r--system/stack/l2cap/l2c_api.h2
-rw-r--r--system/stack/l2cap/l2cap_api.cc5
-rw-r--r--system/test/mock/mock_stack_gap_conn.cc12
-rw-r--r--system/test/mock/mock_stack_l2cap_api.cc5
-rw-r--r--system/test/mock/mock_stack_l2cap_api.h10
-rw-r--r--system/test/mock/mock_stack_l2cap_interface.h1
11 files changed, 217 insertions, 15 deletions
diff --git a/system/stack/gap/gap_conn.cc b/system/stack/gap/gap_conn.cc
index fd988c8fd3..127ded1cff 100644
--- a/system/stack/gap/gap_conn.cc
+++ b/system/stack/gap/gap_conn.cc
@@ -55,7 +55,9 @@ typedef struct {
uint8_t service_id; /* Used by BTM */
uint16_t gap_handle; /* GAP handle */
- uint16_t connection_id; /* L2CAP CID */
+ uint16_t local_cid; /* Local L2CAP CID */
+ uint16_t remote_cid; /* Remote L2CAP CID */
+ uint16_t acl_handle; /* ACL handle */
bool rem_addr_specified;
uint8_t chan_mode_mask; /* Supported channel modes (FCR) */
RawAddress rem_dev_address;
@@ -284,7 +286,7 @@ uint16_t GAP_ConnOpen(const char* /* p_serv_name */, uint8_t service_id, bool is
cid = stack::l2cap::get_interface().L2CA_ConnectReqWithSecurity(p_ccb->psm, *p_rem_bda,
security);
if (cid != 0) {
- p_ccb->connection_id = cid;
+ p_ccb->local_cid = cid;
return p_ccb->gap_handle;
}
log::warn("Unable to initiate connection peer:{} psm:{} transport:{}", *p_rem_bda, p_ccb->psm,
@@ -295,7 +297,7 @@ uint16_t GAP_ConnOpen(const char* /* p_serv_name */, uint8_t service_id, bool is
cid = stack::l2cap::get_interface().L2CA_ConnectLECocReq(p_ccb->psm, *p_rem_bda,
&p_ccb->local_coc_cfg, security);
if (cid != 0) {
- p_ccb->connection_id = cid;
+ p_ccb->local_cid = cid;
return p_ccb->gap_handle;
}
log::warn("Unable to initiate connection peer:{} psm:{} transport:{}", *p_rem_bda, p_ccb->psm,
@@ -329,14 +331,14 @@ uint16_t GAP_ConnClose(uint16_t gap_handle) {
/* Check if we have a connection ID */
if (p_ccb->con_state != GAP_CCB_STATE_LISTENING) {
if (p_ccb->transport == BT_TRANSPORT_LE) {
- if (!stack::l2cap::get_interface().L2CA_DisconnectLECocReq(p_ccb->connection_id)) {
+ if (!stack::l2cap::get_interface().L2CA_DisconnectLECocReq(p_ccb->local_cid)) {
log::warn("Unable to request L2CAP disconnect le_coc peer:{} cid:{}",
- p_ccb->rem_dev_address, p_ccb->connection_id);
+ p_ccb->rem_dev_address, p_ccb->local_cid);
}
} else {
- if (!stack::l2cap::get_interface().L2CA_DisconnectReq(p_ccb->connection_id)) {
+ if (!stack::l2cap::get_interface().L2CA_DisconnectReq(p_ccb->local_cid)) {
log::warn("Unable to request L2CAP disconnect peer:{} cid:{}", p_ccb->rem_dev_address,
- p_ccb->connection_id);
+ p_ccb->local_cid);
}
}
}
@@ -451,9 +453,9 @@ static bool gap_try_write_queued_data(tGAP_CCB* p_ccb) {
while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->tx_queue)) != NULL) {
tL2CAP_DW_RESULT status;
if (p_ccb->transport == BT_TRANSPORT_LE) {
- status = stack::l2cap::get_interface().L2CA_LECocDataWrite(p_ccb->connection_id, p_buf);
+ status = stack::l2cap::get_interface().L2CA_LECocDataWrite(p_ccb->local_cid, p_buf);
} else {
- status = stack::l2cap::get_interface().L2CA_DataWrite(p_ccb->connection_id, p_buf);
+ status = stack::l2cap::get_interface().L2CA_DataWrite(p_ccb->local_cid, p_buf);
}
if (status == tL2CAP_DW_RESULT::CONGESTED) {
@@ -576,7 +578,67 @@ uint16_t GAP_ConnGetL2CAPCid(uint16_t gap_handle) {
return 0;
}
- return p_ccb->connection_id;
+ return p_ccb->local_cid;
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_GetLeChannelInfo
+ *
+ * Description This function is called to get LE L2CAP channel information
+ * by the gap handle. All OUT parameters must NOT be nullptr.
+ *
+ * Parameters: handle - Handle of the port returned in the Open
+ * remote_mtu - OUT remote L2CAP MTU
+ * local_mps - OUT local L2CAP COC MPS
+ * remote_mps - OUT remote L2CAP COC MPS
+ * local_credit - OUT local L2CAP COC credit
+ * remote_credit - OUT remote L2CAP COC credit
+ * local_cid - OUT local L2CAP CID
+ * remote_cid - OUT remote L2CAP CID
+ * acl_handle - OUT ACL handle
+ *
+ * Returns true if request accepted
+ *
+ ******************************************************************************/
+bool GAP_GetLeChannelInfo(uint16_t gap_handle, uint16_t* remote_mtu, uint16_t* local_mps,
+ uint16_t* remote_mps, uint16_t* local_credit, uint16_t* remote_credit,
+ uint16_t* local_cid, uint16_t* remote_cid, uint16_t* acl_handle) {
+ tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
+ if (p_ccb == NULL || p_ccb->transport != BT_TRANSPORT_LE ||
+ p_ccb->con_state != GAP_CCB_STATE_CONNECTED) {
+ return false;
+ }
+
+ *remote_mtu = p_ccb->peer_coc_cfg.mtu;
+ *local_mps = p_ccb->local_coc_cfg.mps;
+ *remote_mps = p_ccb->peer_coc_cfg.mps;
+ *local_credit = p_ccb->local_coc_cfg.credits;
+ *remote_credit = p_ccb->peer_coc_cfg.credits;
+ *local_cid = p_ccb->local_cid;
+ *remote_cid = p_ccb->remote_cid;
+ *acl_handle = p_ccb->acl_handle;
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_IsTransportLe
+ *
+ * Description This function returns if the transport is LE by the gap handle.
+ *
+ * Parameters: handle - Handle of the port returned in the Open
+ *
+ * Returns true if transport is LE, else false
+ *
+ ******************************************************************************/
+bool GAP_IsTransportLe(uint16_t gap_handle) {
+ tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
+ if (p_ccb == NULL || p_ccb->transport != BT_TRANSPORT_LE ||
+ p_ccb->con_state != GAP_CCB_STATE_CONNECTED) {
+ return false;
+ }
+ return true;
}
/*******************************************************************************
@@ -649,7 +711,7 @@ static void gap_connect_ind(const RawAddress& bd_addr, uint16_t l2cap_cid, uint1
/* Save the BD Address and Channel ID. */
p_ccb->rem_dev_address = bd_addr;
- p_ccb->connection_id = l2cap_cid;
+ p_ccb->local_cid = l2cap_cid;
if (p_ccb->transport == BT_TRANSPORT_LE) {
/* get the remote coc configuration */
@@ -683,12 +745,14 @@ static void gap_checks_con_flags(tGAP_CCB* p_ccb) {
tGAP_CB_DATA cb_data;
uint16_t l2cap_remote_cid;
if (com::android::bluetooth::flags::bt_socket_api_l2cap_cid() &&
- stack::l2cap::get_interface().L2CA_GetRemoteChannelId(p_ccb->connection_id,
+ stack::l2cap::get_interface().L2CA_GetRemoteChannelId(p_ccb->local_cid,
&l2cap_remote_cid)) {
- cb_data.l2cap_cids.local_cid = p_ccb->connection_id;
+ cb_data.l2cap_cids.local_cid = p_ccb->local_cid;
cb_data.l2cap_cids.remote_cid = l2cap_remote_cid;
cb_data_ptr = &cb_data;
}
+ stack::l2cap::get_interface().L2CA_GetRemoteChannelId(p_ccb->local_cid, &p_ccb->remote_cid);
+ stack::l2cap::get_interface().L2CA_GetAclHandle(p_ccb->local_cid, &p_ccb->acl_handle);
p_ccb->con_state = GAP_CCB_STATE_CONNECTED;
p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_OPENED, cb_data_ptr);
@@ -926,7 +990,7 @@ static void gap_congestion_ind(uint16_t lcid, bool is_congested) {
* Function gap_find_ccb_by_cid
*
* Description This function searches the CCB table for an entry with the
- * passed CID.
+ * passed local CID.
*
* Returns the CCB address, or NULL if not found.
*
@@ -937,7 +1001,7 @@ static tGAP_CCB* gap_find_ccb_by_cid(uint16_t cid) {
/* Look through each connection control block */
for (xx = 0, p_ccb = conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++) {
- if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) && (p_ccb->connection_id == cid)) {
+ if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) && (p_ccb->local_cid == cid)) {
return p_ccb;
}
}
diff --git a/system/stack/include/gap_api.h b/system/stack/include/gap_api.h
index e4a185eefe..f216b12f3b 100644
--- a/system/stack/include/gap_api.h
+++ b/system/stack/include/gap_api.h
@@ -226,6 +226,43 @@ uint16_t GAP_ConnGetL2CAPCid(uint16_t gap_handle);
/*******************************************************************************
*
+ * Function GAP_GetLeChannelInfo
+ *
+ * Description This function is called to get LE L2CAP channel information
+ * by the gap handle. All OUT parameters must NOT be nullptr.
+ *
+ * Parameters: handle - Handle of the port returned in the Open
+ * remote_mtu - OUT remote L2CAP MTU
+ * local_mps - OUT local L2CAP COC MPS
+ * remote_mps - OUT remote L2CAP COC MPS
+ * local_credit - OUT local L2CAP COC credit
+ * remote_credit - OUT remote L2CAP COC credit
+ * local_cid - OUT local L2CAP CID
+ * remote_cid - OUT remote L2CAP CID
+ * acl_handle - OUT ACL handle
+ *
+ * Returns true if request accepted
+ *
+ ******************************************************************************/
+bool GAP_GetLeChannelInfo(uint16_t gap_handle, uint16_t* remote_mtu, uint16_t* local_mps,
+ uint16_t* remote_mps, uint16_t* local_credit, uint16_t* remote_credit,
+ uint16_t* local_cid, uint16_t* remote_cid, uint16_t* acl_handle);
+
+/*******************************************************************************
+ *
+ * Function GAP_IsTransportLe
+ *
+ * Description This function returns if the transport is LE by the gap handle.
+ *
+ * Parameters: handle - Handle of the port returned in the Open
+ *
+ * Returns true if transport is LE, else false
+ *
+ ******************************************************************************/
+bool GAP_IsTransportLe(uint16_t gap_handle);
+
+/*******************************************************************************
+ *
* Function GAP_Init
*
* Description Initializes the control blocks used by GAP.
diff --git a/system/stack/include/l2cap_interface.h b/system/stack/include/l2cap_interface.h
index cfd88153f7..c3e32dcf36 100644
--- a/system/stack/include/l2cap_interface.h
+++ b/system/stack/include/l2cap_interface.h
@@ -916,6 +916,23 @@ public:
**
*******************************************************************************/
virtual bool L2CA_isMediaChannel(uint16_t handle, uint16_t channel_id, bool is_local_cid) = 0;
+
+ /*******************************************************************************
+ **
+ ** Function L2CA_GetAclHandle
+ **
+ ** Description Given a local channel identifier, |lcid|, this function
+ ** returns the handle of the corresponding ACL connection, |acl_handle|. If
+ ** |lcid| is not known or is invalid, this function returns false and does not
+ ** modify the value pointed at by |acl_handle|.
+ **
+ ** Parameters: lcid: Local CID
+ ** acl_handle: Pointer to ACL handle must NOT be nullptr
+ **
+ ** Returns true if acl_handle lookup was successful
+ **
+ ******************************************************************************/
+ virtual bool L2CA_GetAclHandle(uint16_t lcid, uint16_t* acl_handle) = 0;
};
Interface& get_interface();
diff --git a/system/stack/l2cap/internal/l2c_api.h b/system/stack/l2cap/internal/l2c_api.h
index 5ed3403cff..99c1f57781 100644
--- a/system/stack/l2cap/internal/l2c_api.h
+++ b/system/stack/l2cap/internal/l2c_api.h
@@ -777,3 +777,20 @@ void L2CA_SetMediaStreamChannel(uint16_t local_media_cid, bool status);
**
*******************************************************************************/
[[nodiscard]] bool L2CA_isMediaChannel(uint16_t handle, uint16_t channel_id, bool is_local_cid);
+
+/*******************************************************************************
+**
+** Function L2CA_GetAclHandle
+**
+** Description Given a local channel identifier, |lcid|, this function
+** returns the handle of the corresponding ACL connection, |acl_handle|. If
+** |lcid| is not known or is invalid, this function returns false and does not
+** modify the value pointed at by |acl_handle|.
+**
+** Parameters: lcid: Local CID
+** acl_handle: Pointer to ACL handle must NOT be nullptr
+**
+** Returns true if acl_handle lookup was successful
+**
+******************************************************************************/
+[[nodiscard]] bool L2CA_GetAclHandle(uint16_t lcid, uint16_t* acl_handle);
diff --git a/system/stack/l2cap/l2c_api.cc b/system/stack/l2cap/l2c_api.cc
index 2b67132edb..68aacece21 100644
--- a/system/stack/l2cap/l2c_api.cc
+++ b/system/stack/l2cap/l2c_api.cc
@@ -1731,6 +1731,38 @@ bool L2CA_isMediaChannel(uint16_t handle, uint16_t channel_id, bool is_local_cid
return ret;
}
+/*******************************************************************************
+ *
+ * Function L2CA_GetAclHandle
+ *
+ * Description Given a local channel identifier, |lcid|, this function
+ * returns the bound ACL handle, |acl_handle|. If |acl_handle|
+ * is not known or is invalid, this function returns false and
+ * does not modify the value pointed at by |acl_handle|.
+ *
+ * Parameters: lcid: Local CID
+ * rcid: Pointer to ACL handle must NOT be nullptr
+ *
+ * Return value: true if acl_handle lookup was successful
+ *
+ ******************************************************************************/
+bool L2CA_GetAclHandle(uint16_t lcid, uint16_t* acl_handle) {
+ log::assert_that(acl_handle != nullptr, "assert failed: acl_handle != nullptr");
+
+ tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(nullptr, lcid);
+ if (p_ccb == nullptr) {
+ log::error("No CCB for CID:0x{:04x}", lcid);
+ return false;
+ }
+ uint16_t handle = p_ccb->p_lcb->Handle();
+ if (handle == HCI_INVALID_HANDLE) {
+ log::error("Invalid ACL handle");
+ return false;
+ }
+ *acl_handle = handle;
+ return true;
+}
+
using namespace bluetooth;
#define DUMPSYS_TAG "shim::legacy::l2cap"
diff --git a/system/stack/l2cap/l2c_api.h b/system/stack/l2cap/l2c_api.h
index f645803dad..f89a5cc6ca 100644
--- a/system/stack/l2cap/l2c_api.h
+++ b/system/stack/l2cap/l2c_api.h
@@ -133,6 +133,8 @@ public:
void L2CA_SetMediaStreamChannel(uint16_t local_media_cid, bool status) override;
[[nodiscard]] bool L2CA_isMediaChannel(uint16_t handle, uint16_t channel_id,
bool is_local_cid) override;
+
+ [[nodiscard]] bool L2CA_GetAclHandle(uint16_t lcid, uint16_t* acl_handle) override;
};
} // namespace l2cap
diff --git a/system/stack/l2cap/l2cap_api.cc b/system/stack/l2cap/l2cap_api.cc
index 94466c90e2..2e1b12c7de 100644
--- a/system/stack/l2cap/l2cap_api.cc
+++ b/system/stack/l2cap/l2cap_api.cc
@@ -257,3 +257,8 @@ void bluetooth::stack::l2cap::Impl::L2CA_SetMediaStreamChannel(uint16_t local_me
uint16_t* rcid) {
return ::L2CA_GetRemoteChannelId(lcid, rcid);
}
+
+[[nodiscard]] bool bluetooth::stack::l2cap::Impl::L2CA_GetAclHandle(uint16_t lcid,
+ uint16_t* acl_handle) {
+ return ::L2CA_GetAclHandle(lcid, acl_handle);
+}
diff --git a/system/test/mock/mock_stack_gap_conn.cc b/system/test/mock/mock_stack_gap_conn.cc
index 19034a9fec..07193c9130 100644
--- a/system/test/mock/mock_stack_gap_conn.cc
+++ b/system/test/mock/mock_stack_gap_conn.cc
@@ -61,4 +61,16 @@ uint16_t GAP_ConnWriteData(uint16_t /* gap_handle */, BT_HDR* /* msg */) {
inc_func_call_count(__func__);
return 0;
}
+bool GAP_GetLeChannelInfo(uint16_t /* gap_handle */, uint16_t* /*remote_mtu */,
+ uint16_t* /* local_mps */, uint16_t* /* remote_mps */,
+ uint16_t* /* local_credit */, uint16_t* /* remote_credit */,
+ uint16_t* /* local_cid */, uint16_t* /* remote_cid */,
+ uint16_t* /* acl_handle */) {
+ inc_func_call_count(__func__);
+ return false;
+}
+bool GAP_IsTransportLe(uint16_t /* gap_handle */) {
+ inc_func_call_count(__func__);
+ return false;
+}
void GAP_Init(void) { inc_func_call_count(__func__); }
diff --git a/system/test/mock/mock_stack_l2cap_api.cc b/system/test/mock/mock_stack_l2cap_api.cc
index b8f3f4e227..3dd0ef991c 100644
--- a/system/test/mock/mock_stack_l2cap_api.cc
+++ b/system/test/mock/mock_stack_l2cap_api.cc
@@ -75,6 +75,7 @@ struct L2CA_SetMediaStreamChannel L2CA_SetMediaStreamChannel;
struct L2CA_isMediaChannel L2CA_isMediaChannel;
struct L2CA_LeCreditDefault L2CA_LeCreditDefault;
struct L2CA_LeCreditThreshold L2CA_LeCreditThreshold;
+struct L2CA_GetAclHandle L2CA_GetAclHandle;
} // namespace stack_l2cap_api
} // namespace mock
@@ -250,6 +251,10 @@ uint16_t L2CA_LeCreditThreshold() {
inc_func_call_count(__func__);
return test::mock::stack_l2cap_api::L2CA_LeCreditThreshold();
}
+bool L2CA_GetAclHandle(uint16_t lcid, uint16_t* acl_handle) {
+ inc_func_call_count(__func__);
+ return test::mock::stack_l2cap_api::L2CA_GetAclHandle(lcid, acl_handle);
+}
// END mockcify generation
diff --git a/system/test/mock/mock_stack_l2cap_api.h b/system/test/mock/mock_stack_l2cap_api.h
index 40d746ecd3..ed20c3438d 100644
--- a/system/test/mock/mock_stack_l2cap_api.h
+++ b/system/test/mock/mock_stack_l2cap_api.h
@@ -457,6 +457,16 @@ struct L2CA_LeCreditThreshold {
};
extern struct L2CA_LeCreditThreshold L2CA_LeCreditThreshold;
+// Name: L2CA_GetAclHandle
+// Params: uint16_t lcid, uint16_t* acl_handle
+// Returns: bool
+struct L2CA_GetAclHandle {
+ std::function<bool(uint16_t lcid, uint16_t* acl_handle)> body{
+ [](uint16_t /* lcid */, uint16_t* /* acl_handle */) { return false; }};
+ bool operator()(uint16_t lcid, uint16_t* acl_handle) { return body(lcid, acl_handle); }
+};
+extern struct L2CA_GetAclHandle L2CA_GetAclHandle;
+
} // namespace stack_l2cap_api
} // namespace mock
} // namespace test
diff --git a/system/test/mock/mock_stack_l2cap_interface.h b/system/test/mock/mock_stack_l2cap_interface.h
index c87bf164bb..7756f4a4ed 100644
--- a/system/test/mock/mock_stack_l2cap_interface.h
+++ b/system/test/mock/mock_stack_l2cap_interface.h
@@ -106,6 +106,7 @@ public:
MOCK_METHOD(uint16_t, L2CA_LeCreditThreshold, ());
MOCK_METHOD(void, L2CA_Consolidate, (const RawAddress& identity_addr, const RawAddress& rpa));
+ MOCK_METHOD(bool, L2CA_GetAclHandle, (uint16_t lcid, uint16_t* acl_handle));
// Disconnect methods an active connection for both BR/EDR and BLE
MOCK_METHOD(bool, L2CA_DisconnectReq, (uint16_t cid));