mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-08 04:02:27 +00:00

- Fix PBAC may free undefine memory when conn failed - Fix some memory in OBEX not being freed when bluedroid deinit - Fix pre-commit not check some source file that we added to bluedroid
777 lines
23 KiB
C
777 lines
23 KiB
C
/*
|
|
* 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/obex_api.h"
|
|
#include "obex_int.h"
|
|
#include "obex_tl.h"
|
|
#include "obex_tl_l2cap.h"
|
|
#include "obex_tl_rfcomm.h"
|
|
|
|
#if (OBEX_INCLUDED == TRUE)
|
|
|
|
static inline void obex_server_to_tl_server(tOBEX_SVR_INFO *server, tOBEX_TL_SVR_INFO *tl_server)
|
|
{
|
|
if (server->tl == OBEX_OVER_L2CAP) {
|
|
tl_server->l2cap.psm = server->l2cap.psm;
|
|
tl_server->l2cap.sec_mask = server->l2cap.sec_mask;
|
|
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);
|
|
}
|
|
}
|
|
|
|
static inline void obex_updata_packet_length(BT_HDR *p_buf, UINT16 len)
|
|
{
|
|
UINT8 *p_pkt_len = (UINT8 *)(p_buf + 1) + p_buf->offset + 1;
|
|
UINT16_TO_BE_FIELD(p_pkt_len, len);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_Init
|
|
**
|
|
** Description Initialize OBEX Profile, must call before using any other
|
|
** OBEX APIs
|
|
**
|
|
** Returns OBEX_SUCCESS if successful, otherwise failed
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 OBEX_Init(void)
|
|
{
|
|
#if (OBEX_DYNAMIC_MEMORY)
|
|
if (!obex_cb_ptr) {
|
|
obex_cb_ptr = (tOBEX_CB *)osi_malloc(sizeof(tOBEX_CB));
|
|
if (!obex_cb_ptr) {
|
|
return OBEX_NO_RESOURCES;
|
|
}
|
|
}
|
|
#endif /* #if (OBEX_DYNAMIC_MEMORY) */
|
|
memset(&obex_cb, 0, sizeof(tOBEX_CB));
|
|
obex_cb.tl_ops[OBEX_OVER_L2CAP] = obex_tl_l2cap_ops_get();
|
|
if (obex_cb.tl_ops[OBEX_OVER_L2CAP]->init != NULL) {
|
|
obex_cb.tl_ops[OBEX_OVER_L2CAP]->init(obex_tl_l2cap_callback);
|
|
}
|
|
#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;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_Deinit
|
|
**
|
|
** Description Deinit OBEX profile, once deinit, can not use any other
|
|
** APIs until call OBEX_Init again
|
|
**
|
|
*******************************************************************************/
|
|
void OBEX_Deinit(void)
|
|
{
|
|
if (obex_cb.tl_ops[OBEX_OVER_L2CAP]->deinit != NULL) {
|
|
obex_cb.tl_ops[OBEX_OVER_L2CAP]->deinit();
|
|
}
|
|
#if (RFCOMM_INCLUDED == TRUE)
|
|
if (obex_cb.tl_ops[OBEX_OVER_RFCOMM]->deinit != NULL) {
|
|
obex_cb.tl_ops[OBEX_OVER_RFCOMM]->deinit();
|
|
}
|
|
#endif
|
|
#if (OBEX_DYNAMIC_MEMORY)
|
|
if (obex_cb_ptr) {
|
|
osi_free(obex_cb_ptr);
|
|
obex_cb_ptr = NULL;
|
|
}
|
|
#endif /* #if (OBEX_DYNAMIC_MEMORY) */
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_CreateConn
|
|
**
|
|
** Description Start the progress of creating an OBEX connection
|
|
**
|
|
** Returns OBEX_SUCCESS if successful, otherwise failed, when the
|
|
** connection is opened, an OBEX_CONNECT_EVT will come
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 OBEX_CreateConn(tOBEX_SVR_INFO *server, tOBEX_MSG_CBACK callback, UINT16 *out_handle)
|
|
{
|
|
UINT16 ret = OBEX_SUCCESS;
|
|
tOBEX_CCB *p_ccb = NULL;
|
|
|
|
do {
|
|
if (server->tl >= OBEX_NUM_TL) {
|
|
ret = OBEX_INVALID_PARAM;
|
|
break;
|
|
}
|
|
|
|
p_ccb = obex_allocate_ccb();
|
|
if (p_ccb == NULL) {
|
|
ret = OBEX_NO_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
tOBEX_TL_SVR_INFO tl_server = {0};
|
|
obex_server_to_tl_server(server, &tl_server);
|
|
p_ccb->tl = server->tl;
|
|
p_ccb->tl_hdl = obex_cb.tl_ops[p_ccb->tl]->connect(&tl_server);
|
|
if (p_ccb->tl_hdl == 0) {
|
|
ret = OBEX_ERROR_TL;
|
|
break;
|
|
}
|
|
|
|
p_ccb->callback = callback;
|
|
p_ccb->role = OBEX_ROLE_CLIENT;
|
|
p_ccb->state = OBEX_STATE_OPENING;
|
|
*out_handle = p_ccb->allocated;
|
|
} while (0);
|
|
|
|
if (ret != OBEX_SUCCESS && p_ccb != NULL) {
|
|
obex_free_ccb(p_ccb);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_RemoveConn
|
|
**
|
|
** Description Remove an OBEX connection
|
|
**
|
|
** Returns OBEX_SUCCESS if successful, otherwise failed
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 OBEX_RemoveConn(UINT16 handle)
|
|
{
|
|
tOBEX_CCB *p_ccb = NULL;
|
|
|
|
UINT16 ccb_idx = handle - 1;
|
|
if (ccb_idx >= OBEX_MAX_CONNECTION || !obex_cb.ccb[ccb_idx].allocated) {
|
|
return OBEX_BAD_HANDLE;
|
|
}
|
|
|
|
p_ccb = &obex_cb.ccb[ccb_idx];
|
|
obex_cb.tl_ops[p_ccb->tl]->disconnect(p_ccb->tl_hdl);
|
|
obex_free_ccb(p_ccb);
|
|
|
|
return OBEX_SUCCESS;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_RegisterServer
|
|
**
|
|
** Description Register an OBEX server and listen the incoming connection
|
|
**
|
|
** Returns OBEX_SUCCESS if successful, otherwise failed
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 OBEX_RegisterServer(tOBEX_SVR_INFO *server, tOBEX_MSG_CBACK callback, UINT16 *out_svr_handle)
|
|
{
|
|
UINT8 ret = OBEX_SUCCESS;
|
|
tOBEX_SCB *p_scb = NULL;
|
|
|
|
do {
|
|
if (server->tl >= OBEX_NUM_TL) {
|
|
ret = OBEX_INVALID_PARAM;
|
|
break;
|
|
}
|
|
|
|
p_scb = obex_allocate_scb();
|
|
if (p_scb == NULL) {
|
|
ret = OBEX_NO_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
tOBEX_TL_SVR_INFO tl_server = {0};
|
|
obex_server_to_tl_server(server, &tl_server);
|
|
p_scb->tl = server->tl;
|
|
p_scb->tl_hdl = obex_cb.tl_ops[p_scb->tl]->bind(&tl_server);
|
|
if (p_scb->tl_hdl == 0) {
|
|
ret = OBEX_ERROR_TL;
|
|
break;
|
|
}
|
|
p_scb->callback = callback;
|
|
|
|
if (out_svr_handle) {
|
|
/* To avoid confuse with connection handle, left shift 8 bit */
|
|
*out_svr_handle = p_scb->allocated << 8;
|
|
}
|
|
} while (0);
|
|
|
|
if (ret != OBEX_SUCCESS && p_scb != NULL) {
|
|
obex_free_scb(p_scb);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_DeregisterServer
|
|
**
|
|
** Description Deregister an OBEX server, if there are still a connection
|
|
** alive, the behavior depend on the implementation of transport
|
|
** layer
|
|
**
|
|
** Returns OBEX_SUCCESS if successful, otherwise failed
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 OBEX_DeregisterServer(UINT16 svr_handle)
|
|
{
|
|
tOBEX_SCB *p_scb = NULL;
|
|
|
|
UINT16 scb_idx = (svr_handle >> 8) - 1;
|
|
if (scb_idx >= OBEX_MAX_SERVER || !obex_cb.scb[scb_idx].allocated) {
|
|
return OBEX_BAD_HANDLE;
|
|
}
|
|
|
|
p_scb = &obex_cb.scb[scb_idx];
|
|
obex_cb.tl_ops[p_scb->tl]->unbind(p_scb->tl_hdl);
|
|
obex_free_scb(p_scb);
|
|
return OBEX_SUCCESS;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_SendPacket
|
|
**
|
|
** Description Send a packet to peer OBEX server or client, once call
|
|
** this function, the ownership of pkt is lost, do not free
|
|
** or modify the pkt any more
|
|
**
|
|
** Returns OBEX_SUCCESS if successful, otherwise failed
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 OBEX_SendPacket(UINT16 handle, BT_HDR *pkt)
|
|
{
|
|
UINT16 ret = OBEX_SUCCESS;
|
|
BOOLEAN free_pkt = true;
|
|
tOBEX_CCB *p_ccb = NULL;
|
|
do {
|
|
if (pkt == NULL) {
|
|
ret = OBEX_INVALID_PARAM;
|
|
break;
|
|
}
|
|
|
|
UINT16 ccb_idx = handle - 1;
|
|
if (ccb_idx >= OBEX_MAX_CONNECTION || !obex_cb.ccb[ccb_idx].allocated) {
|
|
ret = OBEX_BAD_HANDLE;
|
|
break;
|
|
}
|
|
|
|
p_ccb = &obex_cb.ccb[ccb_idx];
|
|
if (p_ccb->state != OBEX_STATE_OPENED) {
|
|
ret = OBEX_NOT_OPEN;
|
|
break;
|
|
}
|
|
|
|
if (pkt->len > p_ccb->tl_peer_mtu) {
|
|
ret = OBEX_PACKET_TOO_LARGE;
|
|
break;
|
|
}
|
|
|
|
ret = obex_cb.tl_ops[p_ccb->tl]->send(p_ccb->tl_hdl, pkt);
|
|
/* packet has pass to lower layer, do not free it */
|
|
free_pkt = false;
|
|
if (ret == OBEX_TL_SUCCESS || ret == OBEX_TL_CONGESTED) {
|
|
ret = OBEX_SUCCESS;
|
|
}
|
|
else {
|
|
ret = OBEX_ERROR_TL;
|
|
}
|
|
} while (0);
|
|
|
|
if (free_pkt) {
|
|
osi_free(pkt);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_BuildRequest
|
|
**
|
|
** Description Build a request packet with opcode and additional info,
|
|
** packet can free by osi_free
|
|
**
|
|
** Returns OBEX_SUCCESS if successful, otherwise failed
|
|
**
|
|
*******************************************************************************/
|
|
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) {
|
|
return OBEX_INVALID_PARAM;
|
|
}
|
|
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) {
|
|
return OBEX_NO_RESOURCES;
|
|
}
|
|
|
|
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 - OBEX_BT_HDR_RESERVE_LEN;
|
|
UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
|
/* byte 0: opcode */
|
|
*p_data++ = info->opcode;
|
|
/* byte 1, 2: packet length, skip, we will update at last */
|
|
UINT8 *p_pkt_len = p_data;
|
|
p_data += 2;
|
|
|
|
switch (info->opcode)
|
|
{
|
|
case OBEX_OPCODE_CONNECT:
|
|
/* byte 3: OBEX version number */
|
|
*p_data++ = info->obex_version_number;
|
|
/* byte 4: flags */
|
|
*p_data++ = info->flags;
|
|
/* byte 5, 6: maximum OBEX packet length, recommend to set as our mtu*/
|
|
UINT16_TO_BE_FIELD(p_data, info->max_packet_length);
|
|
pkt_len += 4;
|
|
break;
|
|
case OBEX_OPCODE_SETPATH:
|
|
/* byte 3: flags */
|
|
*p_data++ = info->flags;
|
|
/* byte 4: constants, reserved, must be zero */
|
|
*p_data++ = 0;
|
|
pkt_len += 2;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
UINT16_TO_BE_FIELD(p_pkt_len, pkt_len);
|
|
p_buf->len = pkt_len;
|
|
*out_pkt = p_buf;
|
|
return OBEX_SUCCESS;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_BuildResponse
|
|
**
|
|
** Description Build a response packet with opcode and response and additional
|
|
** info, packet can by free by osi_free
|
|
**
|
|
** Returns OBEX_SUCCESS if successful, otherwise failed
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 OBEX_BuildResponse(tOBEX_PARSE_INFO *info, UINT16 buff_size, BT_HDR **out_pkt)
|
|
{
|
|
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 + OBEX_BT_HDR_RESERVE_LEN;
|
|
|
|
BT_HDR *p_buf= (BT_HDR *)osi_malloc(buff_size);
|
|
if (p_buf == NULL) {
|
|
return OBEX_NO_RESOURCES;
|
|
}
|
|
|
|
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 - OBEX_BT_HDR_RESERVE_LEN;
|
|
UINT8 *p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
|
/* byte 0: response code */
|
|
*p_data++ = info->response_code;
|
|
/* byte 1, 2: packet length, skip, we will update at last */
|
|
UINT8 *p_pkt_len = p_data;
|
|
p_data += 2;
|
|
|
|
/* we need to use opcode to decide the response format */
|
|
switch (info->opcode)
|
|
{
|
|
case OBEX_OPCODE_CONNECT:
|
|
/* byte 3: OBEX version number */
|
|
*p_data++ = info->obex_version_number;
|
|
/* byte 4: flags */
|
|
*p_data++ = info->flags;
|
|
/* byte 5, 6: maximum OBEX packet length, recommend to set as our mtu */
|
|
UINT16_TO_BE_FIELD(p_data, info->max_packet_length);
|
|
pkt_len += 4;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
UINT16_TO_BE_FIELD(p_pkt_len, pkt_len);
|
|
p_buf->len = pkt_len;
|
|
*out_pkt = p_buf;
|
|
return OBEX_SUCCESS;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_AppendHeader
|
|
**
|
|
** Description Append a header to specific packet, packet can be request
|
|
** or response, the format of header must be valid
|
|
**
|
|
** Returns OBEX_SUCCESS if successful, otherwise failed
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 OBEX_AppendHeader(BT_HDR *pkt, const UINT8 *header)
|
|
{
|
|
if (pkt == NULL || header == NULL) {
|
|
return OBEX_INVALID_PARAM;
|
|
}
|
|
|
|
UINT16 header_len = 0;
|
|
UINT8 header_id = *header;
|
|
switch (header_id & OBEX_HEADER_ID_U2B_MASK)
|
|
{
|
|
case OBEX_HEADER_ID_U2B_TYPE1:
|
|
case OBEX_HEADER_ID_U2B_TYPE2:
|
|
header_len = (header[1] << 8) + header[2];
|
|
break;
|
|
case OBEX_HEADER_ID_U2B_TYPE3:
|
|
header_len = 2;
|
|
break;
|
|
case OBEX_HEADER_ID_U2B_TYPE4:
|
|
header_len = 5;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (header_len == 0) {
|
|
return OBEX_INVALID_PARAM;
|
|
}
|
|
|
|
if (pkt->layer_specific - pkt->len < header_len) {
|
|
/* the packet can not hold this header */
|
|
return OBEX_NO_RESOURCES;
|
|
}
|
|
UINT8 *p_data = (UINT8 *)(pkt + 1) + pkt->offset;
|
|
UINT8 *p_start = p_data + pkt->len;
|
|
memcpy(p_start, header, header_len);
|
|
pkt->len += header_len;
|
|
/* point to packet len */
|
|
p_data++;
|
|
UINT16_TO_BE_FIELD(p_data, pkt->len);
|
|
return OBEX_SUCCESS;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_AppendHeaderRaw
|
|
**
|
|
** Description Append a header to specific packet, packet can be request
|
|
** or response, data not include 2 byte length prefixed
|
|
**
|
|
** Returns OBEX_SUCCESS if successful, otherwise failed
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 OBEX_AppendHeaderRaw(BT_HDR *pkt, UINT8 header_id, const UINT8 *data, UINT16 data_len)
|
|
{
|
|
if (pkt == NULL) {
|
|
return OBEX_INVALID_PARAM;
|
|
}
|
|
|
|
if ((data == NULL && data_len != 0) || (data != NULL && data_len == 0)) {
|
|
return OBEX_INVALID_PARAM;
|
|
}
|
|
|
|
UINT16 header_len = 0;
|
|
BOOLEAN store_header_len = FALSE;
|
|
switch (header_id & OBEX_HEADER_ID_U2B_MASK)
|
|
{
|
|
case OBEX_HEADER_ID_U2B_TYPE1:
|
|
case OBEX_HEADER_ID_U2B_TYPE2:
|
|
/* header id + 2 byte length prefixed + data */
|
|
header_len = data_len + 3;
|
|
store_header_len = TRUE;
|
|
break;
|
|
case OBEX_HEADER_ID_U2B_TYPE3:
|
|
header_len = 2;
|
|
if (data_len != 1) {
|
|
return OBEX_INVALID_PARAM;
|
|
}
|
|
break;
|
|
case OBEX_HEADER_ID_U2B_TYPE4:
|
|
header_len = 5;
|
|
if (data_len != 4) {
|
|
return OBEX_INVALID_PARAM;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (header_len == 0) {
|
|
return OBEX_INVALID_PARAM;
|
|
}
|
|
|
|
if (pkt->layer_specific - pkt->len < header_len) {
|
|
/* the packet can not hold this header */
|
|
return OBEX_NO_RESOURCES;
|
|
}
|
|
UINT8 *p_data = (UINT8 *)(pkt + 1) + pkt->offset;
|
|
UINT8 *p_start = p_data + pkt->len;
|
|
/* store header id */
|
|
*p_start++ = header_id;
|
|
if (store_header_len) {
|
|
/* store header length */
|
|
UINT16_TO_BE_FIELD(p_start, header_len);
|
|
p_start+= 2;
|
|
}
|
|
if (data != NULL) {
|
|
/* store data */
|
|
memcpy(p_start, data, data_len);
|
|
}
|
|
pkt->len += header_len;
|
|
/* point to packet len */
|
|
p_data++;
|
|
UINT16_TO_BE_FIELD(p_data, pkt->len);
|
|
return OBEX_SUCCESS;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_AppendHeaderSRM
|
|
**
|
|
** Description Append a Single Response Mode header
|
|
**
|
|
** Returns OBEX_SUCCESS if successful, otherwise failed
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 OBEX_AppendHeaderSRM(BT_HDR *pkt, UINT8 value)
|
|
{
|
|
return OBEX_AppendHeaderRaw(pkt, OBEX_HEADER_ID_SRM, &value, 1);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_AppendHeaderSRMP
|
|
**
|
|
** Description Append a Single Response Mode Parameters header
|
|
**
|
|
** Returns OBEX_SUCCESS if successful, otherwise failed
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 OBEX_AppendHeaderSRMP(BT_HDR *pkt, UINT8 value)
|
|
{
|
|
return OBEX_AppendHeaderRaw(pkt, OBEX_HEADER_ID_SRM_PARAM, &value, 1);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_GetPacketFreeSpace
|
|
**
|
|
** Description Get the current free space of a packet, use this to check
|
|
** if a packet can hold a header
|
|
**
|
|
** Returns Current free space of a packet, in bytes
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 OBEX_GetPacketFreeSpace(BT_HDR *pkt)
|
|
{
|
|
if (pkt == NULL) {
|
|
return 0;
|
|
}
|
|
return pkt->layer_specific - pkt->len;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_GetPacketLength
|
|
**
|
|
** Description Get the current packet length
|
|
**
|
|
** Returns Current packet length, in bytes
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 OBEX_GetPacketLength(BT_HDR *pkt)
|
|
{
|
|
if (pkt == NULL) {
|
|
return 0;
|
|
}
|
|
return pkt->len;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_ParseRequest
|
|
**
|
|
** Description Parse a request packet
|
|
**
|
|
** Returns OBEX_SUCCESS if successful, otherwise failed
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 OBEX_ParseRequest(BT_HDR *pkt, tOBEX_PARSE_INFO *info)
|
|
{
|
|
if (pkt == NULL || info == NULL) {
|
|
return OBEX_INVALID_PARAM;
|
|
}
|
|
|
|
UINT8 *p_data = (UINT8 *)(pkt + 1) + pkt->offset;
|
|
info->opcode = *p_data;
|
|
switch (info->opcode)
|
|
{
|
|
case OBEX_OPCODE_CONNECT:
|
|
info->obex_version_number = p_data[3];
|
|
info->flags = p_data[4];
|
|
info->max_packet_length = (p_data[5] << 8) + p_data[6];
|
|
info->next_header_pos = 7;
|
|
break;
|
|
case OBEX_OPCODE_SETPATH:
|
|
info->flags = p_data[3];
|
|
info->next_header_pos = 5;
|
|
break;
|
|
default:
|
|
info->next_header_pos = 3;
|
|
break;
|
|
}
|
|
return OBEX_SUCCESS;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_ParseResponse
|
|
**
|
|
** Description Parse a request response packet
|
|
**
|
|
** Returns OBEX_SUCCESS if successful, otherwise failed
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 OBEX_ParseResponse(BT_HDR *pkt, UINT8 opcode, tOBEX_PARSE_INFO *info)
|
|
{
|
|
if (pkt == NULL || info == NULL) {
|
|
return OBEX_INVALID_PARAM;
|
|
}
|
|
|
|
UINT8 *p_data = (UINT8 *)(pkt + 1) + pkt->offset;
|
|
info->opcode = opcode;
|
|
info->response_code = *p_data;
|
|
switch (opcode)
|
|
{
|
|
case OBEX_OPCODE_CONNECT:
|
|
info->obex_version_number = p_data[3];
|
|
info->flags = p_data[4];
|
|
info->max_packet_length = (p_data[5] << 8) + p_data[6];
|
|
info->next_header_pos = 7;
|
|
break;
|
|
default:
|
|
info->next_header_pos = 3;
|
|
break;
|
|
}
|
|
return OBEX_SUCCESS;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_CheckFinalBit
|
|
**
|
|
** Description Check whether a packet had set the final bit
|
|
**
|
|
** Returns TRUE if final bit set, otherwise, false
|
|
**
|
|
*******************************************************************************/
|
|
BOOLEAN OBEX_CheckFinalBit(BT_HDR *pkt)
|
|
{
|
|
if (pkt == NULL) {
|
|
return FALSE;
|
|
}
|
|
UINT8 *p_data = (UINT8 *)(pkt + 1) + pkt->offset;
|
|
return (*p_data) & OBEX_FINAL_BIT_MASK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_CheckContinueResponse
|
|
**
|
|
** Description Check whether a packet is continue response
|
|
**
|
|
** Returns TRUE if continue response, otherwise, false
|
|
**
|
|
*******************************************************************************/
|
|
BOOLEAN OBEX_CheckContinueResponse(BT_HDR *pkt)
|
|
{
|
|
if (pkt == NULL) {
|
|
return FALSE;
|
|
}
|
|
UINT8 *p_data = (UINT8 *)(pkt + 1) + pkt->offset;
|
|
return (*p_data == 0x90) || (*p_data == 0x10);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_GetHeaderLength
|
|
**
|
|
** Description Get header length
|
|
**
|
|
** Returns header length
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 OBEX_GetHeaderLength(UINT8 *header)
|
|
{
|
|
UINT16 header_len = 0;
|
|
UINT8 header_id = *header;
|
|
switch (header_id & OBEX_HEADER_ID_U2B_MASK)
|
|
{
|
|
case OBEX_HEADER_ID_U2B_TYPE1:
|
|
case OBEX_HEADER_ID_U2B_TYPE2:
|
|
header_len = (header[1] << 8) + header[2];
|
|
break;
|
|
case OBEX_HEADER_ID_U2B_TYPE3:
|
|
header_len = 2;
|
|
break;
|
|
case OBEX_HEADER_ID_U2B_TYPE4:
|
|
header_len = 5;
|
|
break;
|
|
default:
|
|
/* unreachable */
|
|
break;
|
|
}
|
|
return header_len;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function OBEX_GetNextHeader
|
|
**
|
|
** Description Get next header pointer from a packet
|
|
**
|
|
** Returns Pointer to start address of a header, NULL if no more header
|
|
** or failed
|
|
**
|
|
*******************************************************************************/
|
|
UINT8 *OBEX_GetNextHeader(BT_HDR *pkt, tOBEX_PARSE_INFO *info)
|
|
{
|
|
if (pkt == NULL || info == NULL) {
|
|
return NULL;
|
|
}
|
|
UINT8 *p_data = (UINT8 *)(pkt + 1) + pkt->offset;
|
|
if (info->next_header_pos == 0 || info->next_header_pos >= pkt->len) {
|
|
return NULL;
|
|
}
|
|
UINT8 *header = p_data + info->next_header_pos;
|
|
UINT16 header_len = OBEX_GetHeaderLength(header);
|
|
info->next_header_pos += header_len;
|
|
return header;
|
|
}
|
|
|
|
#endif /* #if (OBEX_INCLUDED == TRUE) */
|