OSDN Git Service

am f29a2fb..e07ad10 from mirror-m-wireless-internal-release
[android-x86/system-bt.git] / bta / jv / bta_jv_act.c
index fb6b40e..a182672 100644 (file)
  ******************************************************************************/
 #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);
 }
 
@@ -70,38 +115,6 @@ tBTA_JV_STATUS bta_jv_set_pm_conn_state(tBTA_JV_PM_CB *p_cb, const tBTA_JV_CONN_
 
 /*******************************************************************************
 **
-** 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
@@ -379,51 +392,33 @@ static tBTA_JV_STATUS bta_jv_free_rfc_cb(tBTA_JV_RFC_CB *p_cb, tBTA_JV_PCB *p_pc
 *******************************************************************************/
 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! */
@@ -465,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]);
@@ -494,9 +489,9 @@ 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;
                     }
                 }
@@ -507,8 +502,8 @@ static tBTA_JV_STATUS bta_jv_free_set_pm_profile_cb(UINT32 jv_handle)
                 {
                     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;
                 }
             }
@@ -599,71 +594,6 @@ static tBTA_JV_PM_CB *bta_jv_alloc_set_pm_profile_cb(UINT32 jv_handle, tBTA_JV_P
 }
 
 /*******************************************************************************
- **
- ** 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
 **
@@ -676,12 +606,12 @@ BOOLEAN bta_jv_check_psm(UINT16 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 */
@@ -721,7 +651,9 @@ BOOLEAN bta_jv_check_psm(UINT16 psm)
             }
         }
         else
+        {
             ret = TRUE;
+        }
     }
     return ret;
 
@@ -741,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));
 }
 
 /*******************************************************************************
@@ -757,226 +690,100 @@ void bta_jv_disable (tBTA_JV_MSG *p_data)
 {
     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);
 }
 
 /*******************************************************************************
@@ -990,13 +797,26 @@ void bta_jv_get_scn(tBTA_JV_MSG *p_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)
@@ -1054,38 +874,27 @@ static void bta_jv_start_discovery_cback(UINT16 result, void * user_data)
     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);
     }
 }
 
@@ -1110,14 +919,7 @@ void bta_jv_start_discovery(tBTA_JV_MSG *p_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);
@@ -1148,152 +950,6 @@ void bta_jv_start_discovery(tBTA_JV_MSG *p_data)
 
 /*******************************************************************************
 **
-** 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
@@ -1313,150 +969,6 @@ void bta_jv_create_record(tBTA_JV_MSG *p_data)
 
 /*******************************************************************************
 **
-** 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
@@ -1475,77 +987,63 @@ void bta_jv_delete_record(tBTA_JV_MSG *p_data)
     }
 }
 
-#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
 
 /*******************************************************************************
 **
@@ -1558,18 +1056,34 @@ static void bta_jv_sdp_cback(UINT16 result)
 *******************************************************************************/
 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);
     */
@@ -1577,27 +1091,13 @@ void bta_jv_l2cap_connect(tBTA_JV_MSG *p_data)
     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;
@@ -1610,6 +1110,7 @@ void bta_jv_l2cap_connect(tBTA_JV_MSG *p_data)
         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;
@@ -1618,11 +1119,12 @@ void bta_jv_l2cap_connect(tBTA_JV_MSG *p_data)
     {
         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
@@ -1634,21 +1136,78 @@ void bta_jv_l2cap_connect(tBTA_JV_MSG *p_data)
 *******************************************************************************/
 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;
+    }
 }
 
 /*******************************************************************************
@@ -1662,17 +1221,29 @@ void bta_jv_l2cap_close(tBTA_JV_MSG *p_data)
 *******************************************************************************/
 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)
     {
@@ -1691,31 +1262,27 @@ void bta_jv_l2cap_start_server(tBTA_JV_MSG *p_data)
 
     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);
 }
 
 /*******************************************************************************
@@ -1729,30 +1296,29 @@ void bta_jv_l2cap_start_server(tBTA_JV_MSG *p_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
@@ -1764,8 +1330,6 @@ void bta_jv_l2cap_stop_server(tBTA_JV_MSG *p_data)
 *******************************************************************************/
 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);
 
@@ -1774,26 +1338,13 @@ void bta_jv_l2cap_read(tBTA_JV_MSG *p_data)
     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);
 }
 
 
@@ -1808,48 +1359,76 @@ void bta_jv_l2cap_read(tBTA_JV_MSG *p_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);
 }
 
 /*******************************************************************************
@@ -1862,23 +1441,21 @@ void bta_jv_l2cap_write(tBTA_JV_MSG *p_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:
@@ -1962,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",
@@ -2126,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
@@ -2141,10 +1750,8 @@ static void bta_jv_port_mgmt_sr_cback(UINT32 code, UINT16 port_handle)
     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);
@@ -2183,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;
@@ -2212,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",
@@ -2266,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);
@@ -2311,8 +1918,6 @@ static tBTA_JV_PCB * bta_jv_add_rfc_port(tBTA_JV_RFC_CB *p_cb, tBTA_JV_PCB *p_pc
 
                 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",
@@ -2375,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;
@@ -2390,7 +1995,7 @@ void bta_jv_rfcomm_start_server(tBTA_JV_MSG *p_data)
         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);
@@ -2399,20 +2004,19 @@ void bta_jv_rfcomm_start_server(tBTA_JV_MSG *p_data)
 
         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);
     }
 }
@@ -2433,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);
@@ -2703,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);
+}