Browse Source

component/bt: Added the new feature of the l2cap layer from the bluedroid new version 7.1.1

Yulong 8 years ago
parent
commit
371c55138e

+ 6 - 0
components/bt/bluedroid/include/bt_target.h

@@ -665,6 +665,12 @@
 #define L2CAP_CLIENT_INCLUDED FALSE
 #endif
 
+/* The maximum number of simultaneous applications that can register with LE L2CAP. */
+#ifndef BLE_MAX_L2CAP_CLIENTS
+#define BLE_MAX_L2CAP_CLIENTS           15
+#endif
+
+
 /* The maximum number of simultaneous links that L2CAP can support. Up to 7*/
 #ifndef MAX_ACL_CONNECTIONS
 #define MAX_L2CAP_LINKS             5

+ 165 - 0
components/bt/bluedroid/stack/btm/btm_ble.c

@@ -830,6 +830,171 @@ tBTM_STATUS BTM_SetBleDataLength(BD_ADDR bd_addr, UINT16 tx_pdu_length)
     }
 }
 
+/*******************************************************************************
+**
+** Function         btm_ble_determine_security_act
+**
+** Description      This function checks the security of current LE link
+**                  and returns the appropriate action that needs to be
+**                  taken to achieve the required security.
+**
+** Parameter        is_originator - True if outgoing connection
+**                  bdaddr: remote device address
+**                  security_required: Security required for the service.
+**
+** Returns          The appropriate security action required.
+**
+*******************************************************************************/
+tBTM_SEC_ACTION btm_ble_determine_security_act(BOOLEAN is_originator, BD_ADDR bdaddr, UINT16 security_required)
+{
+    tBTM_LE_AUTH_REQ auth_req = 0x00;
+
+    if (is_originator)
+    {
+        if ((security_required & BTM_SEC_OUT_FLAGS) == 0 &&
+                (security_required & BTM_SEC_OUT_MITM) == 0)
+        {
+            BTM_TRACE_DEBUG ("%s No security required for outgoing connection", __func__);
+            return BTM_SEC_OK;
+        }
+
+        if (security_required & BTM_SEC_OUT_MITM)
+            auth_req |= BTM_LE_AUTH_REQ_MITM;
+    }
+    else
+    {
+        if ((security_required & BTM_SEC_IN_FLAGS) == 0&& (security_required & BTM_SEC_IN_MITM) == 0)
+        {
+            BTM_TRACE_DEBUG ("%s No security required for incoming connection", __func__);
+            return BTM_SEC_OK;
+        }
+
+        if (security_required & BTM_SEC_IN_MITM)
+            auth_req |= BTM_LE_AUTH_REQ_MITM;
+    }
+
+    tBTM_BLE_SEC_REQ_ACT ble_sec_act;
+    btm_ble_link_sec_check(bdaddr, auth_req, &ble_sec_act);
+
+    BTM_TRACE_DEBUG ("%s ble_sec_act %d", __func__ , ble_sec_act);
+
+    if (ble_sec_act == BTM_BLE_SEC_REQ_ACT_DISCARD)
+        return BTM_SEC_ENC_PENDING;
+
+    if (ble_sec_act == BTM_BLE_SEC_REQ_ACT_NONE)
+        return BTM_SEC_OK;
+
+    UINT8 sec_flag = 0;
+    BTM_GetSecurityFlagsByTransport(bdaddr, &sec_flag, BT_TRANSPORT_LE);
+
+    BOOLEAN is_link_encrypted = FALSE;
+    BOOLEAN is_key_mitm = FALSE;
+    if (sec_flag & (BTM_SEC_FLAG_ENCRYPTED| BTM_SEC_FLAG_LKEY_KNOWN))
+    {
+        if (sec_flag & BTM_SEC_FLAG_ENCRYPTED)
+            is_link_encrypted = TRUE;
+
+        if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED)
+            is_key_mitm = TRUE;
+    }
+
+    if (auth_req & BTM_LE_AUTH_REQ_MITM)
+    {
+        if (!is_key_mitm)
+        {
+            return BTM_SEC_ENCRYPT_MITM;
+        } else {
+            if (is_link_encrypted)
+                return BTM_SEC_OK;
+            else
+                return BTM_SEC_ENCRYPT;
+        }
+    } else {
+        if (is_link_encrypted)
+            return BTM_SEC_OK;
+        else
+            return BTM_SEC_ENCRYPT_NO_MITM;
+    }
+
+    return BTM_SEC_OK;
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_ble_start_sec_check
+**
+** Description      This function is to check and set the security required for
+**                  LE link for LE COC.
+**
+** Parameter        bdaddr: remote device address.
+**                  psm : PSM of the LE COC sevice.
+**                  is_originator: TRUE if outgoing connection.
+**                  p_callback : Pointer to the callback function.
+**                  p_ref_data : Pointer to be returned along with the callback.
+**
+** Returns          TRUE if link already meets the required security; otherwise FALSE.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_start_sec_check(BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_originator,
+                            tBTM_SEC_CALLBACK *p_callback, void *p_ref_data)
+{
+    /* Find the service record for the PSM */
+    tBTM_SEC_SERV_REC *p_serv_rec = btm_sec_find_first_serv (is_originator, psm);
+
+    /* If there is no application registered with this PSM do not allow connection */
+    if (!p_serv_rec)
+    {
+        BTM_TRACE_WARNING ("%s PSM: %d no application registerd", __func__, psm);
+        (*p_callback) (bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_MODE_UNSUPPORTED);
+        return FALSE;
+    }
+
+    tBTM_SEC_ACTION sec_act = btm_ble_determine_security_act(is_originator,
+                                  bd_addr, p_serv_rec->security_flags);
+
+    tBTM_BLE_SEC_ACT ble_sec_act = BTM_BLE_SEC_NONE;
+    BOOLEAN status = FALSE;
+
+    switch (sec_act)
+    {
+        case BTM_SEC_OK:
+            BTM_TRACE_DEBUG ("%s Security met", __func__);
+            p_callback(bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_SUCCESS);
+            status = TRUE;
+            break;
+
+        case BTM_SEC_ENCRYPT:
+            BTM_TRACE_DEBUG ("%s Encryption needs to be done", __func__);
+            ble_sec_act = BTM_BLE_SEC_ENCRYPT;
+            break;
+
+        case BTM_SEC_ENCRYPT_MITM:
+            BTM_TRACE_DEBUG ("%s Pairing with MITM needs to be done", __func__);
+            ble_sec_act = BTM_BLE_SEC_ENCRYPT_MITM;
+            break;
+
+        case BTM_SEC_ENCRYPT_NO_MITM:
+            BTM_TRACE_DEBUG ("%s Pairing with No MITM needs to be done", __func__);
+            ble_sec_act = BTM_BLE_SEC_ENCRYPT_NO_MITM;
+            break;
+
+        case BTM_SEC_ENC_PENDING:
+            BTM_TRACE_DEBUG ("%s Ecryption pending", __func__);
+            break;
+    }
+
+    if (ble_sec_act == BTM_BLE_SEC_NONE)
+        return status;
+
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
+    p_lcb->sec_act = sec_act;
+    BTM_SetEncryption(bd_addr, BT_TRANSPORT_LE, p_callback, p_ref_data);
+
+    return FALSE;
+}
+
+
 /*******************************************************************************
 **
 ** Function         btm_ble_rand_enc_complete

+ 2 - 12
components/bt/bluedroid/stack/btm/btm_sec.c

@@ -56,7 +56,6 @@ BOOLEAN (APPL_AUTH_WRITE_EXCEPTION)(BD_ADDR bd_addr);
 **              L O C A L    F U N C T I O N     P R O T O T Y P E S            *
 *********************************************************************************/
 #if (SMP_INCLUDED == TRUE)
-static tBTM_SEC_SERV_REC *btm_sec_find_first_serv (BOOLEAN is_originator, UINT16 psm);
 static tBTM_SEC_SERV_REC *btm_sec_find_next_serv (tBTM_SEC_SERV_REC *p_cur);
 static tBTM_SEC_SERV_REC *btm_sec_find_mx_serv (UINT8 is_originator, UINT16 psm,
         UINT32 mx_proto_id,
@@ -2049,15 +2048,6 @@ static void btm_sec_check_upgrade(tBTM_SEC_DEV_REC  *p_dev_rec, BOOLEAN is_origi
 ** Returns          tBTM_STATUS
 **
 *******************************************************************************/
-#define BTM_SEC_OUT_FLAGS   (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHORIZE)
-#define BTM_SEC_IN_FLAGS    (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHORIZE)
-
-#define BTM_SEC_OUT_LEVEL4_FLAGS   (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | \
-                                    BTM_SEC_OUT_MITM | BTM_SEC_MODE4_LEVEL4)
-
-#define BTM_SEC_IN_LEVEL4_FLAGS    (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | \
-                                    BTM_SEC_IN_MITM | BTM_SEC_MODE4_LEVEL4)
-
 tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle,
                                       CONNECTION_TYPE conn_type,
                                       tBTM_SEC_CALLBACK *p_callback,
@@ -3480,7 +3470,7 @@ void btm_io_capabilities_rsp (UINT8 *p)
 **
 ** Returns          void
 **
-*******************************************************************************/
+*******************************************************************************/
 void btm_proc_sp_req_evt (tBTM_SP_EVT event, UINT8 *p)
 {
     tBTM_STATUS status = BTM_ERR_PROCESSING;
@@ -5422,7 +5412,7 @@ BOOLEAN btm_sec_are_all_trusted(UINT32 p_mask[])
 **
 *******************************************************************************/
 #if (SMP_INCLUDED == TRUE)
-static tBTM_SEC_SERV_REC *btm_sec_find_first_serv (CONNECTION_TYPE conn_type, UINT16 psm)
+tBTM_SEC_SERV_REC *btm_sec_find_first_serv (CONNECTION_TYPE conn_type, UINT16 psm)
 {
     tBTM_SEC_SERV_REC *p_serv_rec = &btm_cb.sec_serv_rec[0];
     int i;

+ 22 - 0
components/bt/bluedroid/stack/include/btm_int.h

@@ -416,6 +416,15 @@ void btm_sco_chk_pend_rolechange (UINT16 hci_handle);
 ** Define structure for Security Service Record.
 ** A record exists for each service registered with the Security Manager
 */
+#define BTM_SEC_OUT_FLAGS   (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHORIZE)
+#define BTM_SEC_IN_FLAGS    (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHORIZE)
+
+#define BTM_SEC_OUT_LEVEL4_FLAGS   (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | \
+                                        BTM_SEC_OUT_MITM | BTM_SEC_MODE4_LEVEL4)
+
+#define BTM_SEC_IN_LEVEL4_FLAGS    (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | \
+                                        BTM_SEC_IN_MITM | BTM_SEC_MODE4_LEVEL4)
+
 typedef struct {
     UINT32          mx_proto_id;        /* Service runs over this multiplexer protocol */
     UINT32          orig_mx_chan_id;    /* Channel on the multiplexer protocol    */
@@ -878,6 +887,15 @@ typedef struct{
 }tBTM_CallbackFunc;
 
 extern tBTM_CallbackFunc conn_param_update_cb;
+/* security action for L2CAP COC channels */
+#define BTM_SEC_OK                1
+#define BTM_SEC_ENCRYPT           2    /* encrypt the link with current key */
+#define BTM_SEC_ENCRYPT_NO_MITM   3    /* unauthenticated encryption or better */
+#define BTM_SEC_ENCRYPT_MITM      4    /* authenticated encryption */
+#define BTM_SEC_ENC_PENDING       5    /* wait for link encryption pending */
+
+typedef UINT8 tBTM_SEC_ACTION;
+
 /*
 #ifdef __cplusplus
 extern "C"
@@ -1082,6 +1100,10 @@ BOOLEAN btm_sec_is_a_bonded_dev (BD_ADDR bda);
 void btm_consolidate_dev(tBTM_SEC_DEV_REC *p_target_rec);
 BOOLEAN btm_sec_is_le_capable_dev (BD_ADDR bda);
 BOOLEAN btm_ble_init_pseudo_addr (tBTM_SEC_DEV_REC *p_dev_rec, BD_ADDR new_pseudo_addr);
+extern BOOLEAN btm_ble_start_sec_check(BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_originator,
+                            tBTM_SEC_CALLBACK *p_callback, void *p_ref_data);
+extern tBTM_SEC_SERV_REC *btm_sec_find_first_serv (CONNECTION_TYPE conn_type, UINT16 psm);
+
 #endif /* BLE_INCLUDED */
 
 tINQ_DB_ENT *btm_inq_db_new (BD_ADDR p_bda);

+ 79 - 0
components/bt/bluedroid/stack/include/l2c_api.h

@@ -124,6 +124,8 @@ typedef UINT8 tL2CAP_CHNL_DATA_RATE;
 */
 #define L2C_INVALID_PSM(psm)    (((psm) & 0x0101) != 0x0001)
 #define L2C_IS_VALID_PSM(psm)   (((psm) & 0x0101) == 0x0001)
+#define L2C_IS_VALID_LE_PSM(psm)   (((psm) > 0x0000) && ((psm) < 0x0100))
+
 
 /*****************************************************************************
 **  Type Definitions
@@ -164,6 +166,17 @@ typedef struct {
     UINT16      flags;                  /* bit 0: 0-no continuation, 1-continuation */
 } tL2CAP_CFG_INFO;
 
+/* Define a structure to hold the configuration parameter for LE L2CAP connection
+** oriented channels.
+*/
+typedef struct
+{
+    UINT16  mtu;
+    UINT16  mps;
+    UINT16  credits;
+} tL2CAP_LE_CFG_INFO;
+
+
 /* L2CAP channel configured field bitmap */
 #define L2CAP_CH_CFG_MASK_MTU           0x0001
 #define L2CAP_CH_CFG_MASK_QOS           0x0002
@@ -486,6 +499,72 @@ extern BOOLEAN L2CA_DisconnectReq (UINT16 cid);
 extern BOOLEAN L2CA_DisconnectRsp (UINT16 cid);
 #endif  ///CLASSIC_BT_INCLUDED == TRUE
 
+/*******************************************************************************
+**
+** Function         L2CA_RegisterLECoc
+**
+** Description      Other layers call this function to register for L2CAP
+**                  Connection Oriented Channel.
+**
+** Returns          PSM to use or zero if error. Typically, the PSM returned
+**                  is the same as was passed in, but for an outgoing-only
+**                  connection to a dynamic PSM, a "virtual" PSM is returned
+**                  and should be used in the calls to L2CA_ConnectLECocReq()
+**                  and BTM_SetSecurityLevel().
+**
+*******************************************************************************/
+extern UINT16 L2CA_RegisterLECoc (UINT16 psm, tL2CAP_APPL_INFO *p_cb_info);
+
+/*******************************************************************************
+**
+** Function         L2CA_DeregisterLECoc
+**
+** Description      Other layers call this function to deregister for L2CAP
+**                  Connection Oriented Channel.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void L2CA_DeregisterLECoc (UINT16 psm);
+
+/*******************************************************************************
+**
+** Function         L2CA_ConnectLECocReq
+**
+** Description      Higher layers call this function to create an L2CAP LE COC.
+**                  Note that the connection is not established at this time, but
+**                  connection establishment gets started. The callback function
+**                  will be invoked when connection establishes or fails.
+**
+** Returns          the CID of the connection, or 0 if it failed to start
+**
+*******************************************************************************/
+extern UINT16 L2CA_ConnectLECocReq (UINT16 psm, BD_ADDR p_bd_addr, tL2CAP_LE_CFG_INFO *p_cfg);
+
+/*******************************************************************************
+**
+** Function         L2CA_ConnectLECocRsp
+**
+** Description      Higher layers call this function to accept an incoming
+**                  L2CAP LE COC connection, for which they had gotten an connect
+**                  indication callback.
+**
+** Returns          TRUE for success, FALSE for failure
+**
+*******************************************************************************/
+extern BOOLEAN L2CA_ConnectLECocRsp (BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid, UINT16 result,
+                                         UINT16 status, tL2CAP_LE_CFG_INFO *p_cfg);
+
+/*******************************************************************************
+**
+**  Function         L2CA_GetPeerLECocConfig
+**
+**  Description      Get peers configuration for LE Connection Oriented Channel.
+**
+**  Return value:    TRUE if peer is connected
+**
+*******************************************************************************/
+extern BOOLEAN L2CA_GetPeerLECocConfig (UINT16 lcid, tL2CAP_LE_CFG_INFO* peer_cfg);
 
 /*******************************************************************************
 **

+ 9 - 0
components/bt/bluedroid/stack/include/l2cdefs.h

@@ -41,6 +41,10 @@
 
 #define L2CAP_CMD_BLE_UPDATE_REQ            0x12
 #define L2CAP_CMD_BLE_UPDATE_RSP            0x13
+#define L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ 0x14
+#define L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES 0x15
+#define L2CAP_CMD_BLE_FLOW_CTRL_CREDIT      0x16
+
 
 
 /* Define some packet and header lengths
@@ -70,6 +74,11 @@
 #define L2CAP_CMD_BLE_UPD_REQ_LEN   8       /* Min and max interval, latency, tout  */
 #define L2CAP_CMD_BLE_UPD_RSP_LEN   2       /* Result                               */
 
+#define L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ_LEN 10 /* LE_PSM, SCID, MTU, MPS, Init Credit */
+#define L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES_LEN 10 /* DCID, MTU, MPS, Init credit, Result */
+#define L2CAP_CMD_BLE_FLOW_CTRL_CREDIT_LEN      4  /* CID, Credit */
+
+
 
 /* Define the packet boundary flags
 */

+ 43 - 1
components/bt/bluedroid/stack/l2cap/include/l2c_int.h

@@ -34,6 +34,17 @@
 
 #define L2CAP_MIN_MTU   48      /* Minimum acceptable MTU is 48 bytes */
 
+/* LE credit based L2CAP connection parameters */
+#define L2CAP_LE_MIN_MTU            23
+#define L2CAP_LE_MIN_MPS            23
+#define L2CAP_LE_MAX_MPS            65533
+#define L2CAP_LE_MIN_CREDIT         0
+#define L2CAP_LE_MAX_CREDIT         65535
+#define L2CAP_LE_DEFAULT_MTU        512
+#define L2CAP_LE_DEFAULT_MPS        23
+#define L2CAP_LE_DEFAULT_CREDIT     1
+
+
 /* Timeouts. Since L2CAP works off a 1-second list, all are in seconds.
 */
 #define L2CAP_LINK_ROLE_SWITCH_TOUT  10           /* 10 seconds */
@@ -240,6 +251,17 @@ typedef struct {
     tL2CAP_APPL_INFO        api;
 } tL2C_RCB;
 
+typedef void (tL2CAP_SEC_CBACK) (BD_ADDR bd_addr, tBT_TRANSPORT trasnport,
+                                void *p_ref_data, tBTM_STATUS result);
+
+typedef struct
+{
+    UINT16                  psm;
+    tBT_TRANSPORT           transport;
+    BOOLEAN                 is_originator;
+    tL2CAP_SEC_CBACK        *p_callback;
+    void                    *p_ref_data;
+}tL2CAP_SEC_DATA;
 
 #ifndef L2CAP_CBB_DEFAULT_DATA_RATE_BUFF_QUOTA
 #define L2CAP_CBB_DEFAULT_DATA_RATE_BUFF_QUOTA 100
@@ -252,6 +274,8 @@ typedef struct {
 typedef struct t_l2c_ccb {
     BOOLEAN             in_use;                 /* TRUE when in use, FALSE when not */
     tL2C_CHNL_STATE     chnl_state;             /* Channel state                    */
+    tL2CAP_LE_CFG_INFO  local_conn_cfg;         /* Our config for ble conn oriented channel */
+    tL2CAP_LE_CFG_INFO  peer_conn_cfg;          /* Peer device config ble conn oriented channel */
 
     struct t_l2c_ccb    *p_next_ccb;            /* Next CCB in the chain            */
     struct t_l2c_ccb    *p_prev_ccb;            /* Previous CCB in the chain        */
@@ -400,7 +424,8 @@ typedef struct t_l2c_linkcb {
 #if (BLE_INCLUDED == TRUE)
     tBLE_ADDR_TYPE      ble_addr_type;
     UINT16              tx_data_len;            /* tx data length used in data length extension */
-
+    fixed_queue_t       *le_sec_pending_q;      /* LE coc channels waiting for security check completion */
+    UINT8               sec_act;
 #define L2C_BLE_CONN_UPDATE_DISABLE 0x1  /* disable update connection parameters */
 #define L2C_BLE_NEW_CONN_PARAM      0x2  /* new connection parameter to be set */
 #define L2C_BLE_UPDATE_PENDING      0x4  /* waiting for connection update finished */
@@ -488,6 +513,7 @@ typedef struct {
     UINT16                   ble_round_robin_quota;              /* Round-robin link quota           */
     UINT16                   ble_round_robin_unacked;            /* Round-robin unacked              */
     BOOLEAN                  ble_check_round_robin;              /* Do a round robin check           */
+    tL2C_RCB                 ble_rcb_pool[BLE_MAX_L2CAP_CLIENTS]; /* Registration info pool          */
 #endif
 
     tL2CA_ECHO_DATA_CB      *p_echo_data_cb;                /* Echo data callback */
@@ -632,6 +658,12 @@ BOOLEAN l2c_ucd_process_event(tL2C_CCB *p_ccb, UINT16 event, void *p_data);
 #if (BLE_INCLUDED == TRUE)
 extern void l2cu_send_peer_ble_par_req (tL2C_LCB *p_lcb, UINT16 min_int, UINT16 max_int, UINT16 latency, UINT16 timeout);
 extern void l2cu_send_peer_ble_par_rsp (tL2C_LCB *p_lcb, UINT16 reason, UINT8 rem_id);
+extern void l2cu_reject_ble_connection (tL2C_LCB *p_lcb, UINT8 rem_id, UINT16 result);
+extern void l2cu_send_peer_ble_credit_based_conn_res (tL2C_CCB *p_ccb, UINT16 result);
+extern void l2cu_send_peer_ble_credit_based_conn_req (tL2C_CCB *p_ccb);
+extern void l2cu_send_peer_ble_flow_control_credit(tL2C_CCB *p_ccb, UINT16 credit_value);
+extern void l2cu_send_peer_ble_credit_based_disconn_req(tL2C_CCB *p_ccb);
+
 #endif
 
 extern BOOLEAN l2cu_initialize_fixed_ccb (tL2C_LCB *p_lcb, UINT16 fixed_cid, tL2CAP_FCR_OPTS *p_fcr);
@@ -649,6 +681,9 @@ extern void     l2cu_send_feature_req (tL2C_CCB *p_ccb);
 extern tL2C_RCB *l2cu_allocate_rcb (UINT16 psm);
 extern tL2C_RCB *l2cu_find_rcb_by_psm (UINT16 psm);
 extern void     l2cu_release_rcb (tL2C_RCB *p_rcb);
+extern tL2C_RCB *l2cu_allocate_ble_rcb (UINT16 psm);
+extern tL2C_RCB *l2cu_find_ble_rcb_by_psm (UINT16 psm);
+
 
 extern UINT8    l2cu_process_peer_cfg_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
 extern void     l2cu_process_peer_cfg_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
@@ -748,6 +783,13 @@ extern void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status, UINT16
                                                               UINT16 conn_latency, UINT16 conn_timeout);
 extern void l2cble_get_conn_param_format_err_from_contoller(UINT8 status, UINT16 handle);
 
+extern void l2cble_credit_based_conn_req (tL2C_CCB *p_ccb);
+extern void l2cble_credit_based_conn_res (tL2C_CCB *p_ccb, UINT16 result);
+extern void l2cble_send_peer_disc_req(tL2C_CCB *p_ccb);
+extern void l2cble_send_flow_control_credit(tL2C_CCB *p_ccb, UINT16 credit_value);
+extern BOOLEAN l2ble_sec_access_req(BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_originator, tL2CAP_SEC_CBACK *p_callback, void *p_ref_data);
+
+
 #if (defined BLE_LLT_INCLUDED) && (BLE_LLT_INCLUDED == TRUE)
 extern void l2cble_process_rc_param_request_evt(UINT16 handle, UINT16 int_min, UINT16 int_max,
         UINT16 latency, UINT16 timeout);

+ 303 - 0
components/bt/bluedroid/stack/l2cap/l2c_api.c

@@ -1293,6 +1293,309 @@ UINT8 L2CA_GetChnlFcrMode (UINT16 lcid)
 
 #endif  ///CLASSIC_BT_INCLUDED == TRUE
 
+/*******************************************************************************
+**
+** Function         L2CA_RegisterLECoc
+**
+** Description      Other layers call this function to register for L2CAP
+**                  Connection Oriented Channel.
+**
+** Returns          PSM to use or zero if error. Typically, the PSM returned
+**                  is the same as was passed in, but for an outgoing-only
+**                  connection to a dynamic PSM, a "virtual" PSM is returned
+**                  and should be used in the calls to L2CA_ConnectLECocReq()
+**                  and L2CA_DeregisterLECoc()
+**
+*******************************************************************************/
+UINT16 L2CA_RegisterLECoc(UINT16 psm, tL2CAP_APPL_INFO *p_cb_info)
+{
+    L2CAP_TRACE_API("%s called for LE PSM: 0x%04x", __func__, psm);
+
+    /* Verify that the required callback info has been filled in
+    **      Note:  Connection callbacks are required but not checked
+    **             for here because it is possible to be only a client
+    **             or only a server.
+    */
+    if ((!p_cb_info->pL2CA_DataInd_Cb)
+     || (!p_cb_info->pL2CA_DisconnectInd_Cb))
+    {
+        L2CAP_TRACE_ERROR("%s No cb registering BLE PSM: 0x%04x", __func__, psm);
+        return 0;
+    }
+
+    /* Verify PSM is valid */
+    if (!L2C_IS_VALID_LE_PSM(psm))
+    {
+        L2CAP_TRACE_ERROR("%s Invalid BLE PSM value, PSM: 0x%04x", __func__, psm);
+        return 0;
+    }
+
+    tL2C_RCB    *p_rcb;
+    UINT16      vpsm = psm;
+
+    /* Check if this is a registration for an outgoing-only connection to */
+    /* a dynamic PSM. If so, allocate a "virtual" PSM for the app to use. */
+    if ((psm >= 0x0080) && (p_cb_info->pL2CA_ConnectInd_Cb == NULL))
+    {
+        for (vpsm = 0x0080; vpsm < 0x0100; vpsm++)
+        {
+            p_rcb = l2cu_find_ble_rcb_by_psm(vpsm);
+            if (p_rcb == NULL)
+                break;
+        }
+
+        L2CAP_TRACE_API("%s Real PSM: 0x%04x  Virtual PSM: 0x%04x", __func__, psm, vpsm);
+    }
+
+    /* If registration block already there, just overwrite it */
+    p_rcb = l2cu_find_ble_rcb_by_psm(vpsm);
+    if (p_rcb == NULL)
+    {
+        p_rcb = l2cu_allocate_ble_rcb(vpsm);
+        if (p_rcb == NULL)
+        {
+            L2CAP_TRACE_WARNING("%s No BLE RCB available, PSM: 0x%04x  vPSM: 0x%04x",
+                  __func__, psm, vpsm);
+            return 0;
+        }
+    }
+
+    p_rcb->api      = *p_cb_info;
+    p_rcb->real_psm = psm;
+
+    return vpsm;
+}
+
+/*******************************************************************************
+**
+** Function         L2CA_DeregisterLECoc
+**
+** Description      Other layers call this function to de-register for L2CAP
+**                  Connection Oriented Channel.
+**
+** Returns          void
+**
+*******************************************************************************/
+void L2CA_DeregisterLECoc(UINT16 psm)
+{
+    L2CAP_TRACE_API("%s called for PSM: 0x%04x", __func__, psm);
+
+    tL2C_RCB *p_rcb = l2cu_find_ble_rcb_by_psm(psm);
+    if (p_rcb == NULL)
+    {
+        L2CAP_TRACE_WARNING("%s PSM: 0x%04x not found for deregistration", __func__, psm);
+        return;
+    }
+
+    tL2C_LCB *p_lcb = &l2cb.lcb_pool[0];
+    for (int i = 0; i < MAX_L2CAP_LINKS; i++, p_lcb++)
+    {
+        if (!p_lcb->in_use || p_lcb->transport != BT_TRANSPORT_LE)
+            continue;
+
+        tL2C_CCB *p_ccb = p_lcb->ccb_queue.p_first_ccb;
+        if ((p_ccb == NULL) || (p_lcb->link_state == LST_DISCONNECTING))
+            continue;
+
+        if (p_ccb->in_use &&
+           (p_ccb->chnl_state == CST_W4_L2CAP_DISCONNECT_RSP ||
+            p_ccb->chnl_state == CST_W4_L2CA_DISCONNECT_RSP))
+            continue;
+
+        if (p_ccb->p_rcb == p_rcb)
+            l2c_csm_execute(p_ccb, L2CEVT_L2CA_DISCONNECT_REQ, NULL);
+    }
+
+    l2cu_release_rcb (p_rcb);
+}
+
+/*******************************************************************************
+**
+** Function         L2CA_ConnectLECocReq
+**
+** Description      Higher layers call this function to create an L2CAP connection.
+**                  Note that the connection is not established at this time, but
+**                  connection establishment gets started. The callback function
+**                  will be invoked when connection establishes or fails.
+**
+**  Parameters:     PSM: L2CAP PSM for the connection
+**                  BD address of the peer
+**                  Local Coc configurations
+
+** Returns          the CID of the connection, or 0 if it failed to start
+**
+*******************************************************************************/
+UINT16 L2CA_ConnectLECocReq(UINT16 psm, BD_ADDR p_bd_addr, tL2CAP_LE_CFG_INFO *p_cfg)
+{
+    L2CAP_TRACE_API("%s PSM: 0x%04x BDA: %02x:%02x:%02x:%02x:%02x:%02x", __func__, psm,
+        p_bd_addr[0], p_bd_addr[1], p_bd_addr[2], p_bd_addr[3], p_bd_addr[4], p_bd_addr[5]);
+
+    /* Fail if we have not established communications with the controller */
+    if (!BTM_IsDeviceUp())
+    {
+        L2CAP_TRACE_WARNING("%s BTU not ready", __func__);
+        return 0;
+    }
+
+    /* Fail if the PSM is not registered */
+    tL2C_RCB *p_rcb = l2cu_find_ble_rcb_by_psm(psm);
+    if (p_rcb == NULL)
+    {
+        L2CAP_TRACE_WARNING("%s No BLE RCB, PSM: 0x%04x", __func__, psm);
+        return 0;
+    }
+
+    /* First, see if we already have a le link to the remote */
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_LE);
+    if (p_lcb == NULL)
+    {
+        /* No link. Get an LCB and start link establishment */
+        p_lcb = l2cu_allocate_lcb(p_bd_addr, FALSE, BT_TRANSPORT_LE);
+        if ((p_lcb == NULL)
+             /* currently use BR/EDR for ERTM mode l2cap connection */
+         || (l2cu_create_conn(p_lcb, BT_TRANSPORT_LE) == FALSE) )
+        {
+            L2CAP_TRACE_WARNING("%s conn not started for PSM: 0x%04x  p_lcb: 0x%p",
+                __func__, psm, p_lcb);
+            return 0;
+        }
+    }
+
+    /* Allocate a channel control block */
+    tL2C_CCB *p_ccb = l2cu_allocate_ccb(p_lcb, 0);
+    if (p_ccb == NULL)
+    {
+        L2CAP_TRACE_WARNING("%s no CCB, PSM: 0x%04x", __func__, psm);
+        return 0;
+    }
+
+    /* Save registration info */
+    p_ccb->p_rcb = p_rcb;
+
+    /* Save the configuration */
+    if (p_cfg)
+        memcpy(&p_ccb->local_conn_cfg, p_cfg, sizeof(tL2CAP_LE_CFG_INFO));
+
+    /* If link is up, start the L2CAP connection */
+    if (p_lcb->link_state == LST_CONNECTED)
+    {
+        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+        {
+            L2CAP_TRACE_DEBUG("%s LE Link is up", __func__);
+            l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_REQ, NULL);
+        }
+    }
+
+    /* If link is disconnecting, save link info to retry after disconnect
+     * Possible Race condition when a reconnect occurs
+     * on the channel during a disconnect of link. This
+     * ccb will be automatically retried after link disconnect
+     * arrives
+     */
+    else if (p_lcb->link_state == LST_DISCONNECTING)
+    {
+        L2CAP_TRACE_DEBUG("%s link disconnecting: RETRY LATER", __func__);
+
+        /* Save ccb so it can be started after disconnect is finished */
+        p_lcb->p_pending_ccb = p_ccb;
+    }
+
+    L2CAP_TRACE_API("%s(psm: 0x%04x) returned CID: 0x%04x", __func__, psm, p_ccb->local_cid);
+
+    /* Return the local CID as our handle */
+    return p_ccb->local_cid;
+}
+
+/*******************************************************************************
+**
+** Function         L2CA_ConnectLECocRsp
+**
+** Description      Higher layers call this function to accept an incoming
+**                  L2CAP COC connection, for which they had gotten an connect
+**                  indication callback.
+**
+** Returns          TRUE for success, FALSE for failure
+**
+*******************************************************************************/
+BOOLEAN L2CA_ConnectLECocRsp (BD_ADDR p_bd_addr, UINT8 id, UINT16 lcid, UINT16 result,
+                             UINT16 status, tL2CAP_LE_CFG_INFO *p_cfg)
+{
+    L2CAP_TRACE_API("%s CID: 0x%04x Result: %d Status: %d BDA: %02x:%02x:%02x:%02x:%02x:%02x",
+        __func__, lcid, result, status,
+        p_bd_addr[0], p_bd_addr[1], p_bd_addr[2], p_bd_addr[3], p_bd_addr[4], p_bd_addr[5]);
+
+
+    /* First, find the link control block */
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_LE);
+    if (p_lcb == NULL)
+    {
+        /* No link. Get an LCB and start link establishment */
+        L2CAP_TRACE_WARNING("%s no LCB", __func__);
+        return FALSE;
+    }
+
+    /* Now, find the channel control block */
+    tL2C_CCB *p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+    if (p_ccb == NULL)
+    {
+        L2CAP_TRACE_WARNING("%s no CCB", __func__);
+        return FALSE;
+    }
+
+    /* The IDs must match */
+    if (p_ccb->remote_id != id)
+    {
+        L2CAP_TRACE_WARNING("%s bad id. Expected: %d  Got: %d", __func__, p_ccb->remote_id, id);
+        return FALSE;
+    }
+
+    if (p_cfg)
+        memcpy(&p_ccb->local_conn_cfg, p_cfg, sizeof(tL2CAP_LE_CFG_INFO));
+
+    if (result == L2CAP_CONN_OK)
+        l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONNECT_RSP, NULL);
+    else
+    {
+        tL2C_CONN_INFO conn_info;
+        memcpy(conn_info.bd_addr, p_bd_addr, BD_ADDR_LEN);
+        conn_info.l2cap_result = result;
+        conn_info.l2cap_status = status;
+        l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_RSP_NEG, &conn_info);
+    }
+
+    return TRUE;
+}
+
+/*******************************************************************************
+**
+**  Function         L2CA_GetPeerLECocConfig
+**
+**  Description      Get a peers configuration for LE Connection Oriented Channel.
+**
+**  Parameters:      local channel id
+**                   Pointers to peers configuration storage area
+**
+**  Return value:    TRUE if peer is connected
+**
+*******************************************************************************/
+BOOLEAN L2CA_GetPeerLECocConfig (UINT16 lcid, tL2CAP_LE_CFG_INFO* peer_cfg)
+{
+    L2CAP_TRACE_API ("%s CID: 0x%04x", __func__, lcid);
+
+    tL2C_CCB *p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);
+    if (p_ccb == NULL)
+    {
+        L2CAP_TRACE_ERROR("%s No CCB for CID:0x%04x", __func__, lcid);
+        return FALSE;
+    }
+
+    if (peer_cfg != NULL)
+        memcpy(peer_cfg, &p_ccb->peer_conn_cfg, sizeof(tL2CAP_LE_CFG_INFO));
+
+    return TRUE;
+}
+
+
 
 #if (L2CAP_NUM_FIXED_CHNLS > 0)
 /*******************************************************************************

+ 235 - 0
components/bt/bluedroid/stack/l2cap/l2c_ble.c

@@ -1203,4 +1203,239 @@ UINT32 CalConnectParamTimeout(tL2C_LCB *p_lcb)
     return timeout;
 }
 
+/*******************************************************************************
+**
+** Function         l2cble_credit_based_conn_req
+**
+** Description      This function sends LE Credit Based Connection Request for
+**                  LE connection oriented channels.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_credit_based_conn_req (tL2C_CCB *p_ccb)
+{
+    if (!p_ccb)
+        return;
+
+    if (p_ccb->p_lcb && p_ccb->p_lcb->transport != BT_TRANSPORT_LE)
+    {
+        L2CAP_TRACE_WARNING ("LE link doesn't exist");
+        return;
+    }
+
+    l2cu_send_peer_ble_credit_based_conn_req (p_ccb);
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_credit_based_conn_res
+**
+** Description      This function sends LE Credit Based Connection Response for
+**                  LE connection oriented channels.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_credit_based_conn_res (tL2C_CCB *p_ccb, UINT16 result)
+{
+    if (!p_ccb)
+        return;
+
+    if (p_ccb->p_lcb && p_ccb->p_lcb->transport != BT_TRANSPORT_LE)
+    {
+        L2CAP_TRACE_WARNING ("LE link doesn't exist");
+        return;
+    }
+
+    l2cu_send_peer_ble_credit_based_conn_res (p_ccb, result);
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_send_flow_control_credit
+**
+** Description      This function sends flow control credits for
+**                  LE connection oriented channels.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_send_flow_control_credit(tL2C_CCB *p_ccb, UINT16 credit_value)
+{
+    if (!p_ccb)
+        return;
+
+    if (p_ccb->p_lcb && p_ccb->p_lcb->transport != BT_TRANSPORT_LE)
+    {
+        L2CAP_TRACE_WARNING ("LE link doesn't exist");
+        return;
+    }
+
+    l2cu_send_peer_ble_flow_control_credit(p_ccb, credit_value);
+    return;
+
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_send_peer_disc_req
+**
+** Description      This function sends disconnect request
+**                  to the peer LE device
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_send_peer_disc_req(tL2C_CCB *p_ccb)
+{
+    L2CAP_TRACE_DEBUG ("%s",__func__);
+    if (!p_ccb)
+        return;
+
+    if (p_ccb->p_lcb && p_ccb->p_lcb->transport != BT_TRANSPORT_LE)
+    {
+        L2CAP_TRACE_WARNING ("LE link doesn't exist");
+        return;
+    }
+
+    l2cu_send_peer_ble_credit_based_disconn_req(p_ccb);
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_sec_comp
+**
+** Description      This function is called when security procedure for an LE COC
+**                  link is done
+**
+** Returns          void
+**
+*******************************************************************************/
+void  l2cble_sec_comp(BD_ADDR p_bda, tBT_TRANSPORT transport, void *p_ref_data, UINT8 status)
+{
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(p_bda, BT_TRANSPORT_LE);
+    tL2CAP_SEC_DATA *p_buf = NULL;
+    UINT8 sec_flag;
+    UINT8 sec_act;
+
+    if (!p_lcb)
+    {
+        L2CAP_TRACE_WARNING ("%s security complete for unknown device", __func__);
+        return;
+    }
+
+    sec_act = p_lcb->sec_act;
+    p_lcb->sec_act = 0;
+
+    if (!fixed_queue_is_empty(p_lcb->le_sec_pending_q))
+    {
+        p_buf = (tL2CAP_SEC_DATA*) fixed_queue_dequeue(p_lcb->le_sec_pending_q);
+        if (!p_buf)
+        {
+            L2CAP_TRACE_WARNING ("%s Security complete for request not initiated from L2CAP",
+                    __func__);
+            return;
+        }
+
+        if (status != BTM_SUCCESS)
+        {
+            (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data, status);
+        }
+        else
+        {
+            if (sec_act == BTM_SEC_ENCRYPT_MITM)
+            {
+                BTM_GetSecurityFlagsByTransport(p_bda, &sec_flag, transport);
+                if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED)
+                    (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data, status);
+                else
+                {
+                    L2CAP_TRACE_DEBUG ("%s MITM Protection Not present", __func__);
+                    (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data,
+                            BTM_FAILED_ON_SECURITY);
+                }
+            }
+            else
+            {
+                L2CAP_TRACE_DEBUG ("%s MITM Protection not required sec_act = %d",
+                        __func__, p_lcb->sec_act);
+
+                (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data, status);
+            }
+        }
+    }
+    else
+    {
+        L2CAP_TRACE_WARNING ("%s Security complete for request not initiated from L2CAP", __func__);
+        return;
+    }
+    osi_free(p_buf);
+
+    while (!fixed_queue_is_empty(p_lcb->le_sec_pending_q))
+    {
+        p_buf = (tL2CAP_SEC_DATA*) fixed_queue_dequeue(p_lcb->le_sec_pending_q);
+
+        if (status != BTM_SUCCESS)
+            (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data, status);
+        else
+            l2ble_sec_access_req(p_bda, p_buf->psm, p_buf->is_originator,
+                    p_buf->p_callback, p_buf->p_ref_data);
+
+       osi_free(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2ble_sec_access_req
+**
+** Description      This function is called by LE COC link to meet the
+**                  security requirement for the link
+**
+** Returns          TRUE - security procedures are started
+**                  FALSE - failure
+**
+*******************************************************************************/
+BOOLEAN l2ble_sec_access_req(BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_originator, tL2CAP_SEC_CBACK *p_callback, void *p_ref_data)
+{
+    L2CAP_TRACE_DEBUG ("%s", __func__);
+    BOOLEAN status;
+    tL2C_LCB *p_lcb = NULL;
+
+    if (!p_callback)
+    {
+        L2CAP_TRACE_ERROR("%s No callback function", __func__);
+        return FALSE;
+    }
+
+    p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
+
+    if (!p_lcb)
+    {
+        L2CAP_TRACE_ERROR ("%s Security check for unknown device", __func__);
+        p_callback(bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_UNKNOWN_ADDR);
+        return FALSE;
+    }
+
+    tL2CAP_SEC_DATA *p_buf = (tL2CAP_SEC_DATA*) osi_malloc((UINT16)sizeof(tL2CAP_SEC_DATA));
+    if (!p_buf)
+    {
+        p_callback(bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_NO_RESOURCES);
+        return FALSE;
+    }
+
+    p_buf->psm = psm;
+    p_buf->is_originator = is_originator;
+    p_buf->p_callback = p_callback;
+    p_buf->p_ref_data = p_ref_data;
+    fixed_queue_enqueue(p_lcb->le_sec_pending_q, p_buf);
+    status = btm_ble_start_sec_check(bd_addr, psm, is_originator, &l2cble_sec_comp, p_ref_data);
+
+    return status;
+}
+
 #endif /* (BLE_INCLUDED == TRUE) */

+ 15 - 0
components/bt/bluedroid/stack/l2cap/l2c_main.c

@@ -122,6 +122,7 @@ void l2c_rcv_acl_data (BT_HDR *p_msg)
     tL2C_LCB    *p_lcb;
     tL2C_CCB    *p_ccb = NULL;
     UINT16      l2cap_len, rcv_cid, psm;
+    UINT16      credit;
 
     /* Extract the handle */
     STREAM_TO_UINT16 (handle, p);
@@ -275,6 +276,20 @@ void l2c_rcv_acl_data (BT_HDR *p_msg)
         if (p_ccb == NULL) {
             osi_free (p_msg);
         } else {
+            if (p_lcb->transport == BT_TRANSPORT_LE) {
+                // Got a pkt, valid send out credits to the peer device
+                credit = L2CAP_LE_DEFAULT_CREDIT;
+                L2CAP_TRACE_DEBUG("%s Credits received %d",__func__, credit);
+                if((p_ccb->peer_conn_cfg.credits + credit) > L2CAP_LE_MAX_CREDIT) {
+                    /* we have received credits more than max coc credits,
+                     * so disconnecting the Le Coc Channel
+                     */
+                    l2cble_send_peer_disc_req (p_ccb);
+                } else {
+                    p_ccb->peer_conn_cfg.credits += credit;
+                    l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
+                }
+            }
             /* Basic mode packets go straight to the state machine */
             if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE) {
 #if (CLASSIC_BT_INCLUDED == TRUE)

+ 281 - 0
components/bt/bluedroid/stack/l2cap/l2c_utils.c

@@ -71,6 +71,7 @@ tL2C_LCB *l2cu_allocate_lcb (BD_ADDR p_bd_addr, BOOLEAN is_bonding, tBT_TRANSPOR
 #if (BLE_INCLUDED == TRUE)
             p_lcb->transport       = transport;
             p_lcb->tx_data_len     = controller_get_interface()->get_ble_default_data_packet_length();
+            p_lcb->le_sec_pending_q = fixed_queue_new(SIZE_MAX);
 
             if (transport == BT_TRANSPORT_LE) {
                 l2cb.num_ble_links_active++;
@@ -228,6 +229,20 @@ void l2cu_release_lcb (tL2C_LCB *p_lcb)
 
         (*p_cb) (L2CAP_PING_RESULT_NO_LINK);
     }
+
+	/* Check and release all the LE COC connections waiting for security */
+    if (p_lcb->le_sec_pending_q)
+    {
+        while (!fixed_queue_is_empty(p_lcb->le_sec_pending_q))
+        {
+            tL2CAP_SEC_DATA *p_buf = (tL2CAP_SEC_DATA*) fixed_queue_dequeue(p_lcb->le_sec_pending_q);
+            if (p_buf->p_callback)
+                p_buf->p_callback(p_lcb->remote_bd_addr, p_lcb->transport, p_buf->p_ref_data, BTM_DEV_RESET);
+            osi_free(p_buf);
+        }
+        fixed_queue_free(p_lcb->le_sec_pending_q, NULL);
+        p_lcb->le_sec_pending_q = NULL;
+    }
 }
 
 
@@ -1720,6 +1735,37 @@ tL2C_RCB *l2cu_allocate_rcb (UINT16 psm)
     return (NULL);
 }
 
+/*******************************************************************************
+**
+** Function         l2cu_allocate_ble_rcb
+**
+** Description      Look through the BLE Registration Control Blocks for a free
+**                  one.
+**
+** Returns          Pointer to the BLE RCB or NULL if not found
+**
+*******************************************************************************/
+tL2C_RCB *l2cu_allocate_ble_rcb (UINT16 psm)
+{
+    tL2C_RCB    *p_rcb = &l2cb.ble_rcb_pool[0];
+    UINT16      xx;
+
+    for (xx = 0; xx < BLE_MAX_L2CAP_CLIENTS; xx++, p_rcb++)
+    {
+        if (!p_rcb->in_use)
+        {
+            p_rcb->in_use = TRUE;
+            p_rcb->psm    = psm;
+#if (L2CAP_UCD_INCLUDED == TRUE)
+            p_rcb->ucd.state = L2C_UCD_STATE_UNUSED;
+#endif
+            return (p_rcb);
+        }
+    }
+
+    /* If here, no free RCB found */
+    return (NULL);
+}
 
 /*******************************************************************************
 **
@@ -1791,6 +1837,32 @@ tL2C_RCB *l2cu_find_rcb_by_psm (UINT16 psm)
     return (NULL);
 }
 
+/*******************************************************************************
+**
+** Function         l2cu_find_ble_rcb_by_psm
+**
+** Description      Look through the BLE Registration Control Blocks to see if
+**                  anyone registered to handle the PSM in question
+**
+** Returns          Pointer to the BLE RCB or NULL if not found
+**
+*******************************************************************************/
+tL2C_RCB *l2cu_find_ble_rcb_by_psm (UINT16 psm)
+{
+    tL2C_RCB    *p_rcb = &l2cb.ble_rcb_pool[0];
+    UINT16      xx;
+
+    for (xx = 0; xx < BLE_MAX_L2CAP_CLIENTS; xx++, p_rcb++)
+    {
+        if ((p_rcb->in_use) && (p_rcb->psm == psm))
+            return (p_rcb);
+    }
+
+    /* If here, no match found */
+    return (NULL);
+}
+
+
 
 /*******************************************************************************
 **
@@ -2841,6 +2913,215 @@ void l2cu_send_peer_ble_par_rsp (tL2C_LCB *p_lcb, UINT16 reason, UINT8 rem_id)
     l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
 }
 
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_ble_credit_based_conn_req
+**
+** Description      Build and send a BLE packet to establish LE connection oriented
+**                  L2CAP channel.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_ble_credit_based_conn_req (tL2C_CCB *p_ccb)
+{
+    BT_HDR  *p_buf;
+    UINT8   *p;
+    tL2C_LCB *p_lcb = NULL;
+    UINT16 mtu;
+    UINT16 mps;
+    UINT16 initial_credit;
+
+    if (!p_ccb)
+        return;
+    p_lcb = p_ccb->p_lcb;
+
+    /* Create an identifier for this packet */
+    p_ccb->p_lcb->id++;
+    l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+    p_ccb->local_id = p_ccb->p_lcb->id;
+
+    if ((p_buf = l2cu_build_header (p_lcb, L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ_LEN,
+                    L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ, p_lcb->id)) == NULL )
+    {
+        L2CAP_TRACE_WARNING ("l2cu_send_peer_ble_credit_based_conn_req - no buffer");
+        return;
+    }
+
+    p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+                               L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    mtu = p_ccb->local_conn_cfg.mtu;
+    mps = p_ccb->local_conn_cfg.mps;
+    initial_credit = p_ccb->local_conn_cfg.credits;
+
+    L2CAP_TRACE_DEBUG ("l2cu_send_peer_ble_credit_based_conn_req PSM:0x%04x local_cid:%d\
+                mtu:%d mps:%d initial_credit:%d", p_ccb->p_rcb->real_psm,\
+                p_ccb->local_cid, mtu, mps, initial_credit);
+
+    UINT16_TO_STREAM (p, p_ccb->p_rcb->real_psm);
+    UINT16_TO_STREAM (p, p_ccb->local_cid);
+    UINT16_TO_STREAM (p, mtu);
+    UINT16_TO_STREAM (p, mps);
+    UINT16_TO_STREAM (p, initial_credit);
+
+    l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_reject_ble_connection
+**
+** Description      Build and send an L2CAP "Credit based connection res" message
+**                  to the peer. This function is called for non-success cases.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_reject_ble_connection (tL2C_LCB *p_lcb, UINT8 rem_id, UINT16 result)
+{
+    BT_HDR  *p_buf;
+    UINT8   *p;
+
+    if ((p_buf = l2cu_build_header(p_lcb, L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES_LEN,
+                    L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES, rem_id)) == NULL )
+    {
+        L2CAP_TRACE_WARNING ("l2cu_reject_ble_connection - no buffer");
+        return;
+    }
+
+    p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+                               L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, 0);                    /* Local CID of 0   */
+    UINT16_TO_STREAM (p, 0);                    /* MTU */
+    UINT16_TO_STREAM (p, 0);                    /* MPS */
+    UINT16_TO_STREAM (p, 0);                    /* initial credit */
+    UINT16_TO_STREAM (p, result);
+
+    l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_ble_credit_based_conn_res
+**
+** Description      Build and send an L2CAP "Credit based connection res" message
+**                  to the peer. This function is called in case of success.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_ble_credit_based_conn_res (tL2C_CCB *p_ccb, UINT16 result)
+{
+    BT_HDR  *p_buf;
+    UINT8   *p;
+
+    L2CAP_TRACE_DEBUG ("l2cu_send_peer_ble_credit_based_conn_res");
+    if ((p_buf = l2cu_build_header(p_ccb->p_lcb, L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES_LEN,
+                    L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES, p_ccb->remote_id)) == NULL )
+    {
+        L2CAP_TRACE_WARNING ("l2cu_send_peer_ble_credit_based_conn_res - no buffer");
+        return;
+    }
+
+    p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+                               L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, p_ccb->local_cid);                      /* Local CID */
+    UINT16_TO_STREAM (p, p_ccb->local_conn_cfg.mtu);             /* MTU */
+    UINT16_TO_STREAM (p, p_ccb->local_conn_cfg.mps);             /* MPS */
+    UINT16_TO_STREAM (p, p_ccb->local_conn_cfg.credits);         /* initial credit */
+    UINT16_TO_STREAM (p, result);
+
+    l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_ble_flow_control_credit
+**
+** Description      Build and send a BLE packet to give credits to peer device
+**                  for LE connection oriented L2CAP channel.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_ble_flow_control_credit(tL2C_CCB *p_ccb, UINT16 credit_value)
+{
+    BT_HDR  *p_buf;
+    UINT8   *p;
+    tL2C_LCB *p_lcb = NULL;
+
+    if (!p_ccb)
+        return;
+    p_lcb = p_ccb->p_lcb;
+
+    /* Create an identifier for this packet */
+    p_ccb->p_lcb->id++;
+    l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+    p_ccb->local_id = p_ccb->p_lcb->id;
+
+    if ((p_buf = l2cu_build_header (p_lcb, L2CAP_CMD_BLE_FLOW_CTRL_CREDIT_LEN,
+                    L2CAP_CMD_BLE_FLOW_CTRL_CREDIT, p_lcb->id)) == NULL )
+    {
+        L2CAP_TRACE_WARNING ("l2cu_send_peer_ble_credit_based_conn_req - no buffer");
+        return;
+    }
+
+    p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+                               L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, p_ccb->local_cid);
+    UINT16_TO_STREAM (p, credit_value);
+
+    l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_ble_credit_based_conn_req
+**
+** Description      Build and send a BLE packet to disconnect LE connection oriented
+**                  L2CAP channel.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_ble_credit_based_disconn_req(tL2C_CCB *p_ccb)
+{
+    BT_HDR  *p_buf;
+    UINT8   *p;
+    tL2C_LCB *p_lcb = NULL;
+    L2CAP_TRACE_DEBUG ("%s",__func__);
+
+    if (!p_ccb)
+        return;
+    p_lcb = p_ccb->p_lcb;
+
+    /* Create an identifier for this packet */
+    p_ccb->p_lcb->id++;
+    l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+    p_ccb->local_id = p_ccb->p_lcb->id;
+     if ((p_buf = l2cu_build_header (p_lcb, L2CAP_DISC_REQ_LEN,
+                    L2CAP_CMD_DISC_REQ, p_lcb->id)) == NULL )
+    {
+        L2CAP_TRACE_WARNING ("l2cu_send_peer_ble_credit_based_disconn_req - no buffer");
+        return;
+    }
+
+    p = (UINT8 *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+                               L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, p_ccb->remote_cid);
+    UINT16_TO_STREAM (p,p_ccb->local_cid);
+
+    l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
 #endif /* BLE_INCLUDED == TRUE */