summaryrefslogtreecommitdiffstats
path: root/bta/jv
diff options
context:
space:
mode:
authorVinit Deshpande <vinitd@google.com>2015-04-14 16:00:10 -0700
committerVinit Deshpande <vinitd@google.com>2015-04-14 16:00:10 -0700
commit2cd086a11a972f2e437dd521a121ed76ea79a15a (patch)
tree314d0f12de95616291aed9ab0661da4de4dd41c9 /bta/jv
parentb246a1a750c5a337faaa6033b39e78c8bdd4c2fb (diff)
parente07ad1085d92ea5d7ce488198da9b0e4f8139a6a (diff)
downloadandroid_system_bt-2cd086a11a972f2e437dd521a121ed76ea79a15a.tar.gz
android_system_bt-2cd086a11a972f2e437dd521a121ed76ea79a15a.tar.bz2
android_system_bt-2cd086a11a972f2e437dd521a121ed76ea79a15a.zip
am f29a2fb..e07ad10 from mirror-m-wireless-internal-release
e07ad10 merge in m-wireless-internal-release history after reset to d232721ae5e5b6949a5249f0d116408b8a3c5f1d d232721 L2CAP socket - fix merge errors 899b771 BR/EDR secure connections support 7fb0da6 Support numeric comparison in SMP aa351f2 merge in m-wireless-internal-release history after reset to 399e89150b3df87172bdf92d54712b379324b149 399e891 Fix for AVRCP CTRL stops sending pass through command daddea9 Free Avrcp Controller callbacks on Cleanup 764babe Protect reset of out stream with mutex 444a8da LE Privacy 1.2 and LE secure connections 8372aa5 L2CAP and SDP Search API for BT profiles (2/2) fd422a7 Update Service Availability. 2a0652a merge in m-wireless-internal-release history after reset to 0b47e0a35c16f5b7d77c30ec1c095ed92ff4fd74 78d0f4c merge in m-wireless-internal-release history after reset to m-wireless-internal-dev 0b47e0a Avoid duplicate disconnection callbacks for fixed channel connections 5646973 Add a section on assertions to the style guide. d768767 Merge "Avoid null-pointer dereference in l2c_release_lcb()" into m-wireless-dev ef92b53 Avoid null-pointer dereference in l2c_release_lcb() 4bf68bf merge in m-wireless-internal-release history after reset to f538707fe64c62b1dbb8e4210e4a1bfa0bab2b56 de6ac86 Add a 'Bluedroid conventions' section to the style guide. 1b80439 Add a section to the style guide on variable declarations. 485f19e merge in m-wireless-internal-release history after reset to 4540f59bc447dc2b7b31a3e974b74a60b2417e7d bef8940 merge in m-wireless-internal-release history after reset to 841c9103cad1898ceca87b734acd4d4537f9f452 ab4c38c merge in m-wireless-internal-release history after reset to a7e698f5a9e062f62e21bc435643975c30bab846 2807a74 merge in m-wireless-internal-release history after reset to a7e698f5a9e062f62e21bc435643975c30bab846 99dbe9a merge in m-wireless-internal-release history after reset to 78c0b060f29b7b7014adddb2f98bf6ae9755c488 f7f8399 merge in m-wireless-internal-release history after reset to a5371c238b4e874d8313ac56a23451e7345ff541 3aa60d7 Make A2DP audio HAL a shared library again 3256a31 Move unused include file out of hci_audio.h b866b69 Add option for schedule_next_instance to force rescheduling 4ae5e3e Ensure alarms are called back when they expire in the past a7bd03e Rewrite alarms to use a single posix timer instance 88e7b15 Resolved hardware error observed during SCO Connection setup Change-Id: Ib9a0a2ffca1d4811a9a9e56674bf43275d8b2205
Diffstat (limited to 'bta/jv')
-rw-r--r--bta/jv/bta_jv_act.c1255
-rw-r--r--bta/jv/bta_jv_api.c604
-rw-r--r--bta/jv/bta_jv_int.h161
-rw-r--r--bta/jv/bta_jv_main.c13
4 files changed, 1996 insertions, 37 deletions
diff --git a/bta/jv/bta_jv_act.c b/bta/jv/bta_jv_act.c
index c9299e87e..a1826725f 100644
--- a/bta/jv/bta_jv_act.c
+++ b/bta/jv/bta_jv_act.c
@@ -23,6 +23,7 @@
******************************************************************************/
#include <hardware/bluetooth.h>
#include <arpa/inet.h>
+#include <pthread.h>
#include "bt_types.h"
#include "gki.h"
@@ -42,6 +43,57 @@
#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);
+}
+
+
+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_legacy(bt_uuid_t *p_uuid, char *str);
@@ -330,16 +382,43 @@ static tBTA_JV_STATUS bta_jv_free_rfc_cb(tBTA_JV_RFC_CB *p_cb, tBTA_JV_PCB *p_pc
}
/*******************************************************************************
- **
- ** 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_free_l2c_cb
+**
+** Description free the given L2CAP control block
+**
+** Returns
+**
+*******************************************************************************/
+tBTA_JV_STATUS bta_jv_free_l2c_cb(tBTA_JV_L2C_CB *p_cb)
+{
+ tBTA_JV_STATUS status = BTA_JV_SUCCESS;
+
+ if(BTA_JV_ST_NONE != p_cb->state)
+ {
+ 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;
+}
+
+/*******************************************************************************
+**
+**
+** 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! */
@@ -381,10 +460,10 @@ static tBTA_JV_STATUS bta_jv_free_set_pm_profile_cb(UINT32 jv_handle)
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]);
@@ -410,14 +489,24 @@ static tBTA_JV_STATUS bta_jv_free_set_pm_profile_cb(UINT32 jv_handle)
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;
}
}
}
-
+ else
+ {
+ if (jv_handle < BTA_JV_MAX_L2C_CONN)
+ {
+ 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("%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;
+ }
+ }
if (p_cb)
{
*p_cb = NULL;
@@ -466,6 +555,23 @@ static tBTA_JV_PM_CB *bta_jv_alloc_set_pm_profile_cb(UINT32 jv_handle, tBTA_JV_P
}
}
}
+ else
+ {
+ /* use jv handle for l2cap bd address retrieval */
+ for (j = 0; j < BTA_JV_MAX_L2C_CONN; j++)
+ {
+ if (jv_handle == bta_jv_cb.l2c_cb[j].handle)
+ {
+ pp_cb = &bta_jv_cb.l2c_cb[j].p_pm_cb;
+ UINT8 *p_bd_addr = GAP_ConnGetRemoteAddr((UINT16)jv_handle);
+ if (NULL != p_bd_addr)
+ bdcpy(peer_bd_addr, p_bd_addr);
+ else
+ i = BTA_JV_PM_MAX_NUM;
+ break;
+ }
+ }
+ }
APPL_TRACE_API("bta_jv_alloc_set_pm_profile_cb(handle 0x%2x, app_id %d): "
"idx: %d, (BTA_JV_PM_MAX_NUM: %d), pp_cb: 0x%x", jv_handle, app_id,
i, BTA_JV_PM_MAX_NUM, pp_cb);
@@ -489,6 +595,72 @@ static tBTA_JV_PM_CB *bta_jv_alloc_set_pm_profile_cb(UINT32 jv_handle, tBTA_JV_P
/*******************************************************************************
**
+** Function bta_jv_check_psm
+**
+** Description for now use only the legal PSM per JSR82 spec
+**
+** Returns TRUE, if allowed
+**
+*******************************************************************************/
+BOOLEAN bta_jv_check_psm(UINT16 psm)
+{
+ BOOLEAN ret = FALSE;
+
+ if (L2C_IS_VALID_PSM(psm))
+ {
+ if (psm < 0x1001)
+ {
+ /* see if this is defined by spec */
+ switch (psm)
+ {
+ case SDP_PSM: /* 1 */
+ case BT_PSM_RFCOMM: /* 3 */
+ /* do not allow java app to use these 2 PSMs */
+ break;
+
+ case TCS_PSM_INTERCOM: /* 5 */
+ case TCS_PSM_CORDLESS: /* 7 */
+ if( FALSE == bta_sys_is_register(BTA_ID_CT) &&
+ FALSE == bta_sys_is_register(BTA_ID_CG) )
+ ret = TRUE;
+ break;
+
+ case BT_PSM_BNEP: /* F */
+ if(FALSE == bta_sys_is_register(BTA_ID_PAN))
+ ret = TRUE;
+ break;
+
+ case HID_PSM_CONTROL: /* 0x11 */
+ case HID_PSM_INTERRUPT: /* 0x13 */
+ //FIX: allow HID Device and HID Host to coexist
+ if( FALSE == bta_sys_is_register(BTA_ID_HD) ||
+ FALSE == bta_sys_is_register(BTA_ID_HH) )
+ ret = TRUE;
+ break;
+
+ case AVCT_PSM: /* 0x17 */
+ case AVDT_PSM: /* 0x19 */
+ if ((FALSE == bta_sys_is_register(BTA_ID_AV)) &&
+ (FALSE == bta_sys_is_register(BTA_ID_AVK)))
+ ret = TRUE;
+ break;
+
+ default:
+ ret = TRUE;
+ break;
+ }
+ }
+ else
+ {
+ ret = TRUE;
+ }
+ }
+ return ret;
+
+}
+
+/*******************************************************************************
+**
** Function bta_jv_enable
**
** Description Initialises the JAVA I/F
@@ -501,6 +673,7 @@ void bta_jv_enable(tBTA_JV_MSG *p_data)
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));
}
/*******************************************************************************
@@ -517,9 +690,135 @@ void bta_jv_disable (tBTA_JV_MSG *p_data)
{
UNUSED(p_data);
- APPL_TRACE_ERROR("bta_jv_disable not used");
+ APPL_TRACE_ERROR("%s",__func__);
+}
+
+
+/**
+ * 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;
+}
+
+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?
+ }
+ }
+ 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);
+ }
}
+/*******************************************************************************
+**
+** Function bta_jv_get_channel_id
+**
+** Description Obtain a free SCN (Server Channel Number)
+** (RFCOMM channel or L2CAP PSM)
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_get_channel_id(tBTA_JV_MSG *p_data)
+{
+ UINT16 psm = 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;
+ }
+
+ 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);
+}
+
+/*******************************************************************************
+**
+** Function bta_jv_free_scn
+**
+** Description free a SCN
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_free_scn(tBTA_JV_MSG *p_data)
+{
+ UINT16 scn = p_data->free_channel.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)
{
static uint8_t bt_base_uuid[] =
@@ -587,7 +886,7 @@ static void bta_jv_start_discovery_cback(UINT16 result, void * user_data)
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))
+ if (p_sdp_rec && SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe))
{
dcomp.scn = (UINT8) pe.params[0];
status = BTA_JV_SUCCESS;
@@ -690,6 +989,450 @@ void bta_jv_delete_record(tBTA_JV_MSG *p_data)
/*******************************************************************************
**
+** Function bta_jv_l2cap_client_cback
+**
+** Description handles the l2cap client events
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_jv_l2cap_client_cback(UINT16 gap_handle, UINT16 event)
+{
+ tBTA_JV_L2C_CB *p_cb = &bta_jv_cb.l2c_cb[gap_handle];
+ tBTA_JV evt_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_CL_OPEN;
+ p_cb->p_cback(BTA_JV_L2CAP_OPEN_EVT, &evt_data, p_cb->user_data);
+ break;
+
+ case GAP_EVT_CONN_CLOSED:
+ p_cb->state = BTA_JV_ST_NONE;
+ bta_jv_free_sec_id(&p_cb->sec_id);
+ 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;
+
+ 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;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_connect
+**
+** Description makes an l2cap client connection
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_connect(tBTA_JV_MSG *p_data)
+{
+ 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 (bta_jv_check_psm(cc->remote_psm)) /* allowed */
+ {
+ 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;
+ }
+ }
+ }
+
+ if (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;
+ }
+ else
+ {
+ bta_jv_free_sec_id(&sec_id);
+ }
+
+ evt_data.handle = handle;
+ cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, (tBTA_JV *)&evt_data, cc->user_data);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_close
+**
+** Description Close an L2CAP client connection
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_close(tBTA_JV_MSG *p_data)
+{
+ 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;
+
+ 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;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_start_server
+**
+** Description starts an L2CAP server
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_start_server(tBTA_JV_MSG *p_data)
+{
+ 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)
+ {
+ cfg.mtu_present = TRUE;
+ cfg.mtu = ls->rx_mtu;
+ }
+ else
+ {
+ cfg.mtu_present = FALSE;
+ cfg.mtu = 0;
+ }
+
+ /* TODO DM role manager
+ L2CA_SetDesireRole(ls->role);
+ */
+
+ 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, 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
+ {
+ 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, ls->user_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_stop_server
+**
+** Description stops an L2CAP server
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_stop_server(tBTA_JV_MSG *p_data)
+{
+ 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;
+ 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)
+ {
+ 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, user_data);
+ break;
+ }
+ }
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_read
+**
+** Description Read data from an L2CAP connection
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_read(tBTA_JV_MSG *p_data)
+{
+ tBTA_JV_L2CAP_READ evt_data;
+ tBTA_JV_API_L2CAP_READ *rc = &(p_data->l2cap_read);
+
+ evt_data.status = BTA_JV_FAILURE;
+ evt_data.handle = rc->handle;
+ evt_data.req_id = rc->req_id;
+ evt_data.p_data = rc->p_data;
+ evt_data.len = 0;
+
+ 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, rc->user_data);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_jv_l2cap_write
+**
+** Description Write data to an L2CAP connection
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_jv_l2cap_write(tBTA_JV_MSG *p_data)
+{
+ tBTA_JV_L2CAP_WRITE evt_data;
+ tBTA_JV_API_L2CAP_WRITE *ls = &(p_data->l2cap_write);
+
+ /* 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;
+ }
+ 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);
+}
+
+/*******************************************************************************
+**
** Function bta_jv_port_data_co_cback
**
** Description port data callback function of rfcomm
@@ -703,8 +1446,7 @@ static int bta_jv_port_data_co_cback(UINT16 port_handle, UINT8 *buf, UINT16 len,
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);
int ret = 0;
- APPL_TRACE_DEBUG("bta_jv_port_data_co_cback, p_cb:%p, p_pcb:%p, len:%d, type:%d",
- p_cb, p_pcb, len, type);
+ 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)
@@ -797,7 +1539,7 @@ static void bta_jv_port_event_cl_cback(UINT32 code, UINT16 port_handle)
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",
@@ -961,6 +1703,38 @@ void bta_jv_rfcomm_close(tBTA_JV_MSG *p_data)
/*******************************************************************************
**
+** 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
@@ -977,7 +1751,7 @@ static void bta_jv_port_mgmt_sr_cback(UINT32 code, UINT16 port_handle)
BD_ADDR rem_bda;
UINT16 lcid;
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);
@@ -1016,7 +1790,7 @@ static void bta_jv_port_mgmt_sr_cback(UINT32 code, UINT16 port_handle)
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;
@@ -1045,7 +1819,7 @@ static void bta_jv_port_event_sr_cback(UINT32 code, UINT16 port_handle)
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",
@@ -1099,7 +1873,7 @@ static tBTA_JV_PCB * bta_jv_add_rfc_port(tBTA_JV_RFC_CB *p_cb, tBTA_JV_PCB *p_pc
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);
@@ -1206,7 +1980,7 @@ void bta_jv_rfcomm_start_server(tBTA_JV_MSG *p_data)
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;
@@ -1234,15 +2008,15 @@ void bta_jv_rfcomm_start_server(tBTA_JV_MSG *p_data)
} 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);
}
}
@@ -1263,13 +2037,13 @@ void bta_jv_rfcomm_stop_server(tBTA_JV_MSG *p_data)
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);
@@ -1533,3 +2307,420 @@ static void bta_jv_pm_state_change(tBTA_JV_PM_CB *p_cb, const tBTA_JV_CONN_STATE
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);
+}
diff --git a/bta/jv/bta_jv_api.c b/bta/jv/bta_jv_api.c
index a242f455b..41506cdee 100644
--- a/bta/jv/bta_jv_api.c
+++ b/bta/jv/bta_jv_api.c
@@ -31,6 +31,7 @@
#include "port_api.h"
#include "sdp_api.h"
#include "utl.h"
+#include "gap_api.h"
/*****************************************************************************
** Constants
@@ -150,6 +151,78 @@ BOOLEAN BTA_JvIsEncrypted(BD_ADDR bd_addr)
}
return is_encrypted;
}
+/*******************************************************************************
+**
+** Function BTA_JvGetChannelId
+**
+** Description This function reserves a SCN (server channel number) for
+** applications running over RFCOMM, L2CAP of L2CAP_LE.
+** It is primarily called by server profiles/applications to
+** register their SCN into the SDP database. The SCN is reported
+** by the tBTA_JV_DM_CBACK callback with a BTA_JV_GET_SCN_EVT
+** for RFCOMM channels and BTA_JV_GET_PSM_EVT for L2CAP and LE.
+** If the SCN/PSM reported is 0, that means all resources are
+** exhausted.
+** Parameters
+** conn_type one of BTA_JV_CONN_TYPE_
+** user_data Any uservalue - will be returned in the resulting event.
+** channel Only used for RFCOMM - to try to allocate a specific RFCOMM
+** channel.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvGetChannelId(int conn_type, void* user_data, INT32 channel)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_ALLOC_CHANNEL *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+ if ((p_msg = (tBTA_JV_API_ALLOC_CHANNEL *)GKI_getbuf(sizeof(tBTA_JV_API_ALLOC_CHANNEL))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_GET_CHANNEL_EVT;
+ p_msg->type = conn_type;
+ p_msg->channel = channel;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvFreeChannel
+**
+** Description This function frees a server channel number that was used
+** by an application running over RFCOMM.
+** Parameters
+** channel The channel to free
+** conn_type one of BTA_JV_CONN_TYPE_
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvFreeChannel(UINT16 channel, int conn_type)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_FREE_CHANNEL *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+ if ((p_msg = (tBTA_JV_API_FREE_CHANNEL *)GKI_getbuf(sizeof(tBTA_JV_API_FREE_CHANNEL))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_FREE_SCN_EVT;
+ p_msg->scn = channel;
+ p_msg->type = conn_type;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
/*******************************************************************************
**
@@ -243,6 +316,537 @@ tBTA_JV_STATUS BTA_JvDeleteRecord(UINT32 handle)
/*******************************************************************************
**
+** Function BTA_JvL2capConnectLE
+**
+** Description Initiate an LE connection as a L2CAP client to the given BD
+** Address.
+** When the connection is initiated or failed to initiate,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+** When the connection is established or failed,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capConnectLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO *ertm_info, UINT16 remote_chan,
+ UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+ BD_ADDR peer_bd_addr, tBTA_JV_L2CAP_CBACK *p_cback, void *user_data)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_CONNECT *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if (p_cback &&
+ (p_msg =
+ (tBTA_JV_API_L2CAP_CONNECT *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_CONNECT))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_CONNECT_LE_EVT;
+ p_msg->sec_mask = sec_mask;
+ p_msg->role = role;
+ p_msg->remote_chan = remote_chan;
+ p_msg->rx_mtu = rx_mtu;
+ if(cfg != NULL) {
+ p_msg->has_cfg = TRUE;
+ p_msg->cfg = *cfg;
+ } else {
+ p_msg->has_cfg = FALSE;
+ }
+ if(ertm_info != NULL) {
+ p_msg->has_ertm_info = TRUE;
+ p_msg->ertm_info = *ertm_info;
+ } else {
+ p_msg->has_ertm_info = FALSE;
+ }
+ memcpy(p_msg->peer_bd_addr, peer_bd_addr, sizeof(BD_ADDR));
+ p_msg->p_cback = p_cback;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capConnect
+**
+** Description Initiate a connection as a L2CAP client to the given BD
+** Address.
+** When the connection is initiated or failed to initiate,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+** When the connection is established or failed,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capConnect(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO *ertm_info, UINT16 remote_psm,
+ UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+ BD_ADDR peer_bd_addr, tBTA_JV_L2CAP_CBACK *p_cback, void *user_data)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_CONNECT *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if (p_cback &&
+ (p_msg = (tBTA_JV_API_L2CAP_CONNECT *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_CONNECT))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_CONNECT_EVT;
+ p_msg->sec_mask = sec_mask;
+ p_msg->role = role;
+ p_msg->remote_psm = remote_psm;
+ p_msg->rx_mtu = rx_mtu;
+ if(cfg != NULL) {
+ p_msg->has_cfg = TRUE;
+ p_msg->cfg = *cfg;
+ } else {
+ p_msg->has_cfg = FALSE;
+ }
+ if(ertm_info != NULL) {
+ p_msg->has_ertm_info = TRUE;
+ p_msg->ertm_info = *ertm_info;
+ } else {
+ p_msg->has_ertm_info = FALSE;
+ }
+ memcpy(p_msg->peer_bd_addr, peer_bd_addr, sizeof(BD_ADDR));
+ p_msg->p_cback = p_cback;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capClose
+**
+** Description This function closes an L2CAP client connection
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capClose(UINT32 handle)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_CLOSE *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback &&
+ (p_msg = (tBTA_JV_API_L2CAP_CLOSE *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_CLOSE))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_CLOSE_EVT;
+ p_msg->handle = handle;
+ p_msg->p_cb = &bta_jv_cb.l2c_cb[handle];
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capCloseLE
+**
+** Description This function closes an L2CAP client connection for Fixed Channels
+** Function is idempotent and no callbacks are called!
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capCloseLE(UINT32 handle)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_CLOSE *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if ((p_msg = (tBTA_JV_API_L2CAP_CLOSE *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_CLOSE))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_CLOSE_FIXED_EVT;
+ p_msg->handle = handle;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capStartServer
+**
+** Description This function starts an L2CAP server and listens for an L2CAP
+** connection from a remote Bluetooth device. When the server
+** is started successfully, tBTA_JV_L2CAP_CBACK is called with
+** BTA_JV_L2CAP_START_EVT. When the connection is established,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStartServer(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO *ertm_info,UINT16 local_psm, UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+ tBTA_JV_L2CAP_CBACK *p_cback, void *user_data)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_SERVER *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if (p_cback &&
+ (p_msg = (tBTA_JV_API_L2CAP_SERVER *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_SERVER))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_START_SERVER_EVT;
+ p_msg->sec_mask = sec_mask;
+ p_msg->role = role;
+ p_msg->local_psm = local_psm;
+ p_msg->rx_mtu = rx_mtu;
+ if(cfg != NULL) {
+ p_msg->has_cfg = TRUE;
+ p_msg->cfg = *cfg;
+ } else {
+ p_msg->has_cfg = FALSE;
+ }
+ if(ertm_info != NULL) {
+ p_msg->has_ertm_info = TRUE;
+ p_msg->ertm_info = *ertm_info;
+ } else {
+ p_msg->has_ertm_info = FALSE;
+ }
+ p_msg->p_cback = p_cback;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capStartServerLE
+**
+** Description This function starts an LE L2CAP server and listens for an L2CAP
+** connection from a remote Bluetooth device. When the server
+** is started successfully, tBTA_JV_L2CAP_CBACK is called with
+** BTA_JV_L2CAP_START_EVT. When the connection is established,
+** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStartServerLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO *ertm_info,UINT16 local_chan, UINT16 rx_mtu, tL2CAP_CFG_INFO *cfg,
+ tBTA_JV_L2CAP_CBACK *p_cback, void *user_data)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_SERVER *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if (p_cback &&
+ (p_msg = (tBTA_JV_API_L2CAP_SERVER *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_SERVER))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_START_SERVER_LE_EVT;
+ p_msg->sec_mask = sec_mask;
+ p_msg->role = role;
+ p_msg->local_chan = local_chan;
+ p_msg->rx_mtu = rx_mtu;
+ if(cfg != NULL) {
+ p_msg->has_cfg = TRUE;
+ p_msg->cfg = *cfg;
+ } else {
+ p_msg->has_cfg = FALSE;
+ }
+ if(ertm_info != NULL) {
+ p_msg->has_ertm_info = TRUE;
+ p_msg->ertm_info = *ertm_info;
+ } else {
+ p_msg->has_ertm_info = FALSE;
+ }
+ p_msg->p_cback = p_cback;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capStopServer
+**
+** Description This function stops the L2CAP server. If the server has an
+** active connection, it would be closed.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStopServer(UINT16 local_psm, void *user_data)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_SERVER *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if ((p_msg = (tBTA_JV_API_L2CAP_SERVER *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_SERVER))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_STOP_SERVER_EVT;
+ p_msg->local_psm = local_psm;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capStopServerLE
+**
+** Description This function stops the LE L2CAP server. If the server has an
+** active connection, it would be closed.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStopServerLE(UINT16 local_chan, void *user_data)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_SERVER *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if ((p_msg = (tBTA_JV_API_L2CAP_SERVER *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_SERVER))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT;
+ p_msg->local_chan = local_chan;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capRead
+**
+** Description This function reads data from an L2CAP connecti;
+ tBTA_JV_RFC_CB *p_cb = rc->p_cb;
+on
+** When the operation is complete, tBTA_JV_L2CAP_CBACK is
+** called with BTA_JV_L2CAP_READ_EVT.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capRead(UINT32 handle, UINT32 req_id, UINT8 *p_data, UINT16 len)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_L2CAP_READ evt_data;
+
+ APPL_TRACE_API( "%s", __func__);
+
+
+ if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback)
+ {
+ status = BTA_JV_SUCCESS;
+ evt_data.status = BTA_JV_FAILURE;
+ evt_data.handle = handle;
+ evt_data.req_id = req_id;
+ evt_data.p_data = p_data;
+ evt_data.len = 0;
+
+ if (BT_PASS == GAP_ConnReadData((UINT16)handle, p_data, len, &evt_data.len))
+ {
+ evt_data.status = BTA_JV_SUCCESS;
+ }
+ bta_jv_cb.l2c_cb[handle].p_cback(
+ BTA_JV_L2CAP_READ_EVT, (tBTA_JV *)&evt_data, bta_jv_cb.l2c_cb[handle].user_data);
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capReceive
+**
+** Description This function reads data from an L2CAP connection
+** When the operation is complete, tBTA_JV_L2CAP_CBACK is
+** called with BTA_JV_L2CAP_RECEIVE_EVT.
+** If there are more data queued in L2CAP than len, the extra data will be discarded.
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capReceive(UINT32 handle, UINT32 req_id, UINT8 *p_data, UINT16 len)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_L2CAP_RECEIVE evt_data;
+ UINT32 left_over = 0;
+ UINT16 max_len, read_len;
+
+ APPL_TRACE_API( "%s", __func__);
+
+
+ if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback)
+ {
+ status = BTA_JV_SUCCESS;
+ evt_data.status = BTA_JV_FAILURE;
+ evt_data.handle = handle;
+ evt_data.req_id = req_id;
+ evt_data.p_data = p_data;
+ evt_data.len = 0;
+
+ if (BT_PASS == GAP_ConnReadData((UINT16)handle, p_data, len, &evt_data.len))
+ {
+ evt_data.status = BTA_JV_SUCCESS;
+ GAP_GetRxQueueCnt ((UINT16)handle, &left_over);
+ while (left_over)
+ {
+ max_len = (left_over > 0xFFFF)?0xFFFF:left_over;
+ GAP_ConnReadData ((UINT16)handle, NULL, max_len, &read_len);
+ left_over -= read_len;
+ }
+ }
+ bta_jv_cb.l2c_cb[handle].p_cback(
+ BTA_JV_L2CAP_RECEIVE_EVT, (tBTA_JV *)&evt_data, bta_jv_cb.l2c_cb[handle].user_data);
+ }
+
+ return(status);
+}
+/*******************************************************************************
+**
+** Function BTA_JvL2capReady
+**
+** Description This function determined if there is data to read from
+** an L2CAP connection
+**
+** Returns BTA_JV_SUCCESS, if data queue size is in *p_data_size.
+** BTA_JV_FAILURE, if error.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capReady(UINT32 handle, UINT32 *p_data_size)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+
+ APPL_TRACE_API( "%s: %d", __func__, handle);
+ if (p_data_size && handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback)
+ {
+ *p_data_size = 0;
+ if(BT_PASS == GAP_GetRxQueueCnt((UINT16)handle, p_data_size) )
+ {
+ status = BTA_JV_SUCCESS;
+ }
+ }
+
+ return(status);
+}
+
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capWrite
+**
+** Description This function writes data to an L2CAP connection
+** When the operation is complete, tBTA_JV_L2CAP_CBACK is
+** called with BTA_JV_L2CAP_WRITE_EVT. Works for
+** PSM-based connections
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capWrite(UINT32 handle, UINT32 req_id, UINT8 *p_data,
+ UINT16 len, void *user_data)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_WRITE *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback &&
+ (p_msg = (tBTA_JV_API_L2CAP_WRITE *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_WRITE))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_WRITE_EVT;
+ p_msg->handle = handle;
+ p_msg->req_id = req_id;
+ p_msg->p_data = p_data;
+ p_msg->p_cb = &bta_jv_cb.l2c_cb[handle];
+ p_msg->len = len;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
+** Function BTA_JvL2capWriteFixed
+**
+** Description This function writes data to an L2CAP connection
+** When the operation is complete, tBTA_JV_L2CAP_CBACK is
+** called with BTA_JV_L2CAP_WRITE_EVT. Works for
+** fixed-channel connections
+**
+** Returns BTA_JV_SUCCESS, if the request is being processed.
+** BTA_JV_FAILURE, otherwise.
+**
+*******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capWriteFixed(UINT16 channel, BD_ADDR *addr, UINT32 req_id,
+ tBTA_JV_L2CAP_CBACK *p_cback, UINT8 *p_data, UINT16 len, void *user_data)
+{
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_API_L2CAP_WRITE_FIXED *p_msg;
+
+ APPL_TRACE_API( "%s", __func__);
+
+ if ((p_msg =
+ (tBTA_JV_API_L2CAP_WRITE_FIXED *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_WRITE_FIXED))) != NULL)
+ {
+ p_msg->hdr.event = BTA_JV_API_L2CAP_WRITE_FIXED_EVT;
+ p_msg->channel = channel;
+ memcpy(p_msg->addr, addr, sizeof(p_msg->addr));
+ p_msg->req_id = req_id;
+ p_msg->p_data = p_data;
+ p_msg->p_cback = p_cback;
+ p_msg->len = len;
+ p_msg->user_data = user_data;
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+**
** Function BTA_JvRfcommConnect
**
** Description This function makes an RFCOMM conection to a remote BD
diff --git a/bta/jv/bta_jv_int.h b/bta/jv/bta_jv_int.h
index a76664704..eaaa75ca0 100644
--- a/bta/jv/bta_jv_int.h
+++ b/bta/jv/bta_jv_int.h
@@ -39,9 +39,17 @@ enum
/* these events are handled by the state machine */
BTA_JV_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_JV),
BTA_JV_API_DISABLE_EVT,
+ BTA_JV_API_GET_CHANNEL_EVT,
+ BTA_JV_API_FREE_SCN_EVT,
BTA_JV_API_START_DISCOVERY_EVT,
BTA_JV_API_CREATE_RECORD_EVT,
BTA_JV_API_DELETE_RECORD_EVT,
+ BTA_JV_API_L2CAP_CONNECT_EVT,
+ BTA_JV_API_L2CAP_CLOSE_EVT,
+ BTA_JV_API_L2CAP_START_SERVER_EVT,
+ BTA_JV_API_L2CAP_STOP_SERVER_EVT,
+ BTA_JV_API_L2CAP_READ_EVT,
+ BTA_JV_API_L2CAP_WRITE_EVT,
BTA_JV_API_RFCOMM_CONNECT_EVT,
BTA_JV_API_RFCOMM_CLOSE_EVT,
BTA_JV_API_RFCOMM_START_SERVER_EVT,
@@ -50,6 +58,11 @@ enum
BTA_JV_API_RFCOMM_WRITE_EVT,
BTA_JV_API_SET_PM_PROFILE_EVT,
BTA_JV_API_PM_STATE_CHANGE_EVT,
+ BTA_JV_API_L2CAP_CONNECT_LE_EVT,
+ BTA_JV_API_L2CAP_START_SERVER_LE_EVT,
+ BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT,
+ BTA_JV_API_L2CAP_WRITE_FIXED_EVT,
+ BTA_JV_API_L2CAP_CLOSE_FIXED_EVT,
BTA_JV_MAX_INT_EVT
};
@@ -104,6 +117,18 @@ enum
} ;
typedef UINT8 tBTA_JV_STATE;
#define BTA_JV_ST_CL_MAX BTA_JV_ST_CL_CLOSING
+/* JV L2CAP control block */
+typedef struct
+{
+ tBTA_JV_L2CAP_CBACK *p_cback; /* the callback function */
+ UINT16 psm; /* the psm used for this server connection */
+ tBTA_JV_STATE state; /* the state of this control block */
+ tBTA_SERVICE_ID sec_id; /* service id */
+ UINT32 handle; /* the handle reported to java app (same as gap handle) */
+ BOOLEAN cong; /* TRUE, if congested */
+ tBTA_JV_PM_CB *p_pm_cb; /* ptr to pm control block, NULL: unused */
+ void *user_data; /* user data for callback from higher layers */
+} tBTA_JV_L2C_CB;
#define BTA_JV_RFC_HDL_MASK 0xFF
#define BTA_JV_RFCOMM_MASK 0x80
@@ -115,12 +140,12 @@ typedef UINT8 tBTA_JV_STATE;
typedef struct
{
UINT32 handle; /* the rfcomm session handle at jv */
- UINT16 port_handle; /* port handle */
+ UINT16 port_handle;/* port handle */
tBTA_JV_STATE state; /* the state of this control block */
UINT8 max_sess; /* max sessions */
void *user_data; /* piggyback caller's private data*/
BOOLEAN cong; /* TRUE, if congested */
- tBTA_JV_PM_CB *p_pm_cb; /* ptr to pm control block, NULL: unused */
+ tBTA_JV_PM_CB *p_pm_cb; /* ptr to pm control block, NULL: unused */
} tBTA_JV_PCB;
/* JV RFCOMM control block */
@@ -135,6 +160,90 @@ typedef struct
int curr_sess; /* current sessions count*/
} tBTA_JV_RFC_CB;
+/* data type for BTA_JV_API_L2CAP_CONNECT_EVT & BTA_JV_API_L2CAP_CONNECT_LE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_SEC sec_mask;
+ tBTA_JV_ROLE role;
+ union {
+ UINT16 remote_psm;
+ UINT16 remote_chan;
+ };
+ UINT16 rx_mtu;
+ BD_ADDR peer_bd_addr;
+ INT32 has_cfg;
+ tL2CAP_CFG_INFO cfg;
+ INT32 has_ertm_info;
+ tL2CAP_ERTM_INFO ertm_info;
+ tBTA_JV_L2CAP_CBACK *p_cback;
+ void *user_data;
+} tBTA_JV_API_L2CAP_CONNECT;
+
+/* data type for BTA_JV_API_L2CAP_SERVER_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_SEC sec_mask;
+ tBTA_JV_ROLE role;
+ union {
+ UINT16 local_psm;
+ UINT16 local_chan;
+ };
+ UINT16 rx_mtu;
+ INT32 has_cfg;
+ tL2CAP_CFG_INFO cfg;
+ INT32 has_ertm_info;
+ tL2CAP_ERTM_INFO ertm_info;
+ tBTA_JV_L2CAP_CBACK *p_cback;
+ void *user_data;
+} tBTA_JV_API_L2CAP_SERVER;
+
+/* data type for BTA_JV_API_L2CAP_CLOSE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT32 handle;
+ tBTA_JV_L2C_CB *p_cb;
+} tBTA_JV_API_L2CAP_CLOSE;
+
+/* data type for BTA_JV_API_L2CAP_READ_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT32 handle;
+ UINT32 req_id;
+ tBTA_JV_L2CAP_CBACK *p_cback;
+ UINT8* p_data;
+ UINT16 len;
+ void *user_data;
+} tBTA_JV_API_L2CAP_READ;
+
+/* data type for BTA_JV_API_L2CAP_WRITE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT32 handle;
+ UINT32 req_id;
+ tBTA_JV_L2C_CB *p_cb;
+ UINT8 *p_data;
+ UINT16 len;
+ void *user_data;
+} tBTA_JV_API_L2CAP_WRITE;
+
+/* data type for BTA_JV_API_L2CAP_WRITE_FIXED_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT16 channel;
+ BD_ADDR addr;
+ UINT32 req_id;
+ tBTA_JV_L2CAP_CBACK *p_cback;
+ UINT8 *p_data;
+ UINT16 len;
+ void *user_data;
+} tBTA_JV_API_L2CAP_WRITE_FIXED;
+
/* data type for BTA_JV_API_RFCOMM_CONNECT_EVT */
typedef struct
{
@@ -196,7 +305,7 @@ typedef struct
UINT32 handle;
UINT32 req_id;
UINT8 *p_data;
- int len;
+ int len;
tBTA_JV_RFC_CB *p_cb;
tBTA_JV_PCB *p_pcb;
} tBTA_JV_API_RFCOMM_WRITE;
@@ -208,7 +317,7 @@ typedef struct
UINT32 handle;
tBTA_JV_RFC_CB *p_cb;
tBTA_JV_PCB *p_pcb;
- void *user_data;
+ void *user_data;
} tBTA_JV_API_RFCOMM_CLOSE;
/* data type for BTA_JV_API_CREATE_RECORD_EVT */
@@ -228,6 +337,22 @@ typedef struct
INT32 value_size;
} tBTA_JV_API_ADD_ATTRIBUTE;
+/* data type for BTA_JV_API_FREE_SCN_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ INT32 type; /* One of BTA_JV_CONN_TYPE_ */
+ UINT16 scn;
+} tBTA_JV_API_FREE_CHANNEL;
+
+/* data type for BTA_JV_API_ALLOC_CHANNEL_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ INT32 type; /* One of BTA_JV_CONN_TYPE_ */
+ INT32 channel; /* optionally request a specific channel */
+ void *user_data;
+} tBTA_JV_API_ALLOC_CHANNEL;
/* union of all data types */
typedef union
{
@@ -235,8 +360,15 @@ typedef union
BT_HDR hdr;
tBTA_JV_API_ENABLE enable;
tBTA_JV_API_START_DISCOVERY start_discovery;
+ tBTA_JV_API_ALLOC_CHANNEL alloc_channel;
+ tBTA_JV_API_FREE_CHANNEL free_channel;
tBTA_JV_API_CREATE_RECORD create_record;
tBTA_JV_API_ADD_ATTRIBUTE add_attr;
+ tBTA_JV_API_L2CAP_CONNECT l2cap_connect;
+ tBTA_JV_API_L2CAP_READ l2cap_read;
+ tBTA_JV_API_L2CAP_WRITE l2cap_write;
+ tBTA_JV_API_L2CAP_CLOSE l2cap_close;
+ tBTA_JV_API_L2CAP_SERVER l2cap_server;
tBTA_JV_API_RFCOMM_CONNECT rfcomm_connect;
tBTA_JV_API_RFCOMM_READ rfcomm_read;
tBTA_JV_API_RFCOMM_WRITE rfcomm_write;
@@ -244,6 +376,7 @@ typedef union
tBTA_JV_API_PM_STATE_CHANGE change_pm_state;
tBTA_JV_API_RFCOMM_CLOSE rfcomm_close;
tBTA_JV_API_RFCOMM_SERVER rfcomm_server;
+ tBTA_JV_API_L2CAP_WRITE_FIXED l2cap_write_fixed;
} tBTA_JV_MSG;
/* JV control block */
@@ -255,9 +388,14 @@ typedef struct
UINT32 sdp_handle[BTA_JV_MAX_SDP_REC]; /* SDP records created */
UINT8 *p_sel_raw_data;/* the raw data of last service select */
tBTA_JV_DM_CBACK *p_dm_cback;
+ tBTA_JV_L2C_CB l2c_cb[BTA_JV_MAX_L2C_CONN]; /* index is GAP handle (index) */
tBTA_JV_RFC_CB rfc_cb[BTA_JV_MAX_RFC_CONN];
- tBTA_JV_PCB port_cb[MAX_RFC_PORTS]; /* index of this array is the port_handle, */
+ tBTA_JV_PCB port_cb[MAX_RFC_PORTS]; /* index of this array is
+ the port_handle, */
UINT8 sec_id[BTA_JV_NUM_SERVICE_ID]; /* service ID */
+ BOOLEAN scn[BTA_JV_MAX_SCN]; /* SCN allocated by java */
+ UINT16 free_psm_list[BTA_JV_MAX_L2C_CONN]; /* PSMs freed by java
+ (can be reused) */
UINT8 sdp_active; /* see BTA_JV_SDP_ACT_* */
tSDP_UUID uuid; /* current uuid of sdp discovery*/
tBTA_JV_PM_CB pm_cb[BTA_JV_PM_MAX_NUM]; /* PM on a per JV handle bases */
@@ -285,9 +423,17 @@ extern BOOLEAN bta_jv_sm_execute(BT_HDR *p_msg);
extern void bta_jv_enable (tBTA_JV_MSG *p_data);
extern void bta_jv_disable (tBTA_JV_MSG *p_data);
+extern void bta_jv_get_channel_id (tBTA_JV_MSG *p_data);
+extern void bta_jv_free_scn (tBTA_JV_MSG *p_data);
extern void bta_jv_start_discovery (tBTA_JV_MSG *p_data);
extern void bta_jv_create_record (tBTA_JV_MSG *p_data);
extern void bta_jv_delete_record (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_connect (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_close (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_start_server (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_stop_server (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_read (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_write (tBTA_JV_MSG *p_data);
extern void bta_jv_rfcomm_connect (tBTA_JV_MSG *p_data);
extern void bta_jv_rfcomm_close (tBTA_JV_MSG *p_data);
extern void bta_jv_rfcomm_start_server (tBTA_JV_MSG *p_data);
@@ -296,5 +442,10 @@ extern void bta_jv_rfcomm_read (tBTA_JV_MSG *p_data);
extern void bta_jv_rfcomm_write (tBTA_JV_MSG *p_data);
extern void bta_jv_set_pm_profile (tBTA_JV_MSG *p_data);
extern void bta_jv_change_pm_state(tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_connect_le (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_start_server_le (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_stop_server_le (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_write_fixed (tBTA_JV_MSG *p_data);
+extern void bta_jv_l2cap_close_fixed (tBTA_JV_MSG *p_data);
#endif /* BTA_JV_INT_H */
diff --git a/bta/jv/bta_jv_main.c b/bta/jv/bta_jv_main.c
index 97e2b818e..eb22338f7 100644
--- a/bta/jv/bta_jv_main.c
+++ b/bta/jv/bta_jv_main.c
@@ -46,9 +46,17 @@ const tBTA_JV_ACTION bta_jv_action[] =
{
bta_jv_enable, /* BTA_JV_API_ENABLE_EVT */
bta_jv_disable, /* BTA_JV_API_DISABLE_EVT */
+ bta_jv_get_channel_id, /* BTA_JV_API_GET_CHANNEL_EVT */
+ bta_jv_free_scn, /* BTA_JV_API_FREE_SCN_EVT */
bta_jv_start_discovery, /* BTA_JV_API_START_DISCOVERY_EVT */
bta_jv_create_record, /* BTA_JV_API_CREATE_RECORD_EVT */
bta_jv_delete_record, /* BTA_JV_API_DELETE_RECORD_EVT */
+ bta_jv_l2cap_connect, /* BTA_JV_API_L2CAP_CONNECT_EVT */
+ bta_jv_l2cap_close, /* BTA_JV_API_L2CAP_CLOSE_EVT */
+ bta_jv_l2cap_start_server, /* BTA_JV_API_L2CAP_START_SERVER_EVT */
+ bta_jv_l2cap_stop_server, /* BTA_JV_API_L2CAP_STOP_SERVER_EVT */
+ bta_jv_l2cap_read, /* BTA_JV_API_L2CAP_READ_EVT */
+ bta_jv_l2cap_write, /* BTA_JV_API_L2CAP_WRITE_EVT */
bta_jv_rfcomm_connect, /* BTA_JV_API_RFCOMM_CONNECT_EVT */
bta_jv_rfcomm_close, /* BTA_JV_API_RFCOMM_CLOSE_EVT */
bta_jv_rfcomm_start_server, /* BTA_JV_API_RFCOMM_START_SERVER_EVT */
@@ -57,6 +65,11 @@ const tBTA_JV_ACTION bta_jv_action[] =
bta_jv_rfcomm_write, /* BTA_JV_API_RFCOMM_WRITE_EVT */
bta_jv_set_pm_profile, /* BTA_JV_API_SET_PM_PROFILE_EVT */
bta_jv_change_pm_state, /* BTA_JV_API_PM_STATE_CHANGE_EVT */
+ bta_jv_l2cap_connect_le, /* BTA_JV_API_L2CAP_CONNECT_LE_EVT */
+ bta_jv_l2cap_start_server_le, /* BTA_JV_API_L2CAP_START_SERVER_LE_EVT */
+ bta_jv_l2cap_stop_server_le, /* BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT */
+ bta_jv_l2cap_write_fixed, /* BTA_JV_API_L2CAP_WRITE_FIXED_EVT */
+ bta_jv_l2cap_close_fixed, /* BTA_JV_API_L2CAP_CLOSE_FIXED_EVT */
};
/*******************************************************************************