diff options
author | 2024-11-20 09:10:45 +0000 | |
---|---|---|
committer | 2024-12-03 17:17:17 +0000 | |
commit | 762667bd766f21123ea8b9913764202cb8c33bc0 (patch) | |
tree | c3e256903937c7a7a8a6e968ad4bde58c83c5fe4 | |
parent | 40710b64cfaf517967290887d1dec71214207819 (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.cc | 94 | ||||
-rw-r--r-- | system/stack/include/gap_api.h | 37 | ||||
-rw-r--r-- | system/stack/include/l2cap_interface.h | 17 | ||||
-rw-r--r-- | system/stack/l2cap/internal/l2c_api.h | 17 | ||||
-rw-r--r-- | system/stack/l2cap/l2c_api.cc | 32 | ||||
-rw-r--r-- | system/stack/l2cap/l2c_api.h | 2 | ||||
-rw-r--r-- | system/stack/l2cap/l2cap_api.cc | 5 | ||||
-rw-r--r-- | system/test/mock/mock_stack_gap_conn.cc | 12 | ||||
-rw-r--r-- | system/test/mock/mock_stack_l2cap_api.cc | 5 | ||||
-rw-r--r-- | system/test/mock/mock_stack_l2cap_api.h | 10 | ||||
-rw-r--r-- | system/test/mock/mock_stack_l2cap_interface.h | 1 |
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)); |