feat(bt/bluedroid): Support OBEX over RFCOMM feature

This commit is contained in:
linruihao 2024-09-04 16:10:33 +08:00
parent 0784ee0102
commit b2856253e8
11 changed files with 522 additions and 11 deletions

View File

@ -411,6 +411,7 @@ if(CONFIG_BT_ENABLED)
"host/bluedroid/stack/obex/obex_api.c"
"host/bluedroid/stack/obex/obex_main.c"
"host/bluedroid/stack/obex/obex_tl_l2cap.c"
"host/bluedroid/stack/obex/obex_tl_rfcomm.c"
"host/bluedroid/stack/rfcomm/port_api.c"
"host/bluedroid/stack/rfcomm/port_rfc.c"
"host/bluedroid/stack/rfcomm/port_utils.c"

View File

@ -177,6 +177,9 @@
#endif /* UC_BT_HID_DEVICE_ENABLED */
#if UC_BT_GOEPC_ENABLED
#ifndef RFCOMM_INCLUDED
#define RFCOMM_INCLUDED TRUE
#endif
#ifndef OBEX_INCLUDED
#define OBEX_INCLUDED TRUE
#endif

View File

@ -330,6 +330,13 @@ static inline void trc_dump_buffer(const char *prefix, uint8_t *data, uint16_t l
#define OBEX_TL_L2CAP_TRACE_EVENT(fmt, args...) {if (obex_tl_l2cap_cb.trace_level >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(AVRC,EVENT)) BT_PRINT_D("OBEX_TL_L2CAP", fmt, ## args);}
#define OBEX_TL_L2CAP_TRACE_DEBUG(fmt, args...) {if (obex_tl_l2cap_cb.trace_level >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(AVRC,DEBUG)) BT_PRINT_D("OBEX_TL_L2CAP", fmt, ## args);}
/* Define tracing for OBEX_TL_RFCOMM */
#define OBEX_TL_RFCOMM_TRACE_ERROR(fmt, args...) {if (obex_tl_rfcomm_cb.trace_level >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(AVRC, ERROR)) BT_PRINT_E("OBEX_TL_RFCOMM", fmt, ## args);}
#define OBEX_TL_RFCOMM_TRACE_WARNING(fmt, args...) {if (obex_tl_rfcomm_cb.trace_level >= BT_TRACE_LEVEL_WARNING && BT_LOG_LEVEL_CHECK(AVRC, WARNING)) BT_PRINT_W("OBEX_TL_RFCOMM", fmt, ## args);}
#define OBEX_TL_RFCOMM_TRACE_API(fmt, args...) {if (obex_tl_rfcomm_cb.trace_level >= BT_TRACE_LEVEL_API && BT_LOG_LEVEL_CHECK(AVRC,API)) BT_PRINT_I("OBEX_TL_RFCOMM", fmt, ## args);}
#define OBEX_TL_RFCOMM_TRACE_EVENT(fmt, args...) {if (obex_tl_rfcomm_cb.trace_level >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(AVRC,EVENT)) BT_PRINT_D("OBEX_TL_RFCOMM", fmt, ## args);}
#define OBEX_TL_RFCOMM_TRACE_DEBUG(fmt, args...) {if (obex_tl_rfcomm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(AVRC,DEBUG)) BT_PRINT_D("OBEX_TL_RFCOMM", fmt, ## args);}
/* Define tracing for GOEPC */
#define GOEPC_TRACE_ERROR(fmt, args...) {if (goepc_cb.trace_level >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(AVRC, ERROR)) BT_PRINT_E("BT_GOEPC", fmt, ## args);}
#define GOEPC_TRACE_WARNING(fmt, args...) {if (goepc_cb.trace_level >= BT_TRACE_LEVEL_WARNING && BT_LOG_LEVEL_CHECK(AVRC, WARNING)) BT_PRINT_W("BT_GOEPC", fmt, ## args);}
@ -512,12 +519,20 @@ extern UINT8 btif_trace_level;
#define OBEX_TRACE_EVENT(fmt, args...)
#define OBEX_TRACE_DEBUG(fmt, args...)
/* Define tracing for OBEX L2CAP transport layer */
#define OBEX_TL_L2CAP_TRACE_ERROR(fmt, args...)
#define OBEX_TL_L2CAP_TRACE_WARNING(fmt, args...)
#define OBEX_TL_L2CAP_TRACE_API(fmt, args...)
#define OBEX_TL_L2CAP_TRACE_EVENT(fmt, args...)
#define OBEX_TL_L2CAP_TRACE_DEBUG(fmt, args...)
/* Define tracing for OBEX RFCOMM transport layer */
#define OBEX_TL_RFCOMM_TRACE_ERROR(fmt, args...)
#define OBEX_TL_RFCOMM_TRACE_WARNING(fmt, args...)
#define OBEX_TL_RFCOMM_TRACE_API(fmt, args...)
#define OBEX_TL_RFCOMM_TRACE_EVENT(fmt, args...)
#define OBEX_TL_RFCOMM_TRACE_DEBUG(fmt, args...)
/* Define tracing for GOEPC */
#define GOEPC_TRACE_ERROR(fmt, args...)
#define GOEPC_TRACE_WARNING(fmt, args...)

View File

@ -19,8 +19,6 @@
#define OBEX_NOT_OPEN 6 /* Connection not open */
#define OBEX_PACKET_TOO_LARGE 7 /* Packet size large than MTU */
#define OBEX_ERROR_TL 8 /* Operation failed in transport layer */
#define OBEX_TRY_AGAIN 9 /* Operation failed, connection congestion, try again */
/*
* OBEX profile definitions
@ -162,12 +160,21 @@ typedef struct
BD_ADDR addr; /* peer bluetooth device address */
} tOBEX_OVER_L2CAP_SVR;
typedef struct
{
UINT8 scn; /* service channel number */
UINT16 sec_mask; /* security mask */
UINT16 pref_mtu; /* preferred mtu, limited by rfcomm mtu */
BD_ADDR addr; /* peer bluetooth device address */
} tOBEX_OVER_RFCOMM_SVR;
typedef struct
{
UINT8 tl; /* transport type, OBEX_OVER_L2CAP or OBEX_OVER_RFCOMM */
union
{
tOBEX_OVER_L2CAP_SVR l2cap;
tOBEX_OVER_RFCOMM_SVR rfcomm;
};
} tOBEX_SVR_INFO;

View File

@ -14,7 +14,13 @@
#if (OBEX_INCLUDED == TRUE)
#define OBEX_BT_HDR_MIN_OFFSET OBEX_TL_L2CAP_BT_HDR_MIN_OFFSET /* should set to max value of all transport layer */
#if (RFCOMM_INCLUDED == TRUE)
#define OBEX_BT_HDR_MIN_OFFSET OBEX_TL_RFCOMM_BT_HDR_MIN_OFFSET /* should set to max value of all transport layer */
#define OBEX_BT_HDR_RESERVE_LEN OBEX_TL_RFCOMM_BT_HDR_RESERVE_LEN /* should set to max value of all transport layer */
#else
#define OBEX_BT_HDR_MIN_OFFSET OBEX_TL_L2CAP_BT_HDR_OFFSET_MIN
#define OBEX_BT_HDR_RESERVE_LEN OBEX_TL_L2CAP_BT_HDR_RESERVE_LEN
#endif
#define OBEX_ROLE_CLIENT 0x01
#define OBEX_ROLE_SERVER 0x02
@ -65,6 +71,7 @@ extern tOBEX_CB *obex_cb_ptr;
#endif
void obex_tl_l2cap_callback(tOBEX_TL_EVT evt, tOBEX_TL_MSG *msg);
void obex_tl_rfcomm_callback(tOBEX_TL_EVT evt, tOBEX_TL_MSG *msg);
tOBEX_CCB *obex_allocate_ccb(void);
tOBEX_SCB *obex_allocate_scb(void);
void obex_free_ccb(tOBEX_CCB *p_ccb);

View File

@ -68,9 +68,18 @@ typedef struct
BD_ADDR addr; /* peer bluetooth device address */
} tOBEX_TL_L2CAP_SVR;
typedef struct
{
UINT8 scn; /* service channel number */
UINT16 sec_mask; /* security mask */
UINT16 pref_mtu; /* preferred mtu, limited by rfcomm mtu */
BD_ADDR addr; /* peer bluetooth device address */
} tOBEX_TL_RFCOMM_SVR;
typedef union
{
tOBEX_TL_L2CAP_SVR l2cap;
tOBEX_TL_RFCOMM_SVR rfcomm;
} tOBEX_TL_SVR_INFO;
typedef void (tOBEX_TL_CBACK)(tOBEX_TL_EVT evt, tOBEX_TL_MSG *msg);

View File

@ -10,7 +10,8 @@
#if (OBEX_INCLUDED == TRUE)
#define OBEX_TL_L2CAP_BT_HDR_MIN_OFFSET 13 /* L2CAP_MIN_OFFSET */
#define OBEX_TL_L2CAP_BT_HDR_MIN_OFFSET 13 /* equal to L2CAP_MIN_OFFSET */
#define OBEX_TL_L2CAP_BT_HDR_RESERVE_LEN 0 /* not require any additional byte */
tOBEX_TL_OPS *obex_tl_l2cap_ops_get(void);

View File

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "obex_tl.h"
#if (OBEX_INCLUDED == TRUE && RFCOMM_INCLUDED == TRUE)
#define OBEX_TL_RFCOMM_BT_HDR_MIN_OFFSET 18 /* RFCOMM_MIN_OFFSET + L2CAP_MIN_OFFSET */
#define OBEX_TL_RFCOMM_BT_HDR_RESERVE_LEN 1 /* reserve 1 byte for rfcomm fcs */
tOBEX_TL_OPS *obex_tl_rfcomm_ops_get(void);
#endif /* #if (OBEX_INCLUDED == TRUE && RFCOMM_INCLUDED == TRUE) */

View File

@ -14,6 +14,7 @@
#include "obex_int.h"
#include "obex_tl.h"
#include "obex_tl_l2cap.h"
#include "obex_tl_rfcomm.h"
#if (OBEX_INCLUDED == TRUE)
@ -25,6 +26,12 @@ static inline void obex_server_to_tl_server(tOBEX_SVR_INFO *server, tOBEX_TL_SVR
tl_server->l2cap.pref_mtu = server->l2cap.pref_mtu;
bdcpy(tl_server->l2cap.addr, server->l2cap.addr);
}
else if (server->tl == OBEX_OVER_RFCOMM) {
tl_server->rfcomm.scn = server->rfcomm.scn;
tl_server->rfcomm.sec_mask = server->rfcomm.sec_mask;
tl_server->rfcomm.pref_mtu = server->rfcomm.pref_mtu;
bdcpy(tl_server->rfcomm.addr, server->rfcomm.addr);
}
else {
OBEX_TRACE_ERROR("Unsupported OBEX transport type\n");
assert(0);
@ -62,13 +69,12 @@ UINT16 OBEX_Init(void)
if (obex_cb.tl_ops[OBEX_OVER_L2CAP]->init != NULL) {
obex_cb.tl_ops[OBEX_OVER_L2CAP]->init(obex_tl_l2cap_callback);
}
/* Not implement yet */
/*
#if (RFCOMM_INCLUDED == TRUE)
obex_cb.tl_ops[OBEX_OVER_RFCOMM] = obex_tl_rfcomm_ops_get();
if (obex_cb.tl_ops[OBEX_OVER_RFCOMM]->init != NULL) {
obex_cb.tl_ops[OBEX_OVER_RFCOMM]->init(obex_tl_rfcomm_callback);
}
*/
#endif
obex_cb.trace_level = BT_TRACE_LEVEL_ERROR;
return OBEX_SUCCESS;
}
@ -317,7 +323,7 @@ UINT16 OBEX_BuildRequest(tOBEX_PARSE_INFO *info, UINT16 buff_size, BT_HDR **out_
if (buff_size < OBEX_MIN_PACKET_SIZE || info == NULL || out_pkt == NULL) {
return OBEX_INVALID_PARAM;
}
buff_size += sizeof(BT_HDR) + OBEX_BT_HDR_MIN_OFFSET;
buff_size += sizeof(BT_HDR) + OBEX_BT_HDR_MIN_OFFSET + OBEX_BT_HDR_RESERVE_LEN;
BT_HDR *p_buf= (BT_HDR *)osi_malloc(buff_size);
if (p_buf == NULL) {
@ -327,7 +333,7 @@ UINT16 OBEX_BuildRequest(tOBEX_PARSE_INFO *info, UINT16 buff_size, BT_HDR **out_
UINT16 pkt_len = OBEX_MIN_PACKET_SIZE;
p_buf->offset = OBEX_BT_HDR_MIN_OFFSET;
/* use layer_specific to store the max data length allowed */
p_buf->layer_specific = buff_size - sizeof(BT_HDR) - OBEX_BT_HDR_MIN_OFFSET;
p_buf->layer_specific = buff_size - sizeof(BT_HDR) - OBEX_BT_HDR_MIN_OFFSET - OBEX_BT_HDR_RESERVE_LEN;
UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
/* byte 0: opcode */
*p_data++ = info->opcode;
@ -378,7 +384,7 @@ UINT16 OBEX_BuildResponse(tOBEX_PARSE_INFO *info, UINT16 buff_size, BT_HDR **out
if (buff_size < OBEX_MIN_PACKET_SIZE || info == NULL || out_pkt == NULL) {
return OBEX_INVALID_PARAM;
}
buff_size += sizeof(BT_HDR) + OBEX_BT_HDR_MIN_OFFSET;
buff_size += sizeof(BT_HDR) + OBEX_BT_HDR_MIN_OFFSET + OBEX_BT_HDR_RESERVE_LEN;
BT_HDR *p_buf= (BT_HDR *)osi_malloc(buff_size);
if (p_buf == NULL) {
@ -388,7 +394,7 @@ UINT16 OBEX_BuildResponse(tOBEX_PARSE_INFO *info, UINT16 buff_size, BT_HDR **out
UINT16 pkt_len = OBEX_MIN_PACKET_SIZE;
p_buf->offset = OBEX_BT_HDR_MIN_OFFSET;
/* use layer_specific to store the max data length allowed */
p_buf->layer_specific = buff_size - sizeof(BT_HDR) - OBEX_BT_HDR_MIN_OFFSET;
p_buf->layer_specific = buff_size - sizeof(BT_HDR) - OBEX_BT_HDR_MIN_OFFSET - OBEX_BT_HDR_RESERVE_LEN;
UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
/* byte 0: response code */
*p_data++ = info->response_code;

View File

@ -208,4 +208,9 @@ void obex_tl_l2cap_callback(tOBEX_TL_EVT evt, tOBEX_TL_MSG *msg)
obex_tl_evt_handler(OBEX_OVER_L2CAP, evt, msg);
}
void obex_tl_rfcomm_callback(tOBEX_TL_EVT evt, tOBEX_TL_MSG *msg)
{
obex_tl_evt_handler(OBEX_OVER_RFCOMM, evt, msg);
}
#endif /* #if (OBEX_INCLUDED == TRUE) */

View File

@ -0,0 +1,439 @@
/*
* SPDX-FileCopyrightText: 2024 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");
}
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);
}
}
}
void 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");
assert(0);
}
}
#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;
}
void obex_tl_rfcomm_deinit(void)
{
#if (OBEX_DYNAMIC_MEMORY)
if (obex_tl_rfcomm_cb_ptr) {
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) */