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

This commit is contained in:
Yulong 2017-08-08 03:32:59 -04:00
parent aad24cb6c7
commit 371c55138e
11 changed files with 1160 additions and 13 deletions

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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);
/*******************************************************************************
**

View file

@ -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
*/

View file

@ -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);

View file

@ -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)
/*******************************************************************************

View file

@ -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) */

View file

@ -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)

View file

@ -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 */