From a3dd6f9607654a50195215deeb388919581752c7 Mon Sep 17 00:00:00 2001 From: Sharvil Nanavati Date: Sat, 17 Jan 2015 22:12:38 -0800 Subject: [PATCH] Add connection-specific function L2CA_SetConnectionCallbacks. This function allows a client to specify callback routines per- connection instead of per-PSM. --- stack/include/l2c_api.h | 7 +++++++ stack/l2cap/l2c_api.c | 43 +++++++++++++++++++++++++++++++++++++++++++ stack/l2cap/l2c_int.h | 3 +++ stack/l2cap/l2c_utils.c | 9 +++++++++ 4 files changed, 62 insertions(+) diff --git a/stack/include/l2c_api.h b/stack/include/l2c_api.h index 1aa90b302..010161428 100644 --- a/stack/include/l2c_api.h +++ b/stack/include/l2c_api.h @@ -419,6 +419,13 @@ extern BOOLEAN L2CA_ConnectRsp (BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid, extern UINT16 L2CA_ErtmConnectReq (UINT16 psm, BD_ADDR p_bd_addr, tL2CAP_ERTM_INFO *p_ertm_info); +// This function sets the callback routines for the L2CAP connection referred to by +// |local_cid|. The callback routines can only be modified for outgoing connections +// established by |L2CA_ConnectReq| or accepted incoming connections. |callbacks| +// must not be NULL. This function returns true if the callbacks could be updated, +// false if not (e.g. |local_cid| was not found). +bool L2CA_SetConnectionCallbacks(uint16_t local_cid, const tL2CAP_APPL_INFO *callbacks); + /******************************************************************************* ** ** Function L2CA_ErtmConnectRsp diff --git a/stack/l2cap/l2c_api.c b/stack/l2cap/l2c_api.c index 8ae4cc37a..041e1fb3b 100644 --- a/stack/l2cap/l2c_api.c +++ b/stack/l2cap/l2c_api.c @@ -22,6 +22,9 @@ * ******************************************************************************/ +#define LOG_TAG "bt_l2cap" + +#include #include #include #include @@ -35,6 +38,8 @@ #include "l2c_int.h" #include "btu.h" #include "btm_api.h" +#include "osi/include/allocator.h" +#include "osi/include/log.h" /******************************************************************************* ** @@ -328,6 +333,44 @@ UINT16 L2CA_ErtmConnectReq (UINT16 psm, BD_ADDR p_bd_addr, tL2CAP_ERTM_INFO *p_e return (p_ccb->local_cid); } +bool L2CA_SetConnectionCallbacks(uint16_t local_cid, const tL2CAP_APPL_INFO *callbacks) { + assert(callbacks != NULL); + assert(callbacks->pL2CA_ConnectInd_Cb == NULL); + assert(callbacks->pL2CA_ConnectCfm_Cb != NULL); + assert(callbacks->pL2CA_ConfigInd_Cb != NULL); + assert(callbacks->pL2CA_ConfigCfm_Cb != NULL); + assert(callbacks->pL2CA_DisconnectInd_Cb != NULL); + assert(callbacks->pL2CA_DisconnectCfm_Cb != NULL); + assert(callbacks->pL2CA_CongestionStatus_Cb != NULL); + assert(callbacks->pL2CA_DataInd_Cb != NULL); + assert(callbacks->pL2CA_TxComplete_Cb != NULL); + + tL2C_CCB *channel_control_block = l2cu_find_ccb_by_cid(NULL, local_cid); + if (!channel_control_block) { + LOG_ERROR("%s no channel control block found for L2CAP LCID=0x%04x.", __func__, local_cid); + return false; + } + + // We're making a connection-specific registration control block so we check if + // we already have a private one allocated to us on the heap. If not, we make a + // new allocation, mark it as heap-allocated, and inherit the fields from the old + // control block. + tL2C_RCB *registration_control_block = channel_control_block->p_rcb; + if (!channel_control_block->should_free_rcb) { + registration_control_block = (tL2C_RCB *)osi_calloc(sizeof(tL2C_RCB)); + if (!registration_control_block) { + LOG_ERROR("%s unable to allocate registration control block.", __func__); + return false; + } + + *registration_control_block = *channel_control_block->p_rcb; + channel_control_block->p_rcb = registration_control_block; + channel_control_block->should_free_rcb = true; + } + + registration_control_block->api = *callbacks; + return true; +} /******************************************************************************* ** diff --git a/stack/l2cap/l2c_int.h b/stack/l2cap/l2c_int.h index 8e3566741..9cf79a93d 100644 --- a/stack/l2cap/l2c_int.h +++ b/stack/l2cap/l2c_int.h @@ -24,6 +24,8 @@ #ifndef L2C_INT_H #define L2C_INT_H +#include + #include "btm_api.h" #include "gki.h" #include "l2c_api.h" @@ -261,6 +263,7 @@ typedef struct t_l2c_ccb TIMER_LIST_ENT timer_entry; /* CCB Timer List Entry */ tL2C_RCB *p_rcb; /* Registration CB for this Channel */ + bool should_free_rcb; /* True if RCB was allocated on the heap */ #define IB_CFG_DONE 0x01 #define OB_CFG_DONE 0x02 diff --git a/stack/l2cap/l2c_utils.c b/stack/l2cap/l2c_utils.c index a9a29ba80..d358418ff 100644 --- a/stack/l2cap/l2c_utils.c +++ b/stack/l2cap/l2c_utils.c @@ -39,6 +39,7 @@ #include "btm_int.h" #include "hcidefs.h" #include "bt_utils.h" +#include "osi/include/allocator.h" /******************************************************************************* ** @@ -1528,6 +1529,7 @@ tL2C_CCB *l2cu_allocate_ccb (tL2C_LCB *p_lcb, UINT16 cid) p_ccb->p_lcb = p_lcb; p_ccb->p_rcb = NULL; + p_ccb->should_free_rcb = false; /* Set priority then insert ccb into LCB queue (if we have an LCB) */ p_ccb->ccb_priority = L2CAP_CHNL_PRIORITY_LOW; @@ -1694,6 +1696,13 @@ void l2cu_release_ccb (tL2C_CCB *p_ccb) btm_sec_clr_service_by_psm(p_rcb->psm); } + if (p_ccb->should_free_rcb) + { + osi_free(p_rcb); + p_ccb->p_rcb = NULL; + p_ccb->should_free_rcb = false; + } + btm_sec_clr_temp_auth_service (p_lcb->remote_bd_addr); /* Stop the timer */ -- 2.11.0