mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
Merge branch 'fix/aireview_obex_v5.4' into 'release/v5.4'
fix(bt_obex): fix some bugs in bluedroid obex (v5.4) See merge request espressif/esp-idf!52305
This commit is contained in:
@@ -162,7 +162,9 @@ void bta_av_ca_goep_event_handler(UINT16 handle, UINT8 event, tGOEPC_MSG *p_msg)
|
||||
tBTA_AV_DATA *p_data = NULL;
|
||||
UINT16 rcb_idx;
|
||||
|
||||
if (p_msg == NULL) {
|
||||
if (p_msg == NULL && (event == GOEPC_OPENED_EVT ||
|
||||
event == GOEPC_CLOSED_EVT ||
|
||||
event == GOEPC_RESPONSE_EVT)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -54,6 +54,13 @@ void GOEPC_Deinit(void)
|
||||
{
|
||||
#if (GOEP_DYNAMIC_MEMORY)
|
||||
if (goepc_cb_ptr) {
|
||||
#endif
|
||||
for (int i = 0; i < GOEPC_MAX_CONNECTION; ++i) {
|
||||
if (goepc_cb.ccb[i].allocated) {
|
||||
GOEPC_Close(goepc_cb.ccb[i].allocated);
|
||||
}
|
||||
}
|
||||
#if (GOEP_DYNAMIC_MEMORY)
|
||||
osi_free(goepc_cb_ptr);
|
||||
goepc_cb_ptr = NULL;
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ static void goepc_sm_act_connect(tGOEPC_CCB *p_ccb, tGOEPC_CONNECTED *connected)
|
||||
|
||||
static void goepc_sm_act_disconnect(tGOEPC_CCB *p_ccb)
|
||||
{
|
||||
tGOEPC_MSG msg;
|
||||
tGOEPC_MSG msg = {0};
|
||||
if (p_ccb->obex_handle) {
|
||||
OBEX_RemoveConn(p_ccb->obex_handle);
|
||||
}
|
||||
@@ -510,7 +510,7 @@ static void goepc_srm_sm_act_req(tGOEPC_CCB *p_ccb, BOOLEAN srm_en, BOOLEAN srm_
|
||||
}
|
||||
break;
|
||||
case GOEPC_SRM_STATE_ENABLE_WAIT:
|
||||
if (!srm_wait) {
|
||||
if (!srm_wait){
|
||||
p_ccb->srm_wait = FALSE;
|
||||
}
|
||||
if (!p_ccb->srm_wait && !p_ccb->srm_peer_wait) {
|
||||
@@ -545,7 +545,7 @@ static void goepc_srm_sm_act_rsp(tGOEPC_CCB *p_ccb, BOOLEAN srm_en, BOOLEAN srm_
|
||||
}
|
||||
break;
|
||||
case GOEPC_SRM_STATE_ENABLE_WAIT:
|
||||
if (!srm_wait) {
|
||||
if (!srm_wait){
|
||||
p_ccb->srm_peer_wait = FALSE;
|
||||
}
|
||||
if (!p_ccb->srm_wait && !p_ccb->srm_peer_wait) {
|
||||
|
||||
@@ -135,6 +135,10 @@ UINT16 OBEX_CreateConn(tOBEX_SVR_INFO *server, tOBEX_MSG_CBACK callback, UINT16
|
||||
tOBEX_TL_SVR_INFO tl_server = {0};
|
||||
obex_server_to_tl_server(server, &tl_server);
|
||||
p_ccb->tl = server->tl;
|
||||
if (obex_cb.tl_ops[p_ccb->tl] == NULL){
|
||||
ret = OBEX_ERROR_TL;
|
||||
break;
|
||||
}
|
||||
p_ccb->tl_hdl = obex_cb.tl_ops[p_ccb->tl]->connect(&tl_server);
|
||||
if (p_ccb->tl_hdl == 0) {
|
||||
ret = OBEX_ERROR_TL;
|
||||
@@ -195,7 +199,7 @@ UINT16 OBEX_RegisterServer(tOBEX_SVR_INFO *server, tOBEX_MSG_CBACK callback, UIN
|
||||
tOBEX_SCB *p_scb = NULL;
|
||||
|
||||
do {
|
||||
if (server->tl >= OBEX_NUM_TL) {
|
||||
if (!server || server->tl >= OBEX_NUM_TL || obex_cb.tl_ops[server->tl] == NULL) {
|
||||
ret = OBEX_INVALID_PARAM;
|
||||
break;
|
||||
}
|
||||
@@ -322,12 +326,31 @@ UINT16 OBEX_SendPacket(UINT16 handle, BT_HDR *pkt)
|
||||
*******************************************************************************/
|
||||
UINT16 OBEX_BuildRequest(tOBEX_PARSE_INFO *info, UINT16 buff_size, BT_HDR **out_pkt)
|
||||
{
|
||||
if (buff_size < OBEX_MIN_PACKET_SIZE || info == NULL || out_pkt == NULL) {
|
||||
if (info == NULL || out_pkt == NULL) {
|
||||
return OBEX_INVALID_PARAM;
|
||||
}
|
||||
if (UINT16_MAX - buff_size < sizeof(BT_HDR) + OBEX_BT_HDR_MIN_OFFSET) {
|
||||
return OBEX_NO_RESOURCES;
|
||||
}
|
||||
switch (info->opcode)
|
||||
{
|
||||
case OBEX_OPCODE_CONNECT:
|
||||
if (buff_size < OBEX_MIN_PACKET_SIZE + 4){
|
||||
return OBEX_INVALID_PARAM;
|
||||
}
|
||||
break;
|
||||
case OBEX_OPCODE_SETPATH:
|
||||
if (buff_size < OBEX_MIN_PACKET_SIZE + 2){
|
||||
return OBEX_INVALID_PARAM;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (buff_size < OBEX_MIN_PACKET_SIZE){
|
||||
return OBEX_INVALID_PARAM;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
buff_size += sizeof(BT_HDR) + OBEX_BT_HDR_MIN_OFFSET;
|
||||
|
||||
BT_HDR *p_buf = (BT_HDR *)osi_malloc(buff_size);
|
||||
@@ -469,7 +492,7 @@ UINT16 OBEX_AppendHeader(BT_HDR *pkt, const UINT8 *header)
|
||||
return OBEX_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (pkt->layer_specific - pkt->len < header_len) {
|
||||
if (pkt->layer_specific <= pkt->len || pkt->layer_specific - pkt->len < header_len) {
|
||||
/* the packet can not hold this header */
|
||||
return OBEX_NO_RESOURCES;
|
||||
}
|
||||
@@ -510,6 +533,9 @@ UINT16 OBEX_AppendHeaderRaw(BT_HDR *pkt, UINT8 header_id, const UINT8 *data, UIN
|
||||
case OBEX_HEADER_ID_U2B_TYPE1:
|
||||
case OBEX_HEADER_ID_U2B_TYPE2:
|
||||
/* header id + 2 byte length prefixed + data */
|
||||
if (data_len > UINT16_MAX - 3){
|
||||
return OBEX_NO_RESOURCES;
|
||||
}
|
||||
header_len = data_len + 3;
|
||||
store_header_len = TRUE;
|
||||
break;
|
||||
@@ -532,7 +558,7 @@ UINT16 OBEX_AppendHeaderRaw(BT_HDR *pkt, UINT8 header_id, const UINT8 *data, UIN
|
||||
return OBEX_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (pkt->layer_specific - pkt->len < header_len) {
|
||||
if (pkt->layer_specific <= pkt->len || pkt->layer_specific - pkt->len < header_len) {
|
||||
/* the packet can not hold this header */
|
||||
return OBEX_NO_RESOURCES;
|
||||
}
|
||||
@@ -596,7 +622,7 @@ UINT16 OBEX_AppendHeaderSRMP(BT_HDR *pkt, UINT8 value)
|
||||
*******************************************************************************/
|
||||
UINT16 OBEX_GetPacketFreeSpace(BT_HDR *pkt)
|
||||
{
|
||||
if (pkt == NULL) {
|
||||
if (pkt == NULL || pkt->layer_specific < pkt->len) {
|
||||
return 0;
|
||||
}
|
||||
return pkt->layer_specific - pkt->len;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#if (OBEX_INCLUDED == TRUE)
|
||||
|
||||
_Static_assert(OBEX_MAX_SERVER <= 254, "OBEX_MAX_SERVER must not exceed 254 to prevent overflow.");
|
||||
|
||||
#if OBEX_DYNAMIC_MEMORY == FALSE
|
||||
tOBEX_CB obex_cb;
|
||||
#else
|
||||
@@ -88,12 +90,14 @@ void obex_free_scb(tOBEX_SCB *p_scb)
|
||||
static bool check_conn_mtu_valid(tOBEX_CCB *p_ccb, BOOLEAN call_cb)
|
||||
{
|
||||
if (p_ccb->tl_our_mtu < 255 || p_ccb->tl_peer_mtu < 255) {
|
||||
if (call_cb && p_ccb->callback) {
|
||||
p_ccb->callback(p_ccb->allocated, OBEX_DISCONNECT_EVT, NULL);
|
||||
}
|
||||
OBEX_TRACE_ERROR("Check OBEX transport layer MTU failed, disconnect");
|
||||
tOBEX_MSG_CBACK *cb = p_ccb->callback;
|
||||
UINT8 alloc = p_ccb->allocated;
|
||||
obex_cb.tl_ops[p_ccb->tl]->disconnect(p_ccb->tl_hdl);
|
||||
obex_free_ccb(p_ccb);
|
||||
if (call_cb && cb) {
|
||||
cb(alloc, OBEX_DISCONNECT_EVT, NULL);
|
||||
}
|
||||
OBEX_TRACE_ERROR("Check OBEX transport layer MTU failed, disconnect");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -109,7 +113,9 @@ void obex_tl_evt_handler(UINT8 tl, tOBEX_TL_EVT evt, tOBEX_TL_MSG *msg)
|
||||
switch (evt)
|
||||
{
|
||||
case OBEX_TL_CONN_OPEN_EVT:
|
||||
assert(p_ccb != NULL);
|
||||
if (p_ccb == NULL) {
|
||||
break;
|
||||
}
|
||||
p_ccb->tl_peer_mtu = msg->conn_open.peer_mtu;
|
||||
p_ccb->tl_our_mtu = msg->conn_open.our_mtu;
|
||||
if (!check_conn_mtu_valid(p_ccb, TRUE)) {
|
||||
@@ -131,19 +137,25 @@ void obex_tl_evt_handler(UINT8 tl, tOBEX_TL_EVT evt, tOBEX_TL_MSG *msg)
|
||||
}
|
||||
break;
|
||||
case OBEX_TL_CONGEST_EVT:
|
||||
assert(p_ccb != NULL);
|
||||
if (p_ccb == NULL) {
|
||||
break;
|
||||
}
|
||||
if (p_ccb->callback) {
|
||||
p_ccb->callback(p_ccb->allocated, OBEX_CONGEST_EVT, NULL);
|
||||
}
|
||||
break;
|
||||
case OBEX_TL_UNCONGEST_EVT:
|
||||
assert(p_ccb != NULL);
|
||||
if (p_ccb == NULL) {
|
||||
break;
|
||||
}
|
||||
if (p_ccb->callback) {
|
||||
p_ccb->callback(p_ccb->allocated, OBEX_UNCONGEST_EVT, NULL);
|
||||
}
|
||||
break;
|
||||
case OBEX_TL_MTU_CHANGE_EVT:
|
||||
assert(p_ccb != NULL);
|
||||
if (p_ccb == NULL) {
|
||||
break;
|
||||
}
|
||||
p_ccb->tl_peer_mtu = msg->mtu_chg.peer_mtu;
|
||||
p_ccb->tl_our_mtu = msg->mtu_chg.our_mtu;
|
||||
if (!check_conn_mtu_valid(p_ccb, TRUE)) {
|
||||
@@ -156,7 +168,11 @@ void obex_tl_evt_handler(UINT8 tl, tOBEX_TL_EVT evt, tOBEX_TL_MSG *msg)
|
||||
}
|
||||
break;
|
||||
case OBEX_TL_DATA_EVT:
|
||||
assert(p_ccb != NULL);
|
||||
if (p_ccb == NULL) {
|
||||
OBEX_TRACE_WARNING("Received OBEX_TL_DATA_EVT but CCB is NULL, dropping packet.");
|
||||
osi_free(msg->data.p_buf);
|
||||
break;
|
||||
}
|
||||
if (p_ccb->callback) {
|
||||
cb_msg.data.pkt = msg->data.p_buf;
|
||||
p_ccb->callback(p_ccb->allocated, OBEX_DATA_EVT, &cb_msg);
|
||||
@@ -168,7 +184,9 @@ void obex_tl_evt_handler(UINT8 tl, tOBEX_TL_EVT evt, tOBEX_TL_MSG *msg)
|
||||
break;
|
||||
case OBEX_TL_CONN_INCOME_EVT:
|
||||
/* New connection, p_ccb should be NULL */
|
||||
assert(p_ccb == NULL);
|
||||
if (p_ccb != NULL) {
|
||||
break;
|
||||
}
|
||||
p_scb = obex_find_scb_by_tl_hdl(tl, msg->conn_income.svr_hdl);
|
||||
if (p_scb == NULL) {
|
||||
obex_cb.tl_ops[tl]->disconnect(tl_hdl);
|
||||
|
||||
@@ -139,7 +139,8 @@ static tOBEX_TL_L2CAP_CCB *find_ccb_by_psm(UINT16 psm)
|
||||
{
|
||||
tOBEX_TL_L2CAP_CCB *p_ccb = NULL;
|
||||
for(int i = 0; i < OBEX_TL_L2CAP_NUM_CONN; ++i) {
|
||||
if (obex_tl_l2cap_cb.ccb[i].allocated && obex_tl_l2cap_cb.ccb[i].vpsm == psm) {
|
||||
if (obex_tl_l2cap_cb.ccb[i].allocated
|
||||
&& obex_tl_l2cap_cb.ccb[i].vpsm == psm) {
|
||||
p_ccb = &obex_tl_l2cap_cb.ccb[i];
|
||||
break;
|
||||
}
|
||||
@@ -201,6 +202,11 @@ static void l2cap_sec_check_complete_term(BD_ADDR bd_addr, tBT_TRANSPORT transpo
|
||||
{
|
||||
tOBEX_TL_L2CAP_CCB *p_ccb = (tOBEX_TL_L2CAP_CCB *)p_ref_data;
|
||||
|
||||
if (p_ccb->allocated == 0 || memcmp(p_ccb->addr, bd_addr, BD_ADDR_LEN) != 0) {
|
||||
OBEX_TL_L2CAP_TRACE_WARNING("CCB invalid or reallocated to another device, ignore sec_check_complete\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (res == BTM_SUCCESS) {
|
||||
L2CA_ErtmConnectRsp(p_ccb->addr, p_ccb->id, p_ccb->lcid, L2CAP_CONN_OK, 0, &obex_tl_l2cap_etm_opts);
|
||||
tL2CAP_CFG_INFO cfg = {0};
|
||||
@@ -214,8 +220,8 @@ static void l2cap_sec_check_complete_term(BD_ADDR bd_addr, tBT_TRANSPORT transpo
|
||||
L2CA_ErtmConnectRsp(p_ccb->addr, p_ccb->id, p_ccb->lcid, L2CAP_CONN_SECURITY_BLOCK, 0, &obex_tl_l2cap_etm_opts);
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.any.hdl = p_ccb->allocated;
|
||||
obex_tl_l2cap_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
free_ccb(p_ccb);
|
||||
obex_tl_l2cap_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,6 +237,11 @@ static void l2cap_sec_check_complete_orig(BD_ADDR bd_addr, tBT_TRANSPORT transpo
|
||||
{
|
||||
tOBEX_TL_L2CAP_CCB *p_ccb = (tOBEX_TL_L2CAP_CCB *)p_ref_data;
|
||||
|
||||
if (p_ccb->allocated == 0 || memcmp(p_ccb->addr, bd_addr, BD_ADDR_LEN) != 0) {
|
||||
OBEX_TL_L2CAP_TRACE_WARNING("CCB invalid or reallocated to another device, ignore sec_check_complete\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (res == BTM_SUCCESS) {
|
||||
tL2CAP_CFG_INFO cfg = {0};
|
||||
cfg.mtu_present = TRUE;
|
||||
@@ -242,8 +253,8 @@ static void l2cap_sec_check_complete_orig(BD_ADDR bd_addr, tBT_TRANSPORT transpo
|
||||
L2CA_DisconnectReq(p_ccb->lcid);
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.any.hdl = p_ccb->allocated;
|
||||
obex_tl_l2cap_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
free_ccb(p_ccb);
|
||||
obex_tl_l2cap_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,8 +323,8 @@ void obex_tl_l2cap_connect_cfm(UINT16 lcid, UINT16 result)
|
||||
OBEX_TL_L2CAP_TRACE_WARNING("l2cap_connect_cfm result != L2CAP_CONN_OK: result: 0x%x\n", result);
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.any.hdl = p_ccb->allocated;
|
||||
obex_tl_l2cap_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
free_ccb(p_ccb);
|
||||
obex_tl_l2cap_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,6 +423,11 @@ void obex_tl_l2cap_config_cfm(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
|
||||
if (p_ccb->initiator == FALSE && p_scb == NULL) {
|
||||
/* not a initiator, but can not find corresponding server */
|
||||
OBEX_TL_L2CAP_TRACE_ERROR("l2cap_config_cfm, not a initiator, but can not find corresponding server\n");
|
||||
L2CA_DisconnectReq(p_ccb->lcid);
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.any.hdl = p_ccb->allocated;
|
||||
free_ccb(p_ccb);
|
||||
obex_tl_l2cap_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -420,8 +436,12 @@ void obex_tl_l2cap_config_cfm(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
|
||||
L2CA_DisconnectReq(p_ccb->lcid);
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.any.hdl = p_ccb->allocated;
|
||||
obex_tl_l2cap_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
free_ccb(p_ccb);
|
||||
obex_tl_l2cap_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_ccb->status_flag & OBEX_TL_L2CAP_STATUS_FLAG_CONNECTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -490,8 +510,8 @@ void obex_tl_l2cap_disconnect_ind(UINT16 lcid, BOOLEAN is_conf_needed)
|
||||
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.any.hdl = p_ccb->allocated;
|
||||
obex_tl_l2cap_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
free_ccb(p_ccb);
|
||||
obex_tl_l2cap_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
}
|
||||
|
||||
|
||||
@@ -545,63 +565,6 @@ void obex_tl_l2cap_congestion_status_ind(UINT16 lcid, BOOLEAN is_congested)
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function obex_tl_l2cap_init
|
||||
**
|
||||
** Description Initialize OBEX over L2CAP transport layer, callback
|
||||
** can not be NULL, must be called once before using any
|
||||
** other APIs
|
||||
**
|
||||
*******************************************************************************/
|
||||
UINT16 obex_tl_l2cap_init(tOBEX_TL_CBACK *callback)
|
||||
{
|
||||
assert(callback != NULL);
|
||||
#if (OBEX_DYNAMIC_MEMORY)
|
||||
if (!obex_tl_l2cap_cb_ptr) {
|
||||
obex_tl_l2cap_cb_ptr = (tOBEX_TL_L2CAP_CB *)osi_malloc(sizeof(tOBEX_TL_L2CAP_CB));
|
||||
if (!obex_tl_l2cap_cb_ptr) {
|
||||
OBEX_TL_L2CAP_TRACE_ERROR("OBEX over L2CAP transport layer initialize failed, no memory\n");
|
||||
return OBEX_TL_FAILED;
|
||||
}
|
||||
}
|
||||
#endif /* #if (OBEX_DYNAMIC_MEMORY) */
|
||||
memset(&obex_tl_l2cap_cb, 0, sizeof(tOBEX_TL_L2CAP_CB));
|
||||
obex_tl_l2cap_cb.callback = callback;
|
||||
obex_tl_l2cap_cb.trace_level = BT_TRACE_LEVEL_ERROR;
|
||||
|
||||
tL2CAP_APPL_INFO *p_reg_info = &obex_tl_l2cap_cb.l2cap_reg_info;
|
||||
|
||||
p_reg_info->pL2CA_ConnectInd_Cb = NULL; /* obex_tl_l2cap_connect_ind or NULL, depend on server or not */
|
||||
p_reg_info->pL2CA_ConnectCfm_Cb = obex_tl_l2cap_connect_cfm;
|
||||
p_reg_info->pL2CA_ConnectPnd_Cb = NULL;
|
||||
p_reg_info->pL2CA_ConfigInd_Cb = obex_tl_l2cap_config_ind;
|
||||
p_reg_info->pL2CA_ConfigCfm_Cb = obex_tl_l2cap_config_cfm;
|
||||
p_reg_info->pL2CA_DisconnectInd_Cb = obex_tl_l2cap_disconnect_ind;
|
||||
p_reg_info->pL2CA_DisconnectCfm_Cb = NULL;
|
||||
p_reg_info->pL2CA_QoSViolationInd_Cb = obex_tl_l2cap_qos_violation_ind;
|
||||
p_reg_info->pL2CA_DataInd_Cb = obex_tl_l2cap_buf_data_ind;
|
||||
p_reg_info->pL2CA_CongestionStatus_Cb = obex_tl_l2cap_congestion_status_ind;
|
||||
p_reg_info->pL2CA_TxComplete_Cb = NULL;
|
||||
return OBEX_TL_SUCCESS;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function obex_tl_l2cap_deinit
|
||||
**
|
||||
** Description Deinitialize OBEX over L2CAP transport layer
|
||||
**
|
||||
*******************************************************************************/
|
||||
void obex_tl_l2cap_deinit(void)
|
||||
{
|
||||
#if (OBEX_DYNAMIC_MEMORY)
|
||||
if (obex_tl_l2cap_cb_ptr) {
|
||||
osi_free(obex_tl_l2cap_cb_ptr);
|
||||
obex_tl_l2cap_cb_ptr = NULL;
|
||||
}
|
||||
#endif /* #if (OBEX_DYNAMIC_MEMORY) */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
@@ -642,9 +605,14 @@ UINT16 obex_tl_l2cap_connect(tOBEX_TL_SVR_INFO *server)
|
||||
else {
|
||||
p_ccb->our_mtu = server->l2cap.pref_mtu;
|
||||
}
|
||||
bdcpy(p_ccb->addr, server->l2cap.addr);
|
||||
p_ccb->initiator = TRUE;
|
||||
p_ccb->lcid = L2CA_ErtmConnectReq(p_ccb->vpsm, server->l2cap.addr, &obex_tl_l2cap_etm_opts);
|
||||
if (p_ccb->lcid == 0) {
|
||||
/* outgoing-only PSM was registered above; unload it on connect failure */
|
||||
if (find_scb_by_psm(p_ccb->vpsm) == NULL) {
|
||||
L2CA_Deregister(p_ccb->vpsm);
|
||||
}
|
||||
free_ccb(p_ccb);
|
||||
return 0;
|
||||
}
|
||||
@@ -776,14 +744,84 @@ void obex_tl_l2cap_unbind(UINT16 tl_hdl)
|
||||
L2CA_DisconnectReq(p_ccb->lcid);
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.any.hdl = p_ccb->allocated;
|
||||
obex_tl_l2cap_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
free_ccb(p_ccb);
|
||||
obex_tl_l2cap_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
}
|
||||
L2CA_Deregister(p_scb->psm);
|
||||
free_scb(p_scb);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function obex_tl_l2cap_init
|
||||
**
|
||||
** Description Initialize OBEX over L2CAP transport layer, callback
|
||||
** can not be NULL, must be called once before using any
|
||||
** other APIs
|
||||
**
|
||||
*******************************************************************************/
|
||||
UINT16 obex_tl_l2cap_init(tOBEX_TL_CBACK *callback)
|
||||
{
|
||||
assert(callback != NULL);
|
||||
#if (OBEX_DYNAMIC_MEMORY)
|
||||
if (!obex_tl_l2cap_cb_ptr) {
|
||||
obex_tl_l2cap_cb_ptr = (tOBEX_TL_L2CAP_CB *)osi_malloc(sizeof(tOBEX_TL_L2CAP_CB));
|
||||
if (!obex_tl_l2cap_cb_ptr) {
|
||||
OBEX_TL_L2CAP_TRACE_ERROR("OBEX over L2CAP transport layer initialize failed, no memory\n");
|
||||
return OBEX_TL_FAILED;
|
||||
}
|
||||
}
|
||||
#endif /* #if (OBEX_DYNAMIC_MEMORY) */
|
||||
memset(&obex_tl_l2cap_cb, 0, sizeof(tOBEX_TL_L2CAP_CB));
|
||||
obex_tl_l2cap_cb.callback = callback;
|
||||
obex_tl_l2cap_cb.trace_level = BT_TRACE_LEVEL_ERROR;
|
||||
|
||||
tL2CAP_APPL_INFO *p_reg_info = &obex_tl_l2cap_cb.l2cap_reg_info;
|
||||
|
||||
p_reg_info->pL2CA_ConnectInd_Cb = NULL; /* obex_tl_l2cap_connect_ind or NULL, depend on server or not */
|
||||
p_reg_info->pL2CA_ConnectCfm_Cb = obex_tl_l2cap_connect_cfm;
|
||||
p_reg_info->pL2CA_ConnectPnd_Cb = NULL;
|
||||
p_reg_info->pL2CA_ConfigInd_Cb = obex_tl_l2cap_config_ind;
|
||||
p_reg_info->pL2CA_ConfigCfm_Cb = obex_tl_l2cap_config_cfm;
|
||||
p_reg_info->pL2CA_DisconnectInd_Cb = obex_tl_l2cap_disconnect_ind;
|
||||
p_reg_info->pL2CA_DisconnectCfm_Cb = NULL;
|
||||
p_reg_info->pL2CA_QoSViolationInd_Cb = obex_tl_l2cap_qos_violation_ind;
|
||||
p_reg_info->pL2CA_DataInd_Cb = obex_tl_l2cap_buf_data_ind;
|
||||
p_reg_info->pL2CA_CongestionStatus_Cb = obex_tl_l2cap_congestion_status_ind;
|
||||
p_reg_info->pL2CA_TxComplete_Cb = NULL;
|
||||
return OBEX_TL_SUCCESS;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function obex_tl_l2cap_deinit
|
||||
**
|
||||
** Description Deinitialize OBEX over L2CAP transport layer
|
||||
**
|
||||
*******************************************************************************/
|
||||
void obex_tl_l2cap_deinit(void)
|
||||
{
|
||||
#if (OBEX_DYNAMIC_MEMORY)
|
||||
if (obex_tl_l2cap_cb_ptr){
|
||||
#endif
|
||||
for (int i = 0; i < OBEX_TL_L2CAP_NUM_CONN; ++i) {
|
||||
if (obex_tl_l2cap_cb.ccb[i].allocated) {
|
||||
obex_tl_l2cap_disconnect(obex_tl_l2cap_cb.ccb[i].allocated);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < OBEX_TL_L2CAP_NUM_SERVER; ++i) {
|
||||
if (obex_tl_l2cap_cb.scb[i].allocated) {
|
||||
obex_tl_l2cap_unbind(obex_tl_l2cap_cb.scb[i].allocated << 8);
|
||||
}
|
||||
}
|
||||
#if (OBEX_DYNAMIC_MEMORY)
|
||||
osi_free(obex_tl_l2cap_cb_ptr);
|
||||
obex_tl_l2cap_cb_ptr = NULL;
|
||||
}
|
||||
#endif /* #if (OBEX_DYNAMIC_MEMORY) */
|
||||
}
|
||||
|
||||
static tOBEX_TL_OPS obex_tl_l2cap_ops = {
|
||||
.init = obex_tl_l2cap_init,
|
||||
.deinit = obex_tl_l2cap_deinit,
|
||||
|
||||
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "osi/osi.h"
|
||||
#include "osi/allocator.h"
|
||||
#include "common/bt_target.h"
|
||||
|
||||
#include "stack/port_api.h"
|
||||
#include "stack/btm_api.h"
|
||||
#include "stack/sdpdefs.h"
|
||||
#include "obex_tl.h"
|
||||
#include "obex_tl_rfcomm.h"
|
||||
|
||||
#if (OBEX_INCLUDED == TRUE && RFCOMM_INCLUDED == TRUE)
|
||||
|
||||
#define OBEX_TL_RFCOMM_NUM_CONN 4
|
||||
#define OBEX_TL_RFCOMM_NUM_SERVER 2
|
||||
|
||||
#define OBEX_TL_RFCOMM_EVENT_MARK (PORT_EV_FC | PORT_EV_FCS)
|
||||
|
||||
typedef struct {
|
||||
UINT16 rfc_handle; /* rfcomm handle */
|
||||
UINT16 mtu; /* rfcomm mtu */
|
||||
BOOLEAN initiator; /* TRUE if is initiator, otherwise FALSE */
|
||||
UINT8 scn; /* service channel number */
|
||||
BD_ADDR addr; /* peer bluetooth device address */
|
||||
UINT8 allocated; /* 0 if not allocated, otherwise, index + 1, equal to handle */
|
||||
} tOBEX_TL_RFCOMM_CCB;
|
||||
|
||||
typedef struct {
|
||||
UINT16 rfc_handle; /* rfcomm handle */
|
||||
UINT8 scn; /* service channel number */
|
||||
UINT8 allocated; /* 0 if not allocated, otherwise, index + 1, handle of server will left shift 8 bits */
|
||||
} tOBEX_TL_RFCOMM_SCB;
|
||||
|
||||
typedef struct {
|
||||
tOBEX_TL_CBACK *callback; /* Upper layer callback */
|
||||
tOBEX_TL_RFCOMM_CCB ccb[OBEX_TL_RFCOMM_NUM_CONN];
|
||||
tOBEX_TL_RFCOMM_SCB scb[OBEX_TL_RFCOMM_NUM_SERVER];
|
||||
UINT8 trace_level; /* trace level */
|
||||
} tOBEX_TL_RFCOMM_CB;
|
||||
|
||||
#if OBEX_DYNAMIC_MEMORY == FALSE
|
||||
static tOBEX_TL_RFCOMM_CB obex_tl_rfcomm_cb;
|
||||
#else
|
||||
static tOBEX_TL_RFCOMM_CB *obex_tl_rfcomm_cb_ptr = NULL;
|
||||
#define obex_tl_rfcomm_cb (*obex_tl_rfcomm_cb_ptr)
|
||||
#endif
|
||||
|
||||
static tOBEX_TL_RFCOMM_CCB *allocate_ccb(void)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = NULL;
|
||||
for(int i = 0; i < OBEX_TL_RFCOMM_NUM_CONN; ++i) {
|
||||
if (obex_tl_rfcomm_cb.ccb[i].allocated == 0) {
|
||||
obex_tl_rfcomm_cb.ccb[i].allocated = i + 1;
|
||||
p_ccb = &obex_tl_rfcomm_cb.ccb[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p_ccb;
|
||||
}
|
||||
|
||||
static tOBEX_TL_RFCOMM_SCB *allocate_scb(void)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_SCB *p_scb = NULL;
|
||||
for(int i = 0; i < OBEX_TL_RFCOMM_NUM_SERVER; ++i) {
|
||||
if (obex_tl_rfcomm_cb.scb[i].allocated == 0) {
|
||||
obex_tl_rfcomm_cb.scb[i].allocated = i + 1;
|
||||
p_scb = &obex_tl_rfcomm_cb.scb[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p_scb;
|
||||
}
|
||||
|
||||
static void free_ccb(tOBEX_TL_RFCOMM_CCB *p_ccb)
|
||||
{
|
||||
memset(p_ccb, 0, sizeof(tOBEX_TL_RFCOMM_CCB));
|
||||
}
|
||||
|
||||
static void free_scb(tOBEX_TL_RFCOMM_SCB *p_scb)
|
||||
{
|
||||
memset(p_scb, 0, sizeof(tOBEX_TL_RFCOMM_SCB));
|
||||
}
|
||||
|
||||
static tOBEX_TL_RFCOMM_CCB *find_ccb_by_handle(UINT16 handle)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = NULL;
|
||||
if (handle > 0 && handle <= OBEX_TL_RFCOMM_NUM_CONN) {
|
||||
if (obex_tl_rfcomm_cb.ccb[handle-1].allocated == handle) {
|
||||
p_ccb = &obex_tl_rfcomm_cb.ccb[handle-1];
|
||||
}
|
||||
}
|
||||
return p_ccb;
|
||||
}
|
||||
|
||||
static tOBEX_TL_RFCOMM_CCB *find_ccb_by_rfc_handle(UINT16 rfc_handle)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = NULL;
|
||||
for(int i = 0; i < OBEX_TL_RFCOMM_NUM_CONN; ++i) {
|
||||
if (obex_tl_rfcomm_cb.ccb[i].allocated && obex_tl_rfcomm_cb.ccb[i].rfc_handle == rfc_handle) {
|
||||
p_ccb = &obex_tl_rfcomm_cb.ccb[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p_ccb;
|
||||
}
|
||||
|
||||
static tOBEX_TL_RFCOMM_SCB *find_scb_by_handle(UINT16 handle)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_SCB *p_scb = NULL;
|
||||
handle = handle >> 8;
|
||||
if (handle > 0 && handle <= OBEX_TL_RFCOMM_NUM_SERVER) {
|
||||
if (obex_tl_rfcomm_cb.scb[handle-1].allocated == handle) {
|
||||
p_scb = &obex_tl_rfcomm_cb.scb[handle-1];
|
||||
}
|
||||
}
|
||||
return p_scb;
|
||||
}
|
||||
|
||||
static tOBEX_TL_RFCOMM_SCB *find_scb_by_rfc_handle(UINT16 rfc_handle)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_SCB *p_scb = NULL;
|
||||
for(int i = 0; i < OBEX_TL_RFCOMM_NUM_SERVER; ++i) {
|
||||
if (obex_tl_rfcomm_cb.scb[i].allocated && obex_tl_rfcomm_cb.scb[i].rfc_handle == rfc_handle) {
|
||||
p_scb = &obex_tl_rfcomm_cb.scb[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p_scb;
|
||||
}
|
||||
|
||||
static tOBEX_TL_RFCOMM_SCB *find_scb_by_scn(UINT16 scn)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_SCB *p_scb = NULL;
|
||||
for(int i = 0; i < OBEX_TL_RFCOMM_NUM_SERVER; ++i) {
|
||||
if (obex_tl_rfcomm_cb.scb[i].allocated && obex_tl_rfcomm_cb.scb[i].scn == scn) {
|
||||
p_scb = &obex_tl_rfcomm_cb.scb[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p_scb;
|
||||
}
|
||||
|
||||
static void rfcomm_mgmt_event_handler(tOBEX_TL_RFCOMM_CCB *p_ccb, UINT32 code)
|
||||
{
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.any.hdl = p_ccb->allocated;
|
||||
switch (code)
|
||||
{
|
||||
case PORT_SUCCESS:
|
||||
/* event already handled, do nothing */
|
||||
break;
|
||||
default:
|
||||
/* other event, disconnect */
|
||||
obex_tl_rfcomm_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
free_ccb(p_ccb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void rfcomm_client_mgmt_callback(UINT32 code, UINT16 rfc_handle, void* data)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = find_ccb_by_rfc_handle(rfc_handle);
|
||||
if (p_ccb == NULL) {
|
||||
OBEX_TL_RFCOMM_TRACE_DEBUG("No ccb to handle rfcomm event\n");
|
||||
return;
|
||||
}
|
||||
/* connection opened, handle event here */
|
||||
if (code == PORT_SUCCESS) {
|
||||
assert(data != NULL);
|
||||
tPORT_MGMT_CL_CALLBACK_ARG *cl_mgmt_cb_arg = (tPORT_MGMT_CL_CALLBACK_ARG *)data;
|
||||
p_ccb->mtu = cl_mgmt_cb_arg->peer_mtu;
|
||||
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.conn_open.hdl = p_ccb->allocated;
|
||||
msg.conn_open.peer_mtu = p_ccb->mtu;
|
||||
msg.conn_open.our_mtu = p_ccb->mtu;
|
||||
obex_tl_rfcomm_cb.callback(OBEX_TL_CONN_OPEN_EVT, &msg);
|
||||
}
|
||||
rfcomm_mgmt_event_handler(p_ccb, code);
|
||||
}
|
||||
|
||||
static void rfcomm_server_mgmt_callback(UINT32 code, UINT16 rfc_handle, void* data)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = NULL;
|
||||
/* incoming connection, handle event here */
|
||||
if (code == PORT_SUCCESS) {
|
||||
assert(data != NULL);
|
||||
tOBEX_TL_RFCOMM_SCB *p_scb = find_scb_by_rfc_handle(rfc_handle);
|
||||
tPORT_MGMT_SR_CALLBACK_ARG *sr_mgmt_cb_arg = (tPORT_MGMT_SR_CALLBACK_ARG *)data;
|
||||
if (p_scb == NULL) {
|
||||
OBEX_TL_RFCOMM_TRACE_WARNING("No scb to this rfcomm connection\n");
|
||||
/* tell rfcomm to reject this connection */
|
||||
sr_mgmt_cb_arg->accept = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* try to find p_ccb with this rfc_handle, we expect to get a NULL */
|
||||
p_ccb = find_ccb_by_rfc_handle(rfc_handle);
|
||||
if (p_ccb == NULL) {
|
||||
p_ccb = allocate_ccb();
|
||||
if (p_ccb == NULL) {
|
||||
OBEX_TL_RFCOMM_TRACE_WARNING("can not allocate a ccb for new connection\n");
|
||||
sr_mgmt_cb_arg->accept = FALSE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
OBEX_TL_RFCOMM_TRACE_WARNING("found duplicate rfcomm connection\n");
|
||||
if (sr_mgmt_cb_arg != NULL) {
|
||||
sr_mgmt_cb_arg->accept = FALSE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
p_ccb->initiator = FALSE;
|
||||
p_ccb->rfc_handle = rfc_handle;
|
||||
p_ccb->scn = p_scb->scn;
|
||||
p_ccb->mtu = sr_mgmt_cb_arg->peer_mtu;
|
||||
/* get peer bd_addr */
|
||||
PORT_CheckConnection(rfc_handle, FALSE, p_ccb->addr, NULL);
|
||||
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.conn_income.hdl = p_ccb->allocated;
|
||||
msg.conn_income.peer_mtu = p_ccb->mtu;
|
||||
msg.conn_income.our_mtu = p_ccb->mtu;
|
||||
msg.conn_income.svr_hdl = (p_scb->allocated << 8);
|
||||
obex_tl_rfcomm_cb.callback(OBEX_TL_CONN_INCOME_EVT, &msg);
|
||||
}
|
||||
else {
|
||||
/* other event, it means server is connected */
|
||||
p_ccb = find_ccb_by_rfc_handle(rfc_handle);
|
||||
if (p_ccb == NULL) {
|
||||
OBEX_TL_RFCOMM_TRACE_DEBUG("No ccb to handle rfcomm event\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
rfcomm_mgmt_event_handler(p_ccb, code);
|
||||
}
|
||||
|
||||
static int rfcomm_data_callback(UINT16 rfc_handle, UINT8 *p_buf, UINT16 len, int type)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = find_ccb_by_rfc_handle(rfc_handle);
|
||||
if (p_ccb != NULL && type == DATA_CO_CALLBACK_TYPE_INCOMING) {
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.data.hdl = p_ccb->allocated;
|
||||
msg.data.p_buf = (BT_HDR *)p_buf;
|
||||
obex_tl_rfcomm_cb.callback(OBEX_TL_DATA_EVT, &msg);
|
||||
PORT_FlowControl_GiveCredit(rfc_handle, TRUE, 1);
|
||||
}
|
||||
else if(p_buf != NULL) {
|
||||
osi_free(p_buf);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void rfcomm_event_callback(UINT32 code, UINT16 rfc_handle)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = find_ccb_by_rfc_handle(rfc_handle);
|
||||
if (p_ccb == NULL) {
|
||||
OBEX_TL_RFCOMM_TRACE_WARNING("No ccb to handle rfcomm event\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (code & PORT_EV_FC) {
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.any.hdl = p_ccb->allocated;
|
||||
if (code & PORT_EV_FCS) {
|
||||
obex_tl_rfcomm_cb.callback(OBEX_TL_UNCONGEST_EVT, &msg);
|
||||
}
|
||||
else {
|
||||
obex_tl_rfcomm_cb.callback(OBEX_TL_CONGEST_EVT, &msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UINT16 obex_tl_rfcomm_init(tOBEX_TL_CBACK *callback)
|
||||
{
|
||||
assert(callback != NULL);
|
||||
#if (OBEX_DYNAMIC_MEMORY)
|
||||
if (!obex_tl_rfcomm_cb_ptr) {
|
||||
obex_tl_rfcomm_cb_ptr = (tOBEX_TL_RFCOMM_CB *)osi_malloc(sizeof(tOBEX_TL_RFCOMM_CB));
|
||||
if (!obex_tl_rfcomm_cb_ptr) {
|
||||
OBEX_TL_RFCOMM_TRACE_ERROR("OBEX over RFCOMM transport layer initialize failed, no memory\n");
|
||||
return OBEX_TL_FAILED;
|
||||
}
|
||||
}
|
||||
#endif /* #if (OBEX_DYNAMIC_MEMORY) */
|
||||
memset(&obex_tl_rfcomm_cb, 0, sizeof(tOBEX_TL_RFCOMM_CB));
|
||||
obex_tl_rfcomm_cb.callback = callback;
|
||||
obex_tl_rfcomm_cb.trace_level = BT_TRACE_LEVEL_ERROR;
|
||||
return OBEX_TL_SUCCESS;
|
||||
}
|
||||
|
||||
void obex_tl_rfcomm_deinit(void)
|
||||
{
|
||||
#if (OBEX_DYNAMIC_MEMORY)
|
||||
if (obex_tl_rfcomm_cb_ptr) {
|
||||
#endif
|
||||
for (size_t i = 0; i < OBEX_TL_RFCOMM_NUM_CONN; i++) {
|
||||
if (obex_tl_rfcomm_cb.ccb[i].rfc_handle != 0) {
|
||||
RFCOMM_RemoveConnection(obex_tl_rfcomm_cb.ccb[i].rfc_handle);
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < OBEX_TL_RFCOMM_NUM_SERVER; i++) {
|
||||
if (obex_tl_rfcomm_cb.scb[i].rfc_handle != 0) {
|
||||
RFCOMM_RemoveServer(obex_tl_rfcomm_cb.scb[i].rfc_handle);
|
||||
}
|
||||
}
|
||||
#if (OBEX_DYNAMIC_MEMORY)
|
||||
osi_free(obex_tl_rfcomm_cb_ptr);
|
||||
obex_tl_rfcomm_cb_ptr = NULL;
|
||||
}
|
||||
#endif /* #if (OBEX_DYNAMIC_MEMORY) */
|
||||
}
|
||||
|
||||
UINT16 obex_tl_rfcomm_connect(tOBEX_TL_SVR_INFO *server)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = allocate_ccb();
|
||||
if (p_ccb == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_OBEX, server->rfcomm.sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, server->rfcomm.scn);
|
||||
if (RFCOMM_CreateConnection(UUID_PROTOCOL_OBEX, server->rfcomm.scn, FALSE, server->rfcomm.pref_mtu,
|
||||
server->rfcomm.addr, &p_ccb->rfc_handle, rfcomm_client_mgmt_callback) != PORT_SUCCESS) {
|
||||
free_ccb(p_ccb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set up data callback, event mask and event callback */
|
||||
PORT_SetDataCOCallback(p_ccb->rfc_handle, rfcomm_data_callback);
|
||||
PORT_SetEventMask(p_ccb->rfc_handle, OBEX_TL_RFCOMM_EVENT_MARK);
|
||||
PORT_SetEventCallback(p_ccb->rfc_handle, rfcomm_event_callback);
|
||||
|
||||
bdcpy(p_ccb->addr, server->rfcomm.addr);
|
||||
p_ccb->scn = server->rfcomm.scn;
|
||||
p_ccb->initiator = TRUE;
|
||||
|
||||
return p_ccb->allocated;
|
||||
}
|
||||
|
||||
void obex_tl_rfcomm_disconnect(UINT16 handle)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = find_ccb_by_handle(handle);
|
||||
if (p_ccb != NULL) {
|
||||
RFCOMM_RemoveConnection(p_ccb->rfc_handle);
|
||||
free_ccb(p_ccb);
|
||||
}
|
||||
}
|
||||
|
||||
UINT16 obex_tl_rfcomm_send(UINT16 handle, BT_HDR *p_buf)
|
||||
{
|
||||
UINT16 ret = OBEX_TL_FAILED;
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = find_ccb_by_handle(handle);
|
||||
do {
|
||||
if (p_ccb == NULL) {
|
||||
osi_free(p_buf);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Can not send data size larger than MTU */
|
||||
/* Offset should not smaller than OBEX_TL_RFCOMM_BT_HDR_MIN_OFFSET */
|
||||
if (p_buf->len > p_ccb->mtu || p_buf->offset < OBEX_TL_RFCOMM_BT_HDR_MIN_OFFSET) {
|
||||
osi_free(p_buf);
|
||||
break;
|
||||
}
|
||||
|
||||
if (PORT_Write(p_ccb->rfc_handle, p_buf) == PORT_SUCCESS) {
|
||||
ret = OBEX_TL_SUCCESS;
|
||||
}
|
||||
} while (0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
UINT16 obex_tl_rfcomm_bind(tOBEX_TL_SVR_INFO *server)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_SCB *p_scb = find_scb_by_scn(server->rfcomm.scn);
|
||||
if (p_scb != NULL) {
|
||||
/* scn already used */
|
||||
return 0;
|
||||
}
|
||||
|
||||
p_scb = allocate_scb();
|
||||
if (p_scb == NULL) {
|
||||
OBEX_TL_RFCOMM_TRACE_WARNING("Can not allocate scb, out of number\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_OBEX, server->rfcomm.sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, server->rfcomm.scn);
|
||||
if (RFCOMM_CreateConnection(UUID_PROTOCOL_OBEX, server->rfcomm.scn, TRUE, server->rfcomm.pref_mtu,
|
||||
server->rfcomm.addr, &p_scb->rfc_handle, rfcomm_server_mgmt_callback) != PORT_SUCCESS) {
|
||||
free_scb(p_scb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set up data callback, event mask and event callback */
|
||||
PORT_SetDataCOCallback(p_scb->rfc_handle, rfcomm_data_callback);
|
||||
PORT_SetEventMask(p_scb->rfc_handle, OBEX_TL_RFCOMM_EVENT_MARK);
|
||||
PORT_SetEventCallback(p_scb->rfc_handle, rfcomm_event_callback);
|
||||
|
||||
p_scb->scn = server->rfcomm.scn;
|
||||
|
||||
/* left shift 8 bits as server handle, avoid confuse with connection handle */
|
||||
return (p_scb->allocated << 8);
|
||||
}
|
||||
|
||||
void obex_tl_rfcomm_unbind(UINT16 handle)
|
||||
{
|
||||
tOBEX_TL_RFCOMM_SCB *p_scb = find_scb_by_handle(handle);
|
||||
if (p_scb) {
|
||||
tOBEX_TL_RFCOMM_CCB *p_ccb = NULL;
|
||||
while ((p_ccb = find_ccb_by_rfc_handle(p_scb->rfc_handle)) != NULL) {
|
||||
RFCOMM_RemoveConnection(p_ccb->rfc_handle);
|
||||
tOBEX_TL_MSG msg = {0};
|
||||
msg.any.hdl = p_ccb->allocated;
|
||||
obex_tl_rfcomm_cb.callback(OBEX_TL_DIS_CONN_EVT, &msg);
|
||||
free_ccb(p_ccb);
|
||||
}
|
||||
RFCOMM_RemoveServer(p_scb->rfc_handle);
|
||||
free_scb(p_scb);
|
||||
}
|
||||
}
|
||||
|
||||
static tOBEX_TL_OPS obex_tl_rfcomm_ops = {
|
||||
.init = obex_tl_rfcomm_init,
|
||||
.deinit = obex_tl_rfcomm_deinit,
|
||||
.connect = obex_tl_rfcomm_connect,
|
||||
.disconnect = obex_tl_rfcomm_disconnect,
|
||||
.bind = obex_tl_rfcomm_bind,
|
||||
.unbind = obex_tl_rfcomm_unbind,
|
||||
.send = obex_tl_rfcomm_send
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function obex_tl_rfcomm_ops_get
|
||||
**
|
||||
** Description Get the operation function structure pointer of OBEX over
|
||||
** RFCOMM transport layer
|
||||
**
|
||||
** Returns Pointer to operation function structure
|
||||
**
|
||||
*******************************************************************************/
|
||||
tOBEX_TL_OPS *obex_tl_rfcomm_ops_get(void)
|
||||
{
|
||||
return &obex_tl_rfcomm_ops;
|
||||
}
|
||||
|
||||
#endif /* #if (OBEX_INCLUDED == TRUE && RFCOMM_INCLUDED == TRUE) */
|
||||
Reference in New Issue
Block a user