******************************************************************************/
#include <hardware/bluetooth.h>
#include <arpa/inet.h>
+#include <pthread.h>
#include "bt_types.h"
#include "gki.h"
-#include "bd.h"
#include "utl.h"
#include "bta_sys.h"
#include "bta_api.h"
#include "avct_api.h"
#include "avdt_api.h"
#include "gap_api.h"
+#include "l2c_api.h"
+
+
+/* one of these exists for each client */
+struct fc_client {
+ struct fc_client *next_all_list;
+ struct fc_client *next_chan_list;
+ BD_ADDR remote_addr;
+ uint32_t id;
+ tBTA_JV_L2CAP_CBACK *p_cback;
+ void *user_data;
+ uint16_t handle;
+ uint16_t chan;
+ uint8_t sec_id;
+ unsigned server : 1;
+ unsigned init_called : 1;
+};
+
+/* one of these exists for each channel we're dealing with */
+struct fc_channel {
+ struct fc_channel *next;
+ struct fc_client *clients;
+ uint8_t has_server : 1;
+ uint16_t chan;
+};
+
+
+static struct fc_client *fc_clients;
+static struct fc_channel *fc_channels;
+static uint32_t fc_next_id;
+static pthread_once_t fc_init_once = PTHREAD_ONCE_INIT;
+
+
+static void fc_init_work(void)
+{
+ fc_clients = NULL;
+ fc_channels = NULL;
+ fc_next_id = 0;
+
+ //more init here if needed...
+}
+
+static void fc_init(void)
+{
+ pthread_once(&fc_init_once, fc_init_work);
+}
-#define HDL2CB(handle) \
- UINT32 __hi = ((handle) & BTA_JV_RFC_HDL_MASK) - 1; \
- UINT32 __si = BTA_JV_RFC_HDL_TO_SIDX(handle); \
- tBTA_JV_RFC_CB *p_cb = &bta_jv_cb.rfc_cb[__hi]; \
- tBTA_JV_PCB *p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[__si] - 1]
+static void fcchan_conn_chng_cbk(UINT16 chan, BD_ADDR bd_addr, BOOLEAN connected,
+ UINT16 reason, tBT_TRANSPORT );
+static void fcchan_data_cbk(UINT16 chan, BD_ADDR bd_addr, BT_HDR *p_buf);
-extern void uuid_to_string(bt_uuid_t *p_uuid, char *str);
+
+extern void uuid_to_string_legacy(bt_uuid_t *p_uuid, char *str);
static inline void logu(const char* title, const uint8_t * p_uuid)
{
char uuids[128];
- uuid_to_string((bt_uuid_t*)p_uuid, uuids);
+ uuid_to_string_legacy((bt_uuid_t*)p_uuid, uuids);
APPL_TRACE_DEBUG("%s: %s", title, uuids);
}
/*******************************************************************************
**
-** Function bta_jv_get_local_device_addr_cback
-**
-** Description Callback from btm after local bdaddr is read
-**
-** Returns void
-**
-*******************************************************************************/
-static void bta_jv_get_local_device_addr_cback(BD_ADDR bd_addr)
-{
- if(bta_jv_cb.p_dm_cback)
- bta_jv_cb.p_dm_cback(BTA_JV_LOCAL_ADDR_EVT, (tBTA_JV *)bd_addr, 0);
-}
-
-/*******************************************************************************
-**
-** Function bta_jv_get_remote_device_name_cback
-**
-** Description Callback from btm after remote name is read
-**
-** Returns void
-**
-*******************************************************************************/
-static void bta_jv_get_remote_device_name_cback(tBTM_REMOTE_DEV_NAME *p_name)
-{
- tBTA_JV evt_data;
- evt_data.p_name = p_name->remote_bd_name;
- if(bta_jv_cb.p_dm_cback)
- bta_jv_cb.p_dm_cback(BTA_JV_REMOTE_NAME_EVT, &evt_data, 0);
-}
-
-/*******************************************************************************
-**
** Function bta_jv_alloc_sec_id
**
** Description allocate a security id
*******************************************************************************/
tBTA_JV_STATUS bta_jv_free_l2c_cb(tBTA_JV_L2C_CB *p_cb)
{
- UNUSED(p_cb);
-#if 0
tBTA_JV_STATUS status = BTA_JV_SUCCESS;
if(BTA_JV_ST_NONE != p_cb->state)
{
-#if SDP_FOR_JV_INCLUDED == TRUE
- if(BTA_JV_L2C_FOR_SDP_HDL == p_cb->handle)
- {
- bta_jv_cb.sdp_data_size = 0;
- if(SDP_ConnClose(bta_jv_cb.sdp_for_jv))
- {
- bta_jv_cb.sdp_for_jv = 0;
- }
- else
+ bta_jv_free_set_pm_profile_cb((UINT32)p_cb->handle);
+ if (GAP_ConnClose(p_cb->handle) != BT_PASS)
status = BTA_JV_FAILURE;
- }
- else
-#endif
- {
- bta_jv_free_set_pm_profile_cb((UINT32)p_cb->handle);
- if (GAP_ConnClose(p_cb->handle) != BT_PASS)
- status = BTA_JV_FAILURE;
- }
}
p_cb->psm = 0;
p_cb->state = BTA_JV_ST_NONE;
bta_jv_free_sec_id(&p_cb->sec_id);
p_cb->p_cback = NULL;
return status;
-#endif
- return 0;
}
/*******************************************************************************
- **
- ** Function bta_jv_clear_pm_cb
- **
- ** Description clears jv pm control block and optionally calls bta_sys_conn_close()
- ** In general close_conn should be set to TRUE to remove registering with
- ** dm pm!
- **
- ** WARNING: Make sure to clear pointer form port or l2c to this control block too!
- **
- *******************************************************************************/
+**
+**
+** Function bta_jv_clear_pm_cb
+**
+** Description clears jv pm control block and optionally calls bta_sys_conn_close()
+** In general close_conn should be set to TRUE to remove registering with
+** dm pm!
+**
+** WARNING: Make sure to clear pointer form port or l2c to this control block too!
+**
+*******************************************************************************/
static void bta_jv_clear_pm_cb(tBTA_JV_PM_CB *p_pm_cb, BOOLEAN close_conn)
{
/* needs to be called if registered with bta pm, otherwise we may run out of dm pm slots! */
appid_counter++;
}
- APPL_TRACE_API("bta_jv_free_set_pm_profile_cb(jv_handle: 0x%2x), idx: %d, "
- "app_id: 0x%x", jv_handle, i, bta_jv_cb.pm_cb[i].app_id);
- APPL_TRACE_API("bta_jv_free_set_pm_profile_cb, bd_counter = %d, "
- "appid_counter = %d", bd_counter, appid_counter);
+ APPL_TRACE_API("%s(jv_handle: 0x%2x), idx: %d, "
+ "app_id: 0x%x",__func__, jv_handle, i, bta_jv_cb.pm_cb[i].app_id);
+ APPL_TRACE_API("%s, bd_counter = %d, "
+ "appid_counter = %d", __func__, bd_counter, appid_counter);
if (bd_counter > 1)
{
bta_jv_pm_conn_idle(&bta_jv_cb.pm_cb[i]);
if (p_pcb)
{
if (NULL == p_pcb->p_pm_cb)
- APPL_TRACE_WARNING("bta_jv_free_set_pm_profile_cb(jv_handle:"
+ APPL_TRACE_WARNING("%s(jv_handle:"
" 0x%x):port_handle: 0x%x, p_pm_cb: %d: no link to "
- "pm_cb?", jv_handle, p_pcb->port_handle, i);
+ "pm_cb?", __func__, jv_handle, p_pcb->port_handle, i);
p_cb = &p_pcb->p_pm_cb;
}
}
{
tBTA_JV_L2C_CB *p_l2c_cb = &bta_jv_cb.l2c_cb[jv_handle];
if (NULL == p_l2c_cb->p_pm_cb)
- APPL_TRACE_WARNING("bta_jv_free_set_pm_profile_cb(jv_handle: "
- "0x%x): p_pm_cb: %d: no link to pm_cb?", jv_handle, i);
+ APPL_TRACE_WARNING("%s(jv_handle: "
+ "0x%x): p_pm_cb: %d: no link to pm_cb?", __func__, jv_handle, i);
p_cb = &p_l2c_cb->p_pm_cb;
}
}
}
/*******************************************************************************
- **
- ** Function bta_jv_alloc_sdp_id
- **
- ** Description allocate a SDP id for the given SDP record handle
- **
- ** Returns
- **
- *******************************************************************************/
-UINT32 bta_jv_alloc_sdp_id(UINT32 sdp_handle)
-{
- int j;
- UINT32 id = 0;
-
- /* find a free entry */
- for (j = 0; j < BTA_JV_MAX_SDP_REC; j++)
- {
- if (bta_jv_cb.sdp_handle[j] == 0)
- {
- bta_jv_cb.sdp_handle[j] = sdp_handle;
- id = (UINT32)(j + 1);
- break;
- }
- }
- /* the SDP record handle reported is the (index + 1) to control block */
- return id;
-}
-
-/*******************************************************************************
-**
-** Function bta_jv_free_sdp_id
-**
-** Description free the sdp id
-**
-** Returns
-**
-*******************************************************************************/
-void bta_jv_free_sdp_id(UINT32 sdp_id)
-{
- if(sdp_id > 0 && sdp_id <= BTA_JV_MAX_SDP_REC)
- {
- bta_jv_cb.sdp_handle[sdp_id - 1] = 0;
- }
-}
-
-/*******************************************************************************
-**
-** Function bta_jv_get_sdp_handle
-**
-** Description find the SDP handle associated with the given sdp id
-**
-** Returns
-**
-*******************************************************************************/
-UINT32 bta_jv_get_sdp_handle(UINT32 sdp_id)
-{
- UINT32 sdp_handle = 0;
-
- if(sdp_id > 0 && sdp_id <= BTA_JV_MAX_SDP_REC)
- {
- sdp_handle = bta_jv_cb.sdp_handle[sdp_id - 1];
- }
- return sdp_handle;
-}
-
-/*******************************************************************************
**
** Function bta_jv_check_psm
**
{
BOOLEAN ret = FALSE;
- if(L2C_IS_VALID_PSM(psm) )
+ if (L2C_IS_VALID_PSM(psm))
{
- if(psm < 0x1001)
+ if (psm < 0x1001)
{
/* see if this is defined by spec */
- switch(psm)
+ switch (psm)
{
case SDP_PSM: /* 1 */
case BT_PSM_RFCOMM: /* 3 */
}
}
else
+ {
ret = TRUE;
+ }
}
return ret;
tBTA_JV_STATUS status = BTA_JV_SUCCESS;
bta_jv_cb.p_dm_cback = p_data->enable.p_cback;
bta_jv_cb.p_dm_cback(BTA_JV_ENABLE_EVT, (tBTA_JV *)&status, 0);
+ memset(bta_jv_cb.free_psm_list,0,sizeof(bta_jv_cb.free_psm_list));
}
/*******************************************************************************
{
UNUSED(p_data);
- APPL_TRACE_ERROR("bta_jv_disable not used");
-#if 0
- int i;
+ APPL_TRACE_ERROR("%s",__func__);
+}
- bta_jv_cb.p_dm_cback = NULL;
- /* delete the SDP records created by java apps */
- for(i=0; i<BTA_JV_MAX_SDP_REC; i++)
- {
- if(bta_jv_cb.sdp_handle[i])
- {
- APPL_TRACE_DEBUG( "delete SDP record: %d", bta_jv_cb.sdp_handle[i]);
- SDP_DeleteRecord(bta_jv_cb.sdp_handle[i]);
- bta_jv_cb.sdp_handle[i] = 0;
- }
- }
- /* free the SCNs allocated by java apps */
- for(i=0; i<BTA_JV_MAX_SCN; i++)
- {
- if(bta_jv_cb.scn[i])
- {
- APPL_TRACE_DEBUG( "free scn: %d", (i+1));
- BTM_FreeSCN((UINT8)(i+1));
- bta_jv_cb.scn[i] = FALSE;
+/**
+ * We keep a list of PSM's that have been freed from JAVA, for reuse.
+ * This function will return a free PSM, and delete it from the free
+ * list.
+ * If no free PSMs exist, 0 will be returned.
+ */
+static UINT16 bta_jv_get_free_psm() {
+ const int cnt = sizeof(bta_jv_cb.free_psm_list)/sizeof(bta_jv_cb.free_psm_list[0]);
+ for (int i = 0; i < cnt; i++) {
+ UINT16 psm = bta_jv_cb.free_psm_list[i];
+ if (psm != 0) {
+ APPL_TRACE_DEBUG("%s(): Reusing PSM: 0x%04d", __func__, psm)
+ bta_jv_cb.free_psm_list[i] = 0;
+ return psm;
}
}
+ return 0;
+}
- /* disconnect L2CAP connections */
- for(i=0; i<BTA_JV_MAX_L2C_CONN; i++)
- {
- bta_jv_free_l2c_cb(&bta_jv_cb.l2c_cb[i]);
- }
-
- /* disconnect RFCOMM connections */
- for(i=0; i<BTA_JV_MAX_RFC_CONN; i++)
- {
- bta_jv_free_rfc_cb(&bta_jv_cb.rfc_cb[i]);
- }
-
- /* free the service records allocated by java apps */
- for(i=0; i<BTA_JV_NUM_SERVICE_ID; i++)
- {
- if(bta_jv_cb.sec_id[i])
- {
- BTM_SecClrService(bta_jv_cb.sec_id[i]);
- bta_jv_cb.sec_id[i] = 0;
+static void bta_jv_set_free_psm(UINT16 psm) {
+ int free_index = -1;
+ const int cnt = sizeof(bta_jv_cb.free_psm_list)/sizeof(bta_jv_cb.free_psm_list[0]);
+ for (int i = 0; i < cnt; i++) {
+ if (bta_jv_cb.free_psm_list[i] == 0) {
+ free_index = i;
+ } else if (psm == bta_jv_cb.free_psm_list[i]) {
+ return; // PSM already freed?
}
}
-#endif
-}
-
-/*******************************************************************************
-**
-** Function bta_jv_set_discoverability
-**
-** Description Sets discoverability
-**
-** Returns void
-**
-*******************************************************************************/
-void bta_jv_set_discoverability (tBTA_JV_MSG *p_data)
-{
- tBTA_JV evt_data;
-
- evt_data.set_discover.status = BTA_JV_FAILURE;
- /* initialize the default value for the event as the current mode */
- evt_data.set_discover.disc_mode = BTM_ReadDiscoverability(NULL, NULL);
-
- if(BTM_SUCCESS == BTM_SetDiscoverability((UINT8)p_data->set_discoverability.disc_mode, 0, 0))
- {
- evt_data.set_discover.status = BTA_JV_SUCCESS;
- /* update the mode, after BTM_SetDiscoverability() is successful */
- evt_data.set_discover.disc_mode = p_data->set_discoverability.disc_mode;
+ if (free_index != -1) {
+ bta_jv_cb.free_psm_list[free_index] = psm;
+ APPL_TRACE_DEBUG("%s(): Recycling PSM: 0x%04d", __func__, psm)
+ } else {
+ APPL_TRACE_ERROR("%s unable to free psm 0x%x no more free slots",__func__, psm);
}
-
- if(bta_jv_cb.p_dm_cback)
- bta_jv_cb.p_dm_cback(BTA_JV_SET_DISCOVER_EVT, &evt_data, 0);
-}
-
-/*******************************************************************************
-**
-** Function bta_jv_get_local_device_addr
-**
-** Description Reads the local Bluetooth device address
-**
-** Returns void
-**
-*******************************************************************************/
-void bta_jv_get_local_device_addr(tBTA_JV_MSG *p_data)
-{
- UNUSED(p_data);
-
- BTM_ReadLocalDeviceAddr((tBTM_CMPL_CB *)bta_jv_get_local_device_addr_cback);
-}
-
-/*******************************************************************************
-**
-** Function bta_jv_get_local_device_name
-**
-** Description Reads the local Bluetooth device name
-**
-** Returns void
-**
-*******************************************************************************/
-void bta_jv_get_local_device_name(tBTA_JV_MSG *p_data)
-{
- tBTA_JV evt_data;
- char *name;
- UNUSED(p_data);
-
- BTM_ReadLocalDeviceName(&name);
- evt_data.p_name = (UINT8*)name;
- if(bta_jv_cb.p_dm_cback)
- bta_jv_cb.p_dm_cback(BTA_JV_LOCAL_NAME_EVT, &evt_data, 0);
-}
-
-/*******************************************************************************
-**
-** Function bta_jv_get_remote_device_name
-**
-** Description Reads the local Bluetooth device name
-**
-** Returns void
-**
-*******************************************************************************/
-void bta_jv_get_remote_device_name(tBTA_JV_MSG *p_data)
-{
-
- BTM_ReadRemoteDeviceName(p_data->get_rmt_name.bd_addr,
- (tBTM_CMPL_CB *)bta_jv_get_remote_device_name_cback, BT_TRANSPORT_BR_EDR);
-}
-
-/*******************************************************************************
-**
-** Function bta_jv_set_service_class
-**
-** Description update the service class field of device class
-**
-** Returns void
-**
-*******************************************************************************/
-void bta_jv_set_service_class (tBTA_JV_MSG *p_data)
-{
- tBTA_UTL_COD cod;
-
- /* set class of device */
- /*
- BTA_JvSetServiceClass(UINT32 service) assumes that the service class passed to the
- API function as defined in the assigned number page.
- For example: the object transfer bit is bit 20 of the 24-bit Class of device;
- the value of this bit is 0x00100000 (value 1)
- Our btm_api.h defines this bit as #define BTM_COD_SERVICE_OBJ_TRANSFER 0x1000 (value 2)
- This reflects that the service class defined at btm is UINT16,
- which starts at bit 8 of the 24 bit Class of Device
- The following statement converts from (value 1) into (value 2)
- */
- cod.service = (p_data->set_service.service >> 8);
- utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
}
/*******************************************************************************
**
-** Function bta_jv_sec_cback
+** Function bta_jv_get_channel_id
**
-** Description callback function to handle set encryption complete event
+** Description Obtain a free SCN (Server Channel Number)
+** (RFCOMM channel or L2CAP PSM)
**
** Returns void
**
*******************************************************************************/
-static void bta_jv_sec_cback (BD_ADDR bd_addr, tBTA_TRANSPORT transport,
- void *p_ref_data, tBTM_STATUS result)
+void bta_jv_get_channel_id(tBTA_JV_MSG *p_data)
{
- UNUSED(p_ref_data);
- UNUSED(transport);
+ UINT16 psm = 0;
- tBTA_JV_SET_ENCRYPTION set_enc;
- if(bta_jv_cb.p_dm_cback)
- {
- bdcpy(set_enc.bd_addr, bd_addr);
- set_enc.status = result;
- if (result > BTA_JV_BUSY)
- set_enc.status = BTA_JV_FAILURE;
- bta_jv_cb.p_dm_cback(BTA_JV_SET_ENCRYPTION_EVT, (tBTA_JV *)&set_enc, 0);
+ switch (p_data->alloc_channel.type) {
+ case BTA_JV_CONN_TYPE_RFCOMM: {
+ INT32 channel = p_data->alloc_channel.channel;
+ UINT8 scn = 0;
+ if (channel > 0)
+ {
+ if (BTM_TryAllocateSCN(channel) == FALSE)
+ {
+ APPL_TRACE_ERROR("rfc channel:%d already in use or invalid", channel);
+ channel = 0;
+ }
+ } else if ((channel = BTM_AllocateSCN()) == 0) {
+ APPL_TRACE_ERROR("run out of rfc channels");
+ channel = 0;
+ }
+ if (channel != 0) {
+ bta_jv_cb.scn[channel-1] = TRUE;
+ scn = (UINT8) channel;
+ }
+ if (bta_jv_cb.p_dm_cback)
+ bta_jv_cb.p_dm_cback(BTA_JV_GET_SCN_EVT, (tBTA_JV *)&scn,
+ p_data->alloc_channel.user_data);
+ return;
+ }
+ case BTA_JV_CONN_TYPE_L2CAP:
+ psm = bta_jv_get_free_psm();
+ if (psm == 0) {
+ psm = L2CA_AllocatePSM();
+ APPL_TRACE_DEBUG("%s() returned PSM: 0x%04x", __func__, psm);
+ }
+ break;
+ case BTA_JV_CONN_TYPE_L2CAP_LE:
+ break;
+ default:
+ break;
}
-}
-
-/*******************************************************************************
-**
-** Function bta_jv_set_encryption
-**
-** Description Reads the local Bluetooth device name
-**
-** Returns void
-**
-*******************************************************************************/
-void bta_jv_set_encryption(tBTA_JV_MSG *p_data)
-{
- BTM_SetEncryption(p_data->set_encrypt.bd_addr, BTA_TRANSPORT_BR_EDR, bta_jv_sec_cback, NULL);
-}
-/*******************************************************************************
-**
-** Function bta_jv_get_scn
-**
-** Description obtain a free SCN
-**
-** Returns void
-**
-*******************************************************************************/
-void bta_jv_get_scn(tBTA_JV_MSG *p_data)
-{
- UNUSED(p_data);
-#if 0
- UINT8 scn;
- scn = BTM_AllocateSCN();
- if(scn)
- bta_jv_cb.scn[scn-1] = TRUE;
- if(bta_jv_cb.p_dm_cback)
- bta_jv_cb.p_dm_cback(BTA_JV_GET_SCN_EVT, (tBTA_JV *)&scn);
-#endif
+ if (bta_jv_cb.p_dm_cback)
+ bta_jv_cb.p_dm_cback(BTA_JV_GET_PSM_EVT, (tBTA_JV *)&psm, p_data->alloc_channel.user_data);
}
/*******************************************************************************
*******************************************************************************/
void bta_jv_free_scn(tBTA_JV_MSG *p_data)
{
- UINT8 scn = p_data->free_scn.scn;
+ UINT16 scn = p_data->free_channel.scn;
- if (scn > 0 && scn <= BTA_JV_MAX_SCN && bta_jv_cb.scn[scn-1])
- {
- /* this scn is used by JV */
- bta_jv_cb.scn[scn-1] = FALSE;
- BTM_FreeSCN(scn);
+ switch (p_data->free_channel.type) {
+ case BTA_JV_CONN_TYPE_RFCOMM: {
+ if (scn > 0 && scn <= BTA_JV_MAX_SCN && bta_jv_cb.scn[scn-1])
+ {
+ /* this scn is used by JV */
+ bta_jv_cb.scn[scn-1] = FALSE;
+ BTM_FreeSCN(scn);
+ }
+ break;
+ }
+ case BTA_JV_CONN_TYPE_L2CAP:
+ bta_jv_set_free_psm(scn);
+ break;
+ case BTA_JV_CONN_TYPE_L2CAP_LE:
+ // TODO: Not yet implemented...
+ break;
+ default:
+ break;
}
}
static inline tBT_UUID shorten_sdp_uuid(const tBT_UUID* u)
bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_NONE;
if(bta_jv_cb.p_dm_cback)
{
- if (old_sdp_act == BTA_JV_SDP_ACT_CANCEL)
- {
- APPL_TRACE_DEBUG("BTA_JV_SDP_ACT_CANCEL");
- status = BTA_JV_SUCCESS;
- bta_jv_cb.p_dm_cback(BTA_JV_CANCEL_DISCVRY_EVT, (tBTA_JV *)&status, user_data);
- }
- else
+ tBTA_JV_DISCOVERY_COMP dcomp;
+ dcomp.scn = 0;
+ status = BTA_JV_FAILURE;
+ if (result == SDP_SUCCESS || result == SDP_DB_FULL)
{
- tBTA_JV_DISCOVERY_COMP dcomp;
- dcomp.scn = 0;
- status = BTA_JV_FAILURE;
- if (result == SDP_SUCCESS || result == SDP_DB_FULL)
+ tSDP_DISC_REC *p_sdp_rec = NULL;
+ tSDP_PROTOCOL_ELEM pe;
+ logu("bta_jv_cb.uuid", bta_jv_cb.uuid.uu.uuid128);
+ tBT_UUID su = shorten_sdp_uuid(&bta_jv_cb.uuid);
+ logu("shorten uuid:", su.uu.uuid128);
+ p_sdp_rec = SDP_FindServiceUUIDInDb(p_bta_jv_cfg->p_sdp_db, &su, p_sdp_rec);
+ APPL_TRACE_DEBUG("p_sdp_rec:%p", p_sdp_rec);
+ if (p_sdp_rec && SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe))
{
- tSDP_DISC_REC *p_sdp_rec = NULL;
- tSDP_PROTOCOL_ELEM pe;
- logu("bta_jv_cb.uuid", bta_jv_cb.uuid.uu.uuid128);
- tBT_UUID su = shorten_sdp_uuid(&bta_jv_cb.uuid);
- logu("shorten uuid:", su.uu.uuid128);
- p_sdp_rec = SDP_FindServiceUUIDInDb(p_bta_jv_cfg->p_sdp_db, &su, p_sdp_rec);
- APPL_TRACE_DEBUG("p_sdp_rec:%p", p_sdp_rec);
- if(p_sdp_rec && SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe))
- {
- dcomp.scn = (UINT8) pe.params[0];
- status = BTA_JV_SUCCESS;
- }
+ dcomp.scn = (UINT8) pe.params[0];
+ status = BTA_JV_SUCCESS;
}
-
- dcomp.status = status;
- bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, (tBTA_JV *)&dcomp, user_data);
}
- //free sdp db
- //utl_freebuf(&(p_bta_jv_cfg->p_sdp_db));
+
+ dcomp.status = status;
+ bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, (tBTA_JV *)&dcomp, user_data);
}
}
bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, (tBTA_JV *)&status, p_data->start_discovery.user_data);
return;
}
-/*
- if(p_data->start_discovery.num_uuid == 0)
- {
- p_data->start_discovery.num_uuid = 1;
- p_data->start_discovery.uuid_list[0].len = 2;
- p_data->start_discovery.uuid_list[0].uu.uuid16 = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
- }
-*/
+
/* init the database/set up the filter */
APPL_TRACE_DEBUG("call SDP_InitDiscoveryDb, p_data->start_discovery.num_uuid:%d",
p_data->start_discovery.num_uuid);
/*******************************************************************************
**
-** Function bta_jv_cancel_discovery
-**
-** Description Cancels an active discovery
-**
-** Returns void
-**
-*******************************************************************************/
-void bta_jv_cancel_discovery(tBTA_JV_MSG *p_data)
-{
- tBTA_JV_STATUS status = BTA_JV_SUCCESS;
- if (bta_jv_cb.sdp_active == BTA_JV_SDP_ACT_YES)
- {
- if (SDP_CancelServiceSearch (p_bta_jv_cfg->p_sdp_db))
- {
- bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_CANCEL;
- return;
- }
- }
- if(bta_jv_cb.p_dm_cback)
- bta_jv_cb.p_dm_cback(BTA_JV_CANCEL_DISCVRY_EVT, (tBTA_JV *)&status, p_data->cancel_discovery.user_data);
-}
-
-/*******************************************************************************
-**
-** Function bta_jv_get_services_length
-**
-** Description Obtain the length of each record in the SDP DB.
-**
-** Returns void
-**
-*******************************************************************************/
-void bta_jv_get_services_length(tBTA_JV_MSG *p_data)
-{
- UNUSED(p_data);
-#if 0
- tBTA_JV_SERVICES_LEN evt_data;
- UINT8 *p, *np, *op, type;
- UINT32 raw_used, raw_cur;
- UINT32 len;
-
- evt_data.num_services = -1;
- evt_data.p_services_len = p_data->get_services_length.p_services_len;
- if(p_bta_jv_cfg->p_sdp_db->p_first_rec)
- {
- /* the database is valid */
- evt_data.num_services = 0;
- p = p_bta_jv_cfg->p_sdp_db->raw_data;
- raw_used = p_bta_jv_cfg->p_sdp_db->raw_used;
- while(raw_used && p)
- {
- op = p;
- type = *p++;
- np = sdpu_get_len_from_type(p, type, &len);
- p = np + len;
- raw_cur = p - op;
- if(raw_used >= raw_cur)
- {
- raw_used -= raw_cur;
- }
- else
- {
- /* error. can not continue */
- break;
- }
- if(p_data->get_services_length.inc_hdr)
- {
- evt_data.p_services_len[evt_data.num_services++] = len + np - op;
- }
- else
- {
- evt_data.p_services_len[evt_data.num_services++] = len;
- }
- } /* end of while */
- }
-
- if(bta_jv_cb.p_dm_cback)
- bta_jv_cb.p_dm_cback(BTA_JV_SERVICES_LEN_EVT, (tBTA_JV *)&evt_data);
-#endif
-}
-
-/*******************************************************************************
-**
-** Function bta_jv_service_select
-**
-** Description Obtain the length of given UUID in the SDP DB.
-**
-** Returns void
-**
-*******************************************************************************/
-void bta_jv_service_select(tBTA_JV_MSG *p_data)
-{
- UNUSED(p_data);
-#if 0
- tBTA_JV_SERVICE_SEL serv_sel;
- tSDP_DISC_REC *p_rec, *p_tmp;
- UINT8 *p, *np, *op, type;
- UINT32 raw_used, raw_cur;
- UINT32 len;
-
- serv_sel.service_len = 0;
- bta_jv_cb.p_sel_raw_data = 0;
- p_rec = SDP_FindServiceInDb (p_bta_jv_cfg->p_sdp_db, p_data->service_select.uuid, NULL);
- if(p_rec)
- {
- /* found the record in the database */
- /* the database must be valid */
- p = p_bta_jv_cfg->p_sdp_db->raw_data;
- raw_used = p_bta_jv_cfg->p_sdp_db->raw_used;
- p_tmp = p_bta_jv_cfg->p_sdp_db->p_first_rec;
- while(raw_used && p && p_tmp)
- {
- op = p;
- type = *p++;
- np = sdpu_get_len_from_type(p, type, &len);
- if(p_tmp == p_rec)
- {
- bta_jv_cb.p_sel_raw_data = op;
- bta_jv_cb.sel_len = len;
- serv_sel.service_len = len;
- bdcpy(serv_sel.bd_addr, p_rec->remote_bd_addr);
- APPL_TRACE_DEBUG( "bta_jv_service_select found uuid: 0x%x",
- p_data->service_select.uuid);
- break;
- }
- p = np + len;
- raw_cur = p - op;
- if(raw_used >= raw_cur)
- {
- raw_used -= raw_cur;
- }
- else
- {
- /* error. can not continue */
- break;
- }
- p_tmp = p_tmp->p_next_rec;
- } /* end of while */
- }
- APPL_TRACE_DEBUG( "service_len: %d", serv_sel.service_len);
- if(bta_jv_cb.p_dm_cback)
- bta_jv_cb.p_dm_cback(BTA_JV_SERVICE_SEL_EVT, (tBTA_JV *)&serv_sel);
-#endif
-}
-
-/*******************************************************************************
-**
** Function bta_jv_create_record
**
** Description Create an SDP record with the given attributes
/*******************************************************************************
**
-** Function bta_jv_update_record
-**
-** Description Update an SDP record with the given attributes
-**
-** Returns void
-**
-*******************************************************************************/
-void bta_jv_update_record(tBTA_JV_MSG *p_data)
-{
- UNUSED(p_data);
-#if 0
- tBTA_JV_API_UPDATE_RECORD *ur = &(p_data->update_record);
- tBTA_JV_UPDATE_RECORD evt_data;
- UINT32 handle;
- INT32 i;
- UINT8 *ptr;
- UINT8 *next_ptr;
- UINT8 *end;
- UINT32 len;
- UINT8 type;
-
- evt_data.status = BTA_JV_FAILURE;
- evt_data.handle = ur->handle;
-
- handle = bta_jv_get_sdp_handle(ur->handle);
-
- if(handle)
- {
- /* this is a record created by JV */
- for (i = 0; i < ur->array_len; i++)
- {
- ptr = ur->p_values[i];
- end = ptr + ur->p_value_sizes[i];
-
- while (ptr < end)
- {
- type = *ptr;
- next_ptr = sdpu_get_len_from_type(ptr + 1, *ptr, &len);
-
- if(ATTR_ID_SERVICE_RECORD_HDL != ur->p_ids[i])
- {
- if (!SDP_AddAttribute(handle, ur->p_ids[i], (UINT8)((type >> 3) & 0x1f),
- len, next_ptr))
- {
- /* failed on updating attributes. */
- if(bta_jv_cb.p_dm_cback)
- bta_jv_cb.p_dm_cback(BTA_JV_UPDATE_RECORD_EVT, (tBTA_JV *)&evt_data);
- return;
- }
- }
-
- ptr = next_ptr + len;
- } /* end of while */
- } /* end of for */
- evt_data.status = BTA_JV_SUCCESS;
- }
-
- if(bta_jv_cb.p_dm_cback)
- bta_jv_cb.p_dm_cback(BTA_JV_UPDATE_RECORD_EVT, (tBTA_JV *)&evt_data);
-#endif
-}
-
-/*******************************************************************************
-**
-** Function bta_jv_add_attribute
-**
-** Description Add an attribute to an SDP record
-**
-** Returns void
-**
-*******************************************************************************/
-void bta_jv_add_attribute(tBTA_JV_MSG *p_data)
-{
- UNUSED(p_data);
-#if 0
- tBTA_JV_API_ADD_ATTRIBUTE *aa = &(p_data->add_attr);
- tBTA_JV_ADD_ATTR evt_data;
- UINT32 handle;
- UINT8 type;
- UINT32 len;
- UINT8 *ptr;
- UINT8 *next_ptr;
-
- evt_data.status = BTA_JV_FAILURE;
- evt_data.handle = aa->handle;
- handle = bta_jv_get_sdp_handle(aa->handle);
-
- if(handle)
- {
- /* this is a record created by JV */
- ptr = aa->p_value;
- type = *ptr;
- next_ptr = sdpu_get_len_from_type(ptr + 1, *ptr, &len);
- APPL_TRACE_DEBUG( "bta_jv_add_attribute: ptr chg:%d len:%d, size:%d",
- (next_ptr - ptr), len, aa->value_size);
- if(ATTR_ID_SERVICE_RECORD_HDL != aa->attr_id && /* do not allow the SDP record handle to be updated */
- ((INT32)(next_ptr - ptr + len) == aa->value_size) && /* double check data size */
- SDP_AddAttribute(handle, aa->attr_id, (UINT8)((type >> 3) & 0x1f),
- len, next_ptr))
- {
- evt_data.status = BTA_JV_SUCCESS;
- }
- }
-
- if(bta_jv_cb.p_dm_cback)
- bta_jv_cb.p_dm_cback(BTA_JV_ADD_ATTR_EVT, (tBTA_JV *)&evt_data);
-#endif
-}
-
-/*******************************************************************************
-**
-** Function bta_jv_delete_attribute
-**
-** Description Delete an attribute from the given SDP record
-**
-** Returns void
-**
-*******************************************************************************/
-void bta_jv_delete_attribute(tBTA_JV_MSG *p_data)
-{
- UNUSED(p_data);
-#if 0
- tBTA_JV_API_ADD_ATTRIBUTE *da = &(p_data->add_attr);
- tBTA_JV_DELETE_ATTR evt_data;
- UINT32 handle;
-
- evt_data.status = BTA_JV_FAILURE;
- evt_data.handle = da->handle;
- handle = bta_jv_get_sdp_handle(da->handle);
-
- if(handle)
- {
- /* this is a record created by JV */
- if(SDP_DeleteAttribute(handle, da->attr_id))
- evt_data.status = BTA_JV_SUCCESS;
- }
-
- if(bta_jv_cb.p_dm_cback)
- bta_jv_cb.p_dm_cback(BTA_JV_DELETE_ATTR_EVT, (tBTA_JV *)&evt_data);
-#endif
-}
-
-/*******************************************************************************
-**
** Function bta_jv_delete_record
**
** Description Delete an SDP record
}
}
-#if SDP_FOR_JV_INCLUDED == TRUE
/*******************************************************************************
**
-** Function bta_jv_sdp_res_cback
+** Function bta_jv_l2cap_client_cback
**
-** Description Callback for Start Discovery
+** Description handles the l2cap client events
**
** Returns void
**
*******************************************************************************/
-void bta_jv_sdp_res_cback (UINT16 event, tSDP_DATA *p_data)
+static void bta_jv_l2cap_client_cback(UINT16 gap_handle, UINT16 event)
{
- tBTA_JV evt_data;
- tBTA_JV_L2C_CB *p_cb = &bta_jv_cb.l2c_cb[BTA_JV_L2C_FOR_SDP_HDL];
-
- APPL_TRACE_DEBUG( "bta_jv_sdp_res_cback: %d evt:x%x",
- bta_jv_cb.sdp_for_jv, event);
+ tBTA_JV_L2C_CB *p_cb = &bta_jv_cb.l2c_cb[gap_handle];
+ tBTA_JV evt_data;
- if(!bta_jv_cb.sdp_for_jv)
+ if (gap_handle >= BTA_JV_MAX_L2C_CONN && !p_cb->p_cback)
return;
+ APPL_TRACE_DEBUG( "%s: %d evt:x%x",__func__, gap_handle, event);
evt_data.l2c_open.status = BTA_JV_SUCCESS;
- evt_data.l2c_open.handle = BTA_JV_L2C_FOR_SDP_HDL;
+ evt_data.l2c_open.handle = gap_handle;
- switch(event)
+ switch (event)
{
- case SDP_EVT_OPEN:
- bdcpy(evt_data.l2c_open.rem_bda, p_data->open.peer_addr);
- evt_data.l2c_open.tx_mtu = p_data->open.peer_mtu;
- p_cb->state = BTA_JV_ST_SR_OPEN;
- p_cb->p_cback(BTA_JV_L2CAP_OPEN_EVT, &evt_data);
- break;
- case SDP_EVT_DATA_IND:
- evt_data.handle = BTA_JV_L2C_FOR_SDP_HDL;
- memcpy(p_bta_jv_cfg->p_sdp_raw_data, p_data->data.p_data, p_data->data.data_len);
- APPL_TRACE_DEBUG( "data size: %d/%d ", bta_jv_cb.sdp_data_size, p_data->data.data_len);
- bta_jv_cb.sdp_data_size = p_data->data.data_len;
- p_cb->p_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data);
+ case GAP_EVT_CONN_OPENED:
+ bdcpy(evt_data.l2c_open.rem_bda, GAP_ConnGetRemoteAddr(gap_handle));
+ evt_data.l2c_open.tx_mtu = GAP_ConnGetRemMtuSize(gap_handle);
+ p_cb->state = BTA_JV_ST_CL_OPEN;
+ p_cb->p_cback(BTA_JV_L2CAP_OPEN_EVT, &evt_data, p_cb->user_data);
break;
- }
-}
-
-/*******************************************************************************
-**
-** Function bta_jv_sdp_cback
-**
-** Description Callback for Start Discovery
-**
-** Returns void
-**
-*******************************************************************************/
-static void bta_jv_sdp_cback(UINT16 result)
-{
- tBTA_JV_L2CAP_CLOSE close;
- tBTA_JV_L2C_CB *p_cb = &bta_jv_cb.l2c_cb[BTA_JV_L2C_FOR_SDP_HDL];
- APPL_TRACE_DEBUG( "bta_jv_sdp_cback: result:x%x", result);
- if(p_cb->p_cback)
- {
- close.handle = BTA_JV_L2C_FOR_SDP_HDL;
- close.async = FALSE;
- close.status = BTA_JV_SUCCESS;
+ case GAP_EVT_CONN_CLOSED:
+ p_cb->state = BTA_JV_ST_NONE;
bta_jv_free_sec_id(&p_cb->sec_id);
- p_cb->p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV *)&close);
- }
+ evt_data.l2c_close.async = TRUE;
+ p_cb->p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt_data, p_cb->user_data);
+ p_cb->p_cback = NULL;
+ break;
- bta_jv_cb.sdp_for_jv = 0;
- p_cb->p_cback = NULL;
+ case GAP_EVT_CONN_DATA_AVAIL:
+ evt_data.data_ind.handle = gap_handle;
+ /* Reset idle timer to avoid requesting sniff mode while receiving data */
+ bta_jv_pm_conn_busy(p_cb->p_pm_cb);
+ p_cb->p_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data, p_cb->user_data);
+ bta_jv_pm_conn_idle(p_cb->p_pm_cb);
+ break;
+
+ case GAP_EVT_CONN_CONGESTED:
+ case GAP_EVT_CONN_UNCONGESTED:
+ p_cb->cong = (event == GAP_EVT_CONN_CONGESTED) ? TRUE : FALSE;
+ evt_data.l2c_cong.cong = p_cb->cong;
+ p_cb->p_cback(BTA_JV_L2CAP_CONG_EVT, &evt_data, p_cb->user_data);
+ break;
+ default:
+ break;
+ }
}
-#endif
/*******************************************************************************
**
*******************************************************************************/
void bta_jv_l2cap_connect(tBTA_JV_MSG *p_data)
{
- UNUSED(p_data);
-#if 0
tBTA_JV_L2C_CB *p_cb;
tBTA_JV_L2CAP_CL_INIT evt_data;
UINT16 handle=GAP_INVALID_HANDLE;
UINT8 sec_id;
tL2CAP_CFG_INFO cfg;
tBTA_JV_API_L2CAP_CONNECT *cc = &(p_data->l2cap_connect);
+ UINT8 chan_mode_mask = GAP_FCR_CHAN_OPT_BASIC;
+ tL2CAP_ERTM_INFO *ertm_info = NULL;
memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ if (cc->has_cfg == TRUE)
+ {
+ cfg = cc->cfg;
+ if (cfg.fcr_present && cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
+ chan_mode_mask = GAP_FCR_CHAN_OPT_ERTM;
+ }
+ }
+
+ if (cc->has_ertm_info == TRUE)
+ {
+ ertm_info = &(cc->ertm_info);
+ }
+
+ /* We need to use this value for MTU to be able to handle cases where cfg is not set in req. */
cfg.mtu_present = TRUE;
cfg.mtu = cc->rx_mtu;
+
/* TODO: DM role manager
L2CA_SetDesireRole(cc->role);
*/
sec_id = bta_jv_alloc_sec_id();
evt_data.sec_id = sec_id;
evt_data.status = BTA_JV_FAILURE;
+
if (sec_id)
{
-#if SDP_FOR_JV_INCLUDED == TRUE
- if(SDP_PSM == cc->remote_psm && 0 == bta_jv_cb.sdp_for_jv)
+ if (bta_jv_check_psm(cc->remote_psm)) /* allowed */
{
- bta_jv_cb.sdp_for_jv = SDP_ConnOpen(cc->peer_bd_addr,
- bta_jv_sdp_res_cback,
- bta_jv_sdp_cback);
- if(bta_jv_cb.sdp_for_jv)
- {
- bta_jv_cb.sdp_data_size = 0;
- handle = BTA_JV_L2C_FOR_SDP_HDL;
- evt_data.status = BTA_JV_SUCCESS;
- }
- }
- else
-#endif
- if(bta_jv_check_psm(cc->remote_psm)) /* allowed */
- {
- if( (handle = GAP_ConnOpen("", sec_id, 0, cc->peer_bd_addr, cc->remote_psm,
- &cfg, cc->sec_mask, GAP_FCR_CHAN_OPT_BASIC,
+ if ((handle = GAP_ConnOpen("", sec_id, 0, cc->peer_bd_addr, cc->remote_psm,
+ &cfg, ertm_info, cc->sec_mask, chan_mode_mask,
bta_jv_l2cap_client_cback)) != GAP_INVALID_HANDLE )
{
evt_data.status = BTA_JV_SUCCESS;
p_cb = &bta_jv_cb.l2c_cb[handle];
p_cb->handle = handle;
p_cb->p_cback = cc->p_cback;
+ p_cb->user_data = cc->user_data;
p_cb->psm = 0; /* not a server */
p_cb->sec_id = sec_id;
p_cb->state = BTA_JV_ST_CL_OPENING;
{
bta_jv_free_sec_id(&sec_id);
}
+
evt_data.handle = handle;
- cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, (tBTA_JV *)&evt_data);
-#endif
+ cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, (tBTA_JV *)&evt_data, cc->user_data);
}
+
/*******************************************************************************
**
** Function bta_jv_l2cap_close
*******************************************************************************/
void bta_jv_l2cap_close(tBTA_JV_MSG *p_data)
{
- UNUSED(p_data);
-#if 0
tBTA_JV_L2CAP_CLOSE evt_data;
tBTA_JV_API_L2CAP_CLOSE *cc = &(p_data->l2cap_close);
tBTA_JV_L2CAP_CBACK *p_cback = cc->p_cb->p_cback;
+ void *user_data = cc->p_cb->user_data;
+
+ evt_data.handle = cc->handle;
+ evt_data.status = bta_jv_free_l2c_cb(cc->p_cb);
+ evt_data.async = FALSE;
+
+ if (p_cback)
+ p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV *)&evt_data, user_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_server_cback
+**
+** Description handles the l2cap server callback
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_jv_l2cap_server_cback(UINT16 gap_handle, UINT16 event)
+{
+ tBTA_JV_L2C_CB *p_cb = &bta_jv_cb.l2c_cb[gap_handle];
+ tBTA_JV evt_data;
+ tBTA_JV_L2CAP_CBACK *p_cback;
+ void *user_data;
+
+ if (gap_handle >= BTA_JV_MAX_L2C_CONN && !p_cb->p_cback)
+ return;
+
+ APPL_TRACE_DEBUG( "%s: %d evt:x%x", __func__, gap_handle, event);
+ evt_data.l2c_open.status = BTA_JV_SUCCESS;
+ evt_data.l2c_open.handle = gap_handle;
+
+ switch (event)
+ {
+ case GAP_EVT_CONN_OPENED:
+ bdcpy(evt_data.l2c_open.rem_bda, GAP_ConnGetRemoteAddr(gap_handle));
+ evt_data.l2c_open.tx_mtu = GAP_ConnGetRemMtuSize(gap_handle);
+ p_cb->state = BTA_JV_ST_SR_OPEN;
+ p_cb->p_cback(BTA_JV_L2CAP_OPEN_EVT, &evt_data, p_cb->user_data);
+ break;
+
+ case GAP_EVT_CONN_CLOSED:
+ evt_data.l2c_close.async = TRUE;
+ evt_data.l2c_close.handle = p_cb->handle;
+ p_cback = p_cb->p_cback;
+ user_data = p_cb->user_data;
+ evt_data.l2c_close.status = bta_jv_free_l2c_cb(p_cb);
+ p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt_data, user_data);
+ break;
- evt_data.handle = cc->handle;
- evt_data.status = bta_jv_free_l2c_cb(cc->p_cb);
- evt_data.async = FALSE;
+ case GAP_EVT_CONN_DATA_AVAIL:
+ evt_data.data_ind.handle = gap_handle;
+ /* Reset idle timer to avoid requesting sniff mode while receiving data */
+ bta_jv_pm_conn_busy(p_cb->p_pm_cb);
+ p_cb->p_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data, p_cb->user_data);
+ bta_jv_pm_conn_idle(p_cb->p_pm_cb);
+ break;
- if (p_cback)
- p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV *)&evt_data);
- else
- APPL_TRACE_ERROR("### NO CALLBACK SET !!! ###");
-#endif
+ case GAP_EVT_CONN_CONGESTED:
+ case GAP_EVT_CONN_UNCONGESTED:
+ p_cb->cong = (event == GAP_EVT_CONN_CONGESTED) ? TRUE : FALSE;
+ evt_data.l2c_cong.cong = p_cb->cong;
+ p_cb->p_cback(BTA_JV_L2CAP_CONG_EVT, &evt_data, p_cb->user_data);
+ break;
+
+ default:
+ break;
+ }
}
/*******************************************************************************
*******************************************************************************/
void bta_jv_l2cap_start_server(tBTA_JV_MSG *p_data)
{
- UNUSED(p_data);
-#if 0
tBTA_JV_L2C_CB *p_cb;
UINT8 sec_id;
UINT16 handle;
tL2CAP_CFG_INFO cfg;
tBTA_JV_L2CAP_START evt_data;
tBTA_JV_API_L2CAP_SERVER *ls = &(p_data->l2cap_server);
+ INT32 use_etm = FALSE;
+ UINT8 chan_mode_mask = GAP_FCR_CHAN_OPT_BASIC;
+ tL2CAP_ERTM_INFO *ertm_info = NULL;
memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ if (ls->has_cfg == TRUE) {
+ cfg = ls->cfg;
+ if (cfg.fcr_present && cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
+ chan_mode_mask = GAP_FCR_CHAN_OPT_ERTM;
+ }
+ }
+
+ if (ls->has_ertm_info == TRUE) {
+ ertm_info = &(ls->ertm_info);
+ }
+
//FIX: MTU=0 means not present
if (ls->rx_mtu >0)
{
sec_id = bta_jv_alloc_sec_id();
if (0 == sec_id || (FALSE == bta_jv_check_psm(ls->local_psm)) ||
- (handle = GAP_ConnOpen("JV L2CAP", sec_id, 1, 0, ls->local_psm, &cfg,
- ls->sec_mask, GAP_FCR_CHAN_OPT_BASIC, bta_jv_l2cap_server_cback)) == GAP_INVALID_HANDLE)
+ (handle = GAP_ConnOpen("JV L2CAP", sec_id, 1, 0, ls->local_psm, &cfg, ertm_info,
+ ls->sec_mask, chan_mode_mask, bta_jv_l2cap_server_cback)) == GAP_INVALID_HANDLE)
{
bta_jv_free_sec_id(&sec_id);
evt_data.status = BTA_JV_FAILURE;
}
else
{
- /* default JV implementation requires explicit call
- to allow incoming connections when ready*/
-
- GAP_SetAcceptReady(handle, FALSE);
-
p_cb = &bta_jv_cb.l2c_cb[handle];
evt_data.status = BTA_JV_SUCCESS;
evt_data.handle = handle;
evt_data.sec_id = sec_id;
p_cb->p_cback = ls->p_cback;
+ p_cb->user_data = ls->user_data;
p_cb->handle = handle;
p_cb->sec_id = sec_id;
p_cb->state = BTA_JV_ST_SR_LISTEN;
p_cb->psm = ls->local_psm;
}
- ls->p_cback(BTA_JV_L2CAP_START_EVT, (tBTA_JV *)&evt_data);
-#endif
+
+ ls->p_cback(BTA_JV_L2CAP_START_EVT, (tBTA_JV *)&evt_data, ls->user_data);
}
/*******************************************************************************
*******************************************************************************/
void bta_jv_l2cap_stop_server(tBTA_JV_MSG *p_data)
{
- UNUSED(p_data);
-#if 0
tBTA_JV_L2C_CB *p_cb;
tBTA_JV_L2CAP_CLOSE evt_data;
tBTA_JV_API_L2CAP_SERVER *ls = &(p_data->l2cap_server);
tBTA_JV_L2CAP_CBACK *p_cback;
- int i;
-
- for(i=0; i<BTA_JV_MAX_L2C_CONN; i++)
+ void *user_data;
+ for (int i = 0; i < BTA_JV_MAX_L2C_CONN; i++)
{
- if(bta_jv_cb.l2c_cb[i].psm == ls->local_psm)
+ if (bta_jv_cb.l2c_cb[i].psm == ls->local_psm)
{
p_cb = &bta_jv_cb.l2c_cb[i];
p_cback = p_cb->p_cback;
+ user_data = p_cb->user_data;
evt_data.handle = p_cb->handle;
evt_data.status = bta_jv_free_l2c_cb(p_cb);
evt_data.async = FALSE;
- p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV *)&evt_data);
+ p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV *)&evt_data, user_data);
break;
}
}
-#endif
}
+
+
/*******************************************************************************
**
** Function bta_jv_l2cap_read
*******************************************************************************/
void bta_jv_l2cap_read(tBTA_JV_MSG *p_data)
{
- UNUSED(p_data);
-#if 0
tBTA_JV_L2CAP_READ evt_data;
tBTA_JV_API_L2CAP_READ *rc = &(p_data->l2cap_read);
evt_data.req_id = rc->req_id;
evt_data.p_data = rc->p_data;
evt_data.len = 0;
-#if SDP_FOR_JV_INCLUDED == TRUE
- if(BTA_JV_L2C_FOR_SDP_HDL == rc->handle)
- {
- evt_data.len = rc->len;
- if(evt_data.len > bta_jv_cb.sdp_data_size)
- evt_data.len = bta_jv_cb.sdp_data_size;
- memcpy(rc->p_data, p_bta_jv_cfg->p_sdp_raw_data, evt_data.len);
- bta_jv_cb.sdp_data_size = 0;
- evt_data.status = BTA_JV_SUCCESS;
- }
- else
-#endif
if (BT_PASS == GAP_ConnReadData(rc->handle, rc->p_data, rc->len, &evt_data.len))
{
evt_data.status = BTA_JV_SUCCESS;
}
- rc->p_cback(BTA_JV_L2CAP_READ_EVT, (tBTA_JV *)&evt_data);
-#endif
+ rc->p_cback(BTA_JV_L2CAP_READ_EVT, (tBTA_JV *)&evt_data, rc->user_data);
}
*******************************************************************************/
void bta_jv_l2cap_write(tBTA_JV_MSG *p_data)
{
- UNUSED(p_data);
-#if 0
tBTA_JV_L2CAP_WRITE evt_data;
tBTA_JV_API_L2CAP_WRITE *ls = &(p_data->l2cap_write);
- evt_data.status = BTA_JV_FAILURE;
- evt_data.handle = ls->handle;
- evt_data.req_id = ls->req_id;
- evt_data.cong = ls->p_cb->cong;
- evt_data.len = 0;
-#if SDP_FOR_JV_INCLUDED == TRUE
- if(BTA_JV_L2C_FOR_SDP_HDL == ls->handle)
- {
- UINT8 *p;
- BT_HDR *p_msg = (BT_HDR *) GKI_getbuf ((UINT16)(ls->len + BT_HDR_SIZE + L2CAP_MIN_OFFSET));
- if(p_msg)
- {
- p_msg->offset = L2CAP_MIN_OFFSET;
- p = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET;
- p_msg->len = ls->len;
- memcpy(p, ls->p_data, p_msg->len);
- bta_jv_pm_conn_busy(ls->p_cb->p_pm_cb);
- if(SDP_WriteData (bta_jv_cb.sdp_for_jv, p_msg))
- {
- evt_data.len = ls->len;
- evt_data.status = BTA_JV_SUCCESS;
- }
- }
- }
- else
-#endif
- {
+ /* As we check this callback exists before the tBTA_JV_API_L2CAP_WRITE can be send through the
+ * API this check should not be needed.
+ * But the API is not designed to be used (safely at least) in a multi-threaded scheduler, hence
+ * if the peer device disconnects the l2cap link after the API is called, but before this
+ * message is handled, the ->p_cback will be cleared at this point. At first glanch this seems
+ * highly unlikely, but for all obex-profiles with two channels connected - e.g. MAP, this
+ * happens around 1 of 4 disconnects, as a disconnect on the server channel causes a disconnect
+ * to be send on the client (notification) channel, but at the peer typically disconnects both
+ * the OBEX disconnect request crosses the incoming l2cap disconnect.
+ * If p_cback is cleared, we simply discard the data.
+ * RISK: The caller must handle any cleanup based on another signal than BTA_JV_L2CAP_WRITE_EVT,
+ * which is typically not possible, as the pointer to the allocated buffer is stored
+ * in this message, and can therefore not be freed, hence we have a mem-leak-by-design.*/
+ if (ls->p_cb->p_cback != NULL) {
+ evt_data.status = BTA_JV_FAILURE;
+ evt_data.handle = ls->handle;
+ evt_data.req_id = ls->req_id;
+ evt_data.cong = ls->p_cb->cong;
+ evt_data.len = 0;
bta_jv_pm_conn_busy(ls->p_cb->p_pm_cb);
if (!evt_data.cong &&
BT_PASS == GAP_ConnWriteData(ls->handle, ls->p_data, ls->len, &evt_data.len))
{
evt_data.status = BTA_JV_SUCCESS;
}
+ ls->p_cb->p_cback(BTA_JV_L2CAP_WRITE_EVT, (tBTA_JV *)&evt_data, ls->user_data);
+ bta_jv_set_pm_conn_state(ls->p_cb->p_pm_cb, BTA_JV_CONN_IDLE);
+ } else {
+ /* As this pointer is checked in the API function, this occurs only when the channel is
+ * disconnected after the API function is called, but before the message is handled. */
+ APPL_TRACE_ERROR("%s() ls->p_cb->p_cback == NULL", __func__);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_write_fixed
+**
+** Description Write data to an L2CAP connection using Fixed channels
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_write_fixed(tBTA_JV_MSG *p_data)
+{
+ tBTA_JV_L2CAP_WRITE_FIXED evt_data;
+ tBTA_JV_API_L2CAP_WRITE_FIXED *ls = &(p_data->l2cap_write_fixed);
+ BT_HDR *msg = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + ls->len + L2CAP_MIN_OFFSET);
+ if (!msg)
+ {
+ APPL_TRACE_ERROR("%s() could not allocate msg buffer",__func__);
+ return;
}
- ls->p_cb->p_cback(BTA_JV_L2CAP_WRITE_EVT, (tBTA_JV *)&evt_data);
- bta_jv_set_pm_conn_state(ls->p_cb->p_pm_cb, BTA_JV_CONN_IDLE);
-#endif
+ evt_data.status = BTA_JV_FAILURE;
+ evt_data.channel = ls->channel;
+ memcpy(evt_data.addr, ls->addr, sizeof(evt_data.addr));
+ evt_data.req_id = ls->req_id;
+ evt_data.len = 0;
+
+
+ memcpy(((uint8_t*)(msg + 1)) + L2CAP_MIN_OFFSET, ls->p_data, ls->len);
+ msg->len = ls->len;
+ msg->offset = L2CAP_MIN_OFFSET;
+
+ L2CA_SendFixedChnlData(ls->channel, ls->addr, msg);
+
+ ls->p_cback(BTA_JV_L2CAP_WRITE_FIXED_EVT, (tBTA_JV *)&evt_data, ls->user_data);
}
/*******************************************************************************
** Returns void
**
*******************************************************************************/
-/*
-#define DATA_CO_CALLBACK_TYPE_INCOMING 1
-#define DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE 2
-#define DATA_CO_CALLBACK_TYPE_OUTGOING 3
-*/
static int bta_jv_port_data_co_cback(UINT16 port_handle, UINT8 *buf, UINT16 len, int type)
{
tBTA_JV_RFC_CB *p_cb = bta_jv_rfc_port_to_cb(port_handle);
tBTA_JV_PCB *p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
- APPL_TRACE_DEBUG("bta_jv_port_data_co_cback, p_cb:%p, p_pcb:%p, len:%d",
- p_cb, p_pcb, len);
+ int ret = 0;
+ APPL_TRACE_DEBUG("%s, p_cb:%p, p_pcb:%p, len:%d, type:%d", __func__, p_cb, p_pcb, len, type);
if (p_pcb != NULL)
{
switch(type)
{
case DATA_CO_CALLBACK_TYPE_INCOMING:
- return bta_co_rfc_data_incoming(p_pcb->user_data, (BT_HDR*)buf);
+ bta_jv_pm_conn_busy(p_pcb->p_pm_cb);
+ ret = bta_co_rfc_data_incoming(p_pcb->user_data, (BT_HDR*)buf);
+ bta_jv_pm_conn_idle(p_pcb->p_pm_cb);
+ return ret;
case DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE:
return bta_co_rfc_data_outgoing_size(p_pcb->user_data, (int*)buf);
case DATA_CO_CALLBACK_TYPE_OUTGOING:
tBTA_JV evt_data;
APPL_TRACE_DEBUG( "bta_jv_port_event_cl_cback:%d", port_handle);
- if(NULL == p_cb || NULL == p_cb->p_cback)
+ if (NULL == p_cb || NULL == p_cb->p_cback)
return;
APPL_TRACE_DEBUG( "bta_jv_port_event_cl_cback code=x%x port_handle:%d handle:%d",
/*******************************************************************************
**
+** Function bta_jv_get_num_rfc_listen
+**
+** Description when a RFCOMM connection goes down, make sure that there's only
+** one port stays listening on this scn.
+**
+** Returns
+**
+*******************************************************************************/
+static UINT8 bta_jv_get_num_rfc_listen(tBTA_JV_RFC_CB *p_cb)
+{
+ UINT8 listen=1;
+
+ if (p_cb->max_sess > 1)
+ {
+ listen = 0;
+ for (UINT8 i=0; i<p_cb->max_sess; i++)
+ {
+ if (p_cb->rfc_hdl[i] != 0)
+ {
+ const tBTA_JV_PCB *p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[i] - 1];
+ if (BTA_JV_ST_SR_LISTEN == p_pcb->state)
+ {
+ listen++;
+ }
+ }
+ }
+ }
+ return listen;
+}
+
+/*******************************************************************************
+**
** Function bta_jv_port_mgmt_sr_cback
**
** Description callback for port mamangement function of rfcomm
tBTA_JV evt_data;
BD_ADDR rem_bda;
UINT16 lcid;
- UINT8 num;
- UINT32 si;
APPL_TRACE_DEBUG("bta_jv_port_mgmt_sr_cback, code:%d, port_handle:%d", code, port_handle);
- if(NULL == p_cb || NULL == p_cb->p_cback)
+ if (NULL == p_cb || NULL == p_cb->p_cback)
{
APPL_TRACE_ERROR("bta_jv_port_mgmt_sr_cback, p_cb:%p, p_cb->p_cback%p",
p_cb, p_cb ? p_cb->p_cback : NULL);
tBTA_JV_RFCOMM_CBACK *p_cback = p_cb->p_cback;
APPL_TRACE_DEBUG("PORT_CLOSED before BTA_JV_RFCOMM_CLOSE_EVT: curr_sess:%d, max_sess:%d",
p_cb->curr_sess, p_cb->max_sess);
- if(BTA_JV_ST_SR_CLOSING == p_pcb->state)
+ if (BTA_JV_ST_SR_CLOSING == p_pcb->state)
{
evt_data.rfc_close.async = FALSE;
evt_data.rfc_close.status = BTA_JV_SUCCESS;
tBTA_JV_RFC_CB *p_cb = bta_jv_rfc_port_to_cb(port_handle);
tBTA_JV evt_data;
- if(NULL == p_cb || NULL == p_cb->p_cback)
+ if (NULL == p_cb || NULL == p_cb->p_cback)
return;
APPL_TRACE_DEBUG( "bta_jv_port_event_sr_cback code=x%x port_handle:%d handle:%d",
if (p_pcb->state == BTA_JV_ST_SR_LISTEN)
{
listen++;
- if(p_pcb_open == p_pcb)
+ if (p_pcb_open == p_pcb)
{
APPL_TRACE_DEBUG("bta_jv_add_rfc_port, port_handle:%d, change the listen port to open state",
p_pcb->port_handle);
port_state.fc_type = (PORT_FC_CTS_ON_INPUT | PORT_FC_CTS_ON_OUTPUT);
-/* coverity[uninit_use_in_call]
-FALSE-POSITIVE: port_state is initialized at PORT_GetState() */
PORT_SetState(p_pcb->port_handle, &port_state);
p_pcb->handle = BTA_JV_RFC_H_S_TO_HDL(p_cb->handle, si);
APPL_TRACE_DEBUG("bta_jv_add_rfc_port: p_pcb->handle:0x%x, curr_sess:%d",
p_cb = bta_jv_alloc_rfc_cb(handle, &p_pcb);
- if(!p_cb)
+ if (!p_cb)
{
APPL_TRACE_ERROR("bta_jv_rfcomm_start_server, run out of rfc control block");
break;
evt_data.status = BTA_JV_SUCCESS;
evt_data.handle = p_cb->handle;
evt_data.sec_id = sec_id;
- evt_data.use_co = TRUE; //FALSE;
+ evt_data.use_co = TRUE;
PORT_ClearKeepHandleFlag(handle);
PORT_SetEventCallback(handle, bta_jv_port_event_sr_cback);
port_state.fc_type = (PORT_FC_CTS_ON_INPUT | PORT_FC_CTS_ON_OUTPUT);
-/* coverity[uninit_use_in_call]
-FALSE-POSITIVE: port_state is initialized at PORT_GetState() */
PORT_SetState(handle, &port_state);
} while (0);
+
rs->p_cback(BTA_JV_RFCOMM_START_EVT, (tBTA_JV *)&evt_data, rs->user_data);
- if(evt_data.status == BTA_JV_SUCCESS)
+ if (evt_data.status == BTA_JV_SUCCESS)
{
PORT_SetDataCOCallback (handle, bta_jv_port_data_co_cback);
}
else
{
- if(sec_id)
+ if (sec_id)
bta_jv_free_sec_id(&sec_id);
- if(handle)
+ if (handle)
RFCOMM_RemoveConnection(handle);
}
}
tBTA_JV_RFC_CB *p_cb = NULL;
tBTA_JV_PCB *p_pcb = NULL;
APPL_TRACE_DEBUG("bta_jv_rfcomm_stop_server");
- if(!ls->handle)
+ if (!ls->handle)
{
APPL_TRACE_ERROR("bta_jv_rfcomm_stop_server, jv handle is null");
return;
}
void* user_data = ls->user_data;
- if(!find_rfc_pcb(user_data, &p_cb, &p_pcb))
+ if (!find_rfc_pcb(user_data, &p_cb, &p_pcb))
return;
APPL_TRACE_DEBUG("bta_jv_rfcomm_stop_server: p_pcb:%p, p_pcb->port_handle:%d",
p_pcb, p_pcb->port_handle);
break;
}
}
+/**********************************************************************************************/
+
+
+static struct fc_channel *fcchan_get(uint16_t chan, char create)
+{
+ struct fc_channel *t = fc_channels;
+ static tL2CAP_FIXED_CHNL_REG fcr = {
+ .pL2CA_FixedConn_Cb = fcchan_conn_chng_cbk,
+ .pL2CA_FixedData_Cb = fcchan_data_cbk,
+ .default_idle_tout = 0xffff,
+ .fixed_chnl_opts = {
+ .mode = L2CAP_FCR_BASIC_MODE,
+ .max_transmit = 0xFF,
+ .rtrans_tout = 2000,
+ .mon_tout = 12000,
+ .mps = 670,
+ .tx_win_sz = 1,
+ },
+ };
+
+ while (t && t->chan != chan)
+ t = t->next;
+
+ if (t)
+ return t;
+ else if (!create)
+ return NULL; /* we cannot alloc a struct if not asked to */
+
+ t = calloc(sizeof(*t), 1);
+ if (!t)
+ return NULL;
+
+ t->chan = chan;
+
+ if (!L2CA_RegisterFixedChannel(chan, &fcr)) {
+ free(t);
+ return NULL;
+ }
+
+ //link it in
+ t->next = fc_channels;
+ fc_channels = t;
+
+ return t;
+}
+
+/* pass NULL to find servers */
+static struct fc_client *fcclient_find_by_addr(struct fc_client *start, BD_ADDR addr)
+{
+ struct fc_client *t = start;
+
+ while (t) {
+
+ /* match client if have addr */
+ if (addr && !memcmp(addr, &t->remote_addr, sizeof(t->remote_addr)))
+ break;
+
+ /* match server if do not have addr */
+ if (!addr && t->server)
+ break;
+
+ t = t->next_all_list;
+ }
+
+ return t;
+}
+
+static struct fc_client *fcclient_find_by_id(uint32_t id)
+{
+ struct fc_client *t = fc_clients;
+
+ while (t && t->id != id)
+ t = t->next_all_list;
+
+ return t;
+}
+
+static struct fc_client *fcclient_alloc(uint16_t chan, char server, const uint8_t *sec_id_to_use)
+{
+ struct fc_channel *fc = fcchan_get(chan, TRUE);
+ struct fc_client *t;
+ uint8_t sec_id;
+
+ if (!fc)
+ return NULL;
+
+ if (fc->has_server && server)
+ return NULL; /* no way to have multiple servers on same channel */
+
+ if (sec_id_to_use)
+ sec_id = *sec_id_to_use;
+ else
+ sec_id = bta_jv_alloc_sec_id();
+
+ t = calloc(sizeof(*t), 1);
+ if (t) {
+ //allocate it a unique ID
+ do {
+ t->id = ++fc_next_id;
+ } while (!t->id || fcclient_find_by_id(t->id));
+
+ //populate some params
+ t->chan = chan;
+ t->server = server;
+
+ //get a security id
+ t->sec_id = sec_id;
+
+ //link it in to global list
+ t->next_all_list = fc_clients;
+ fc_clients = t;
+
+ //link it in to channel list
+ t->next_chan_list = fc->clients;
+ fc->clients = t;
+
+ //update channel if needed
+ if (server)
+ fc->has_server = TRUE;
+ } else if (!sec_id_to_use)
+ bta_jv_free_sec_id(&sec_id);
+
+ return t;
+}
+
+static void fcclient_free(struct fc_client *fc)
+{
+ struct fc_client *t = fc_clients;
+ struct fc_channel *tc = fcchan_get(fc->chan, FALSE);
+
+ //remove from global list
+ while (t && t->next_all_list != fc)
+ t = t->next_all_list;
+
+ if (!t && fc != fc_clients)
+ return; /* prevent double-free */
+
+ if (t)
+ t->next_all_list = fc->next_all_list;
+ else
+ fc_clients = fc->next_all_list;
+
+ //remove from channel list
+ if (tc) {
+ t = tc->clients;
+
+ while (t && t->next_chan_list != fc)
+ t = t->next_chan_list;
+
+ if (t)
+ t->next_chan_list = fc->next_chan_list;
+ else
+ tc->clients = fc->next_chan_list;
+
+ //if was server then channel no longer has a server
+ if (fc->server)
+ tc->has_server = FALSE;
+ }
+
+ //free security id
+ bta_jv_free_sec_id(&fc->sec_id);
+
+ free(fc);
+}
+
+static void fcchan_conn_chng_cbk(UINT16 chan, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason, tBT_TRANSPORT transport)
+{
+ tBTA_JV init_evt;
+ tBTA_JV open_evt;
+ struct fc_channel *tc;
+ struct fc_client *t = NULL, *new_conn;
+ tBTA_JV_L2CAP_CBACK *p_cback = NULL;
+ char call_init = FALSE;
+ void *user_data = NULL;
+
+
+ tc = fcchan_get(chan, FALSE);
+ if (tc) {
+ t = fcclient_find_by_addr(tc->clients, bd_addr); // try to find an open socked for that addr
+ if (t) {
+ p_cback = t->p_cback;
+ user_data = t->user_data;
+ } else {
+ t = fcclient_find_by_addr(tc->clients, NULL); // try to find a listening socked for that channel
+ if (t) {
+ //found: create a normal connection socket and assign the connection to it
+ new_conn = fcclient_alloc(chan, FALSE, &t->sec_id);
+ if (new_conn){
+
+ memcpy(&new_conn->remote_addr, bd_addr, sizeof(new_conn->remote_addr));
+ new_conn->p_cback = NULL; //for now
+ new_conn->init_called = TRUE; /*nop need to do it again */
+
+ p_cback = t->p_cback;
+ user_data = t->user_data;
+
+ t = new_conn;
+ }
+ } else {
+ //drop it
+ return;
+ }
+ }
+ }
+
+ if (t) {
+
+ if (!t->init_called) {
+
+ call_init = TRUE;
+ t->init_called = TRUE;
+
+ init_evt.l2c_cl_init.handle = t->id;
+ init_evt.l2c_cl_init.status = BTA_JV_SUCCESS;
+ init_evt.l2c_cl_init.sec_id = t->sec_id;
+ }
+
+ open_evt.l2c_open.handle = t->id;
+ open_evt.l2c_open.tx_mtu = 23; /* 23, why not ?*/
+ memcpy(&open_evt.l2c_le_open.rem_bda, &t->remote_addr, sizeof(open_evt.l2c_le_open.rem_bda));
+ open_evt.l2c_le_open.p_p_cback = (void**)&t->p_cback;
+ open_evt.l2c_le_open.p_user_data = &t->user_data;
+ open_evt.l2c_le_open.status = BTA_JV_SUCCESS;
+
+ if (connected) {
+ open_evt.l2c_open.status = BTA_JV_SUCCESS;
+ } else {
+ fcclient_free(t);
+ open_evt.l2c_open.status = BTA_JV_FAILURE;
+ }
+ }
+
+ if (call_init)
+ p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &init_evt, user_data);
+
+ //call this with lock taken so socket does not disappear from under us */
+ if (p_cback) {
+ p_cback(BTA_JV_L2CAP_OPEN_EVT, &open_evt, user_data);
+ if (!t->p_cback) /* no callback set, means they do not want this one... */
+ fcclient_free(t);
+ }
+}
+
+static void fcchan_data_cbk(UINT16 chan, BD_ADDR bd_addr, BT_HDR *p_buf)
+{
+ tBTA_JV evt_data;
+ tBTA_JV evt_open;
+ struct fc_channel *tc;
+ struct fc_client *t = NULL;
+ tBTA_JV_L2CAP_CBACK *sock_cback = NULL;
+ void *sock_user_data;
+
+ tc = fcchan_get(chan, FALSE);
+ if (tc) {
+ t = fcclient_find_by_addr(tc->clients, bd_addr); // try to find an open socked for that addr and channel
+ if (!t) {
+ //no socket -> drop it
+ return;
+ }
+ }
+
+ sock_cback = t->p_cback;
+ sock_user_data = t->user_data;
+ evt_data.le_data_ind.handle = t->id;
+ evt_data.le_data_ind.p_buf = p_buf;
+
+ if (sock_cback)
+ sock_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data, sock_user_data);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_connect_le
+**
+** Description makes an le l2cap client connection
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_connect_le(tBTA_JV_MSG *p_data)
+{
+ tBTA_JV_API_L2CAP_CONNECT *cc = &(p_data->l2cap_connect);
+ tBTA_JV evt;
+ uint32_t id;
+ char call_init_f = TRUE;
+ struct fc_client *t;
+
+ evt.l2c_cl_init.handle = GAP_INVALID_HANDLE;
+ evt.l2c_cl_init.status = BTA_JV_FAILURE;
+
+ t = fcclient_alloc(cc->remote_chan, FALSE, NULL);
+ if (!t) {
+ cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, cc->user_data);
+ return;
+ }
+
+ t->p_cback = cc->p_cback;
+ t->user_data = cc->user_data;
+ memcpy(&t->remote_addr, &cc->peer_bd_addr, sizeof(t->remote_addr));
+ id = t->id;
+ t->init_called = FALSE;
+
+ if (L2CA_ConnectFixedChnl(t->chan, t->remote_addr)) {
+
+ evt.l2c_cl_init.status = BTA_JV_SUCCESS;
+ evt.l2c_cl_init.handle = id;
+ }
+
+ //it could have been deleted/moved from under us, so re-find it */
+ t = fcclient_find_by_id(id);
+ if (t) {
+ if (evt.l2c_cl_init.status == BTA_JV_SUCCESS)
+ call_init_f = !t->init_called;
+ else
+ fcclient_free(t);
+ }
+ if (call_init_f)
+ cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, cc->user_data);
+ t->init_called = TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_stop_server_le
+**
+** Description stops an LE L2CAP server
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_stop_server_le(tBTA_JV_MSG *p_data)
+{
+ tBTA_JV evt;
+ tBTA_JV_API_L2CAP_SERVER *ls = &(p_data->l2cap_server);
+ tBTA_JV_L2CAP_CBACK *p_cback = NULL;
+ struct fc_channel *fcchan;
+ struct fc_client *fcclient;
+ void *user_data;
+
+ evt.l2c_close.status = BTA_JV_FAILURE;
+ evt.l2c_close.async = FALSE;
+ evt.l2c_close.handle = GAP_INVALID_HANDLE;
+
+ fcchan = fcchan_get(ls->local_chan, FALSE);
+ if (fcchan) {
+ while((fcclient = fcchan->clients)) {
+ p_cback = fcclient->p_cback;
+ user_data = fcclient->user_data;
+
+ evt.l2c_close.handle = fcclient->id;
+ evt.l2c_close.status = BTA_JV_SUCCESS;
+ evt.l2c_close.async = FALSE;
+
+ fcclient_free(fcclient);
+
+ if (p_cback)
+ p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt, user_data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_start_server_le
+**
+** Description starts an LE L2CAP server
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_start_server_le(tBTA_JV_MSG *p_data)
+{
+ tBTA_JV_API_L2CAP_SERVER *ss = &(p_data->l2cap_server);
+ tBTA_JV_L2CAP_START evt_data;
+ struct fc_client *t;
+ uint16_t handle;
+
+ evt_data.handle = GAP_INVALID_HANDLE;
+ evt_data.status = BTA_JV_FAILURE;
+
+
+ t = fcclient_alloc(ss->local_chan, TRUE, NULL);
+ if (!t)
+ goto out;
+
+ t->p_cback = ss->p_cback;
+ t->user_data = ss->user_data;
+
+ //if we got here, we're registered...
+ evt_data.status = BTA_JV_SUCCESS;
+ evt_data.handle = t->id;
+ evt_data.sec_id = t->sec_id;
+
+out:
+ ss->p_cback(BTA_JV_L2CAP_START_EVT, (tBTA_JV *)&evt_data, ss->user_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_close_fixed
+**
+** Description close a fixed channel connection. calls no callbacks. idempotent
+**
+** Returns void
+**
+*******************************************************************************/
+extern void bta_jv_l2cap_close_fixed (tBTA_JV_MSG *p_data)
+{
+ tBTA_JV_API_L2CAP_CLOSE *cc = &(p_data->l2cap_close);
+ struct fc_client *t;
+
+ t = fcclient_find_by_id(cc->handle);
+ if (t)
+ fcclient_free(t);
+}