Fork ESP-IDF's bluetooth component
i want better sbc encoding, and no cla will stop me
This commit is contained in:
@@ -0,0 +1,638 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2008-2014 Broadcom Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* this file contains ATT protocol functions
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "common/bt_target.h"
|
||||
#include "osi/allocator.h"
|
||||
|
||||
#if BLE_INCLUDED == TRUE
|
||||
|
||||
#include "gatt_int.h"
|
||||
#include "stack/l2c_api.h"
|
||||
|
||||
#define GATT_HDR_FIND_TYPE_VALUE_LEN 21
|
||||
#define GATT_OP_CODE_SIZE 1
|
||||
/**********************************************************************
|
||||
** ATT protocl message building utility *
|
||||
***********************************************************************/
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function attp_build_mtu_exec_cmd
|
||||
**
|
||||
** Description Build a exchange MTU request
|
||||
**
|
||||
** Returns None.
|
||||
**
|
||||
*******************************************************************************/
|
||||
BT_HDR *attp_build_mtu_cmd(UINT8 op_code, UINT16 rx_mtu)
|
||||
{
|
||||
BT_HDR *p_buf = NULL;
|
||||
UINT8 *p;
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + GATT_HDR_SIZE + L2CAP_MIN_OFFSET)) != NULL) {
|
||||
p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
|
||||
|
||||
UINT8_TO_STREAM (p, op_code);
|
||||
UINT16_TO_STREAM (p, rx_mtu);
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET;
|
||||
p_buf->len = GATT_HDR_SIZE; /* opcode + 2 bytes mtu */
|
||||
}
|
||||
return p_buf;
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function attp_build_exec_write_cmd
|
||||
**
|
||||
** Description Build a execute write request or response.
|
||||
**
|
||||
** Returns None.
|
||||
**
|
||||
*******************************************************************************/
|
||||
BT_HDR *attp_build_exec_write_cmd (UINT8 op_code, UINT8 flag)
|
||||
{
|
||||
BT_HDR *p_buf = NULL;
|
||||
UINT8 *p;
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(GATT_DATA_BUF_SIZE)) != NULL) {
|
||||
p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET;
|
||||
p_buf->len = GATT_OP_CODE_SIZE;
|
||||
|
||||
UINT8_TO_STREAM (p, op_code);
|
||||
|
||||
if (op_code == GATT_REQ_EXEC_WRITE) {
|
||||
flag &= GATT_PREP_WRITE_EXEC;
|
||||
UINT8_TO_STREAM (p, flag);
|
||||
p_buf->len += 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return p_buf;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function attp_build_err_cmd
|
||||
**
|
||||
** Description Build a exchange MTU request
|
||||
**
|
||||
** Returns None.
|
||||
**
|
||||
*******************************************************************************/
|
||||
BT_HDR *attp_build_err_cmd(UINT8 cmd_code, UINT16 err_handle, UINT8 reason)
|
||||
{
|
||||
BT_HDR *p_buf = NULL;
|
||||
UINT8 *p;
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + 5)) != NULL) {
|
||||
p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
|
||||
|
||||
UINT8_TO_STREAM (p, GATT_RSP_ERROR);
|
||||
UINT8_TO_STREAM (p, cmd_code);
|
||||
UINT16_TO_STREAM(p, err_handle);
|
||||
UINT8_TO_STREAM (p, reason);
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET;
|
||||
/* GATT_HDR_SIZE (1B ERR_RSP op code+ 2B handle) + 1B cmd_op_code + 1B status */
|
||||
p_buf->len = GATT_HDR_SIZE + 1 + 1;
|
||||
}
|
||||
return p_buf;
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function attp_build_browse_cmd
|
||||
**
|
||||
** Description Build a read information request or read by type request
|
||||
**
|
||||
** Returns None.
|
||||
**
|
||||
*******************************************************************************/
|
||||
BT_HDR *attp_build_browse_cmd(UINT8 op_code, UINT16 s_hdl, UINT16 e_hdl, tBT_UUID uuid)
|
||||
{
|
||||
BT_HDR *p_buf = NULL;
|
||||
UINT8 *p;
|
||||
/* length of ATT_READ_BY_TYPE_REQ PDU: opcode(1) + start_handle (2) + end_handle (2) + uuid (2 or 16) */
|
||||
const UINT8 payload_size = 1 + 2 + 2 + ((uuid.len == LEN_UUID_16) ? LEN_UUID_16 : LEN_UUID_128);
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET)) != NULL) {
|
||||
p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
|
||||
/* Describe the built message location and size */
|
||||
p_buf->offset = L2CAP_MIN_OFFSET;
|
||||
p_buf->len = GATT_OP_CODE_SIZE + 4;
|
||||
|
||||
UINT8_TO_STREAM (p, op_code);
|
||||
UINT16_TO_STREAM (p, s_hdl);
|
||||
UINT16_TO_STREAM (p, e_hdl);
|
||||
p_buf->len += gatt_build_uuid_to_stream(&p, uuid);
|
||||
}
|
||||
|
||||
return p_buf;
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function attp_build_read_handles_cmd
|
||||
**
|
||||
** Description Build a read by type and value request.
|
||||
**
|
||||
** Returns pointer to the command buffer.
|
||||
**
|
||||
*******************************************************************************/
|
||||
BT_HDR *attp_build_read_by_type_value_cmd (UINT16 payload_size, tGATT_FIND_TYPE_VALUE *p_value_type)
|
||||
{
|
||||
BT_HDR *p_buf = NULL;
|
||||
UINT8 *p;
|
||||
UINT16 len = p_value_type->value_len;
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc((UINT16)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET))) != NULL) {
|
||||
p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET;
|
||||
p_buf->len = 5; /* opcode + s_handle + e_handle */
|
||||
|
||||
UINT8_TO_STREAM (p, GATT_REQ_FIND_TYPE_VALUE);
|
||||
UINT16_TO_STREAM (p, p_value_type->s_handle);
|
||||
UINT16_TO_STREAM (p, p_value_type->e_handle);
|
||||
|
||||
p_buf->len += gatt_build_uuid_to_stream(&p, p_value_type->uuid);
|
||||
|
||||
if (p_value_type->value_len + p_buf->len > payload_size ) {
|
||||
len = payload_size - p_buf->len;
|
||||
}
|
||||
|
||||
memcpy (p, p_value_type->value, len);
|
||||
p_buf->len += len;
|
||||
}
|
||||
|
||||
return p_buf;
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function attp_build_read_multi_cmd
|
||||
**
|
||||
** Description Build a read multiple request
|
||||
**
|
||||
** Returns None.
|
||||
**
|
||||
*******************************************************************************/
|
||||
BT_HDR *attp_build_read_multi_cmd(UINT8 op_code, UINT16 payload_size, UINT16 num_handle, UINT16 *p_handle)
|
||||
{
|
||||
BT_HDR *p_buf = NULL;
|
||||
UINT8 *p, i = 0;
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc((UINT16)(sizeof(BT_HDR) + num_handle * 2 + 1 + L2CAP_MIN_OFFSET))) != NULL) {
|
||||
p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET;
|
||||
p_buf->len = 1;
|
||||
|
||||
UINT8_TO_STREAM (p, op_code);
|
||||
|
||||
for (i = 0; i < num_handle && p_buf->len + 2 <= payload_size; i ++) {
|
||||
UINT16_TO_STREAM (p, *(p_handle + i));
|
||||
p_buf->len += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return p_buf;
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function attp_build_handle_cmd
|
||||
**
|
||||
** Description Build a read /read blob request
|
||||
**
|
||||
** Returns None.
|
||||
**
|
||||
*******************************************************************************/
|
||||
BT_HDR *attp_build_handle_cmd(UINT8 op_code, UINT16 handle, UINT16 offset)
|
||||
{
|
||||
BT_HDR *p_buf = NULL;
|
||||
UINT8 *p;
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + 5 + L2CAP_MIN_OFFSET)) != NULL) {
|
||||
p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
|
||||
|
||||
p_buf->offset = L2CAP_MIN_OFFSET;
|
||||
|
||||
UINT8_TO_STREAM (p, op_code);
|
||||
p_buf->len = 1;
|
||||
|
||||
UINT16_TO_STREAM (p, handle);
|
||||
p_buf->len += 2;
|
||||
|
||||
if (op_code == GATT_REQ_READ_BLOB) {
|
||||
UINT16_TO_STREAM (p, offset);
|
||||
p_buf->len += 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return p_buf;
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function attp_build_opcode_cmd
|
||||
**
|
||||
** Description Build a request/response with opcode only.
|
||||
**
|
||||
** Returns None.
|
||||
**
|
||||
*******************************************************************************/
|
||||
BT_HDR *attp_build_opcode_cmd(UINT8 op_code)
|
||||
{
|
||||
BT_HDR *p_buf = NULL;
|
||||
UINT8 *p;
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + 1 + L2CAP_MIN_OFFSET)) != NULL) {
|
||||
p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
|
||||
p_buf->offset = L2CAP_MIN_OFFSET;
|
||||
|
||||
UINT8_TO_STREAM (p, op_code);
|
||||
p_buf->len = 1;
|
||||
}
|
||||
|
||||
return p_buf;
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function attp_build_value_cmd
|
||||
**
|
||||
** Description Build a attribute value request
|
||||
**
|
||||
** Returns None.
|
||||
**
|
||||
*******************************************************************************/
|
||||
BT_HDR *attp_build_value_cmd (UINT16 payload_size, UINT8 op_code, UINT16 handle,
|
||||
UINT16 offset, UINT16 len, UINT8 *p_data)
|
||||
{
|
||||
BT_HDR *p_buf = NULL;
|
||||
UINT8 *p, *pp, pair_len, *p_pair_len;
|
||||
|
||||
if ((p_buf = (BT_HDR *)osi_malloc((UINT16)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET))) != NULL) {
|
||||
p = pp = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
|
||||
|
||||
UINT8_TO_STREAM (p, op_code);
|
||||
p_buf->offset = L2CAP_MIN_OFFSET;
|
||||
p_buf->len = 1;
|
||||
|
||||
if (op_code == GATT_RSP_READ_BY_TYPE) {
|
||||
p_pair_len = p;
|
||||
pair_len = len + 2;
|
||||
UINT8_TO_STREAM (p, pair_len);
|
||||
p_buf->len += 1;
|
||||
}
|
||||
if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ && op_code != GATT_HANDLE_MULTI_VALUE_NOTIF) {
|
||||
UINT16_TO_STREAM (p, handle);
|
||||
p_buf->len += 2;
|
||||
}
|
||||
|
||||
if (op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_RSP_PREPARE_WRITE ) {
|
||||
UINT16_TO_STREAM (p, offset);
|
||||
p_buf->len += 2;
|
||||
}
|
||||
|
||||
if(payload_size < GATT_DEF_BLE_MTU_SIZE || payload_size > GATT_MAX_MTU_SIZE) {
|
||||
GATT_TRACE_ERROR("invalid payload_size %d", payload_size);
|
||||
osi_free(p_buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (len > 0 && p_data != NULL) {
|
||||
/* ensure data not exceed MTU size */
|
||||
if (payload_size - p_buf->len < len) {
|
||||
len = payload_size - p_buf->len;
|
||||
/* update handle value pair length */
|
||||
if (op_code == GATT_RSP_READ_BY_TYPE) {
|
||||
*p_pair_len = (len + 2);
|
||||
}
|
||||
|
||||
GATT_TRACE_WARNING("attribute value too long, to be truncated to %d", len);
|
||||
}
|
||||
|
||||
ARRAY_TO_STREAM (p, p_data, len);
|
||||
p_buf->len += len;
|
||||
}
|
||||
}
|
||||
return p_buf;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function attp_send_msg_to_l2cap
|
||||
**
|
||||
** Description Send message to L2CAP.
|
||||
**
|
||||
*******************************************************************************/
|
||||
tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP)
|
||||
{
|
||||
UINT16 l2cap_ret;
|
||||
|
||||
|
||||
if (p_tcb->att_lcid == L2CAP_ATT_CID) {
|
||||
l2cap_ret = L2CA_SendFixedChnlData (L2CAP_ATT_CID, p_tcb->peer_bda, p_toL2CAP);
|
||||
} else {
|
||||
#if (CLASSIC_BT_INCLUDED == TRUE)
|
||||
l2cap_ret = (UINT16) L2CA_DataWrite (p_tcb->att_lcid, p_toL2CAP);
|
||||
#else
|
||||
l2cap_ret = L2CAP_DW_FAILED;
|
||||
#endif ///CLASSIC_BT_INCLUDED == TRUE
|
||||
}
|
||||
|
||||
if (l2cap_ret == L2CAP_DW_FAILED) {
|
||||
GATT_TRACE_DEBUG("ATT failed to pass msg:0x%0x to L2CAP",
|
||||
*((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset));
|
||||
return GATT_INTERNAL_ERROR;
|
||||
} else if (l2cap_ret == L2CAP_DW_CONGESTED) {
|
||||
GATT_TRACE_DEBUG("ATT congested, message accepted");
|
||||
return GATT_CONGESTED;
|
||||
}
|
||||
return GATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function attp_build_sr_msg
|
||||
**
|
||||
** Description Build ATT Server PDUs.
|
||||
**
|
||||
*******************************************************************************/
|
||||
BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, UINT8 op_code, tGATT_SR_MSG *p_msg)
|
||||
{
|
||||
BT_HDR *p_cmd = NULL;
|
||||
UINT16 offset = 0;
|
||||
|
||||
switch (op_code) {
|
||||
case GATT_RSP_READ_BLOB:
|
||||
case GATT_RSP_PREPARE_WRITE:
|
||||
case GATT_RSP_READ_BY_TYPE:
|
||||
case GATT_RSP_READ:
|
||||
case GATT_HANDLE_VALUE_NOTIF:
|
||||
case GATT_HANDLE_VALUE_IND:
|
||||
case GATT_HANDLE_MULTI_VALUE_NOTIF:
|
||||
case GATT_RSP_ERROR:
|
||||
case GATT_RSP_MTU:
|
||||
/* Need to check the validation of parameter p_msg*/
|
||||
if (p_msg == NULL) {
|
||||
GATT_TRACE_ERROR("Invalid parameters in %s, op_code=0x%x, the p_msg should not be NULL.", __func__, op_code);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (op_code) {
|
||||
case GATT_RSP_READ_BLOB:
|
||||
case GATT_RSP_PREPARE_WRITE:
|
||||
GATT_TRACE_EVENT ("ATT_RSP_READ_BLOB/GATT_RSP_PREPARE_WRITE: len = %d offset = %d",
|
||||
p_msg->attr_value.len, p_msg->attr_value.offset);
|
||||
offset = p_msg->attr_value.offset;
|
||||
/* Coverity: [FALSE-POSITIVE error] intended fall through */
|
||||
/* Missing break statement between cases in switch statement */
|
||||
/* fall through */
|
||||
case GATT_RSP_READ_BY_TYPE:
|
||||
case GATT_RSP_READ:
|
||||
case GATT_HANDLE_VALUE_NOTIF:
|
||||
case GATT_HANDLE_VALUE_IND:
|
||||
case GATT_HANDLE_MULTI_VALUE_NOTIF:
|
||||
p_cmd = attp_build_value_cmd(p_tcb->payload_size,
|
||||
op_code,
|
||||
p_msg->attr_value.handle,
|
||||
offset,
|
||||
p_msg->attr_value.len,
|
||||
p_msg->attr_value.value);
|
||||
break;
|
||||
|
||||
case GATT_RSP_WRITE:
|
||||
p_cmd = attp_build_opcode_cmd(op_code);
|
||||
break;
|
||||
|
||||
case GATT_RSP_ERROR:
|
||||
p_cmd = attp_build_err_cmd(p_msg->error.cmd_code, p_msg->error.handle, p_msg->error.reason);
|
||||
break;
|
||||
|
||||
case GATT_RSP_EXEC_WRITE:
|
||||
p_cmd = attp_build_exec_write_cmd(op_code, 0);
|
||||
break;
|
||||
|
||||
case GATT_RSP_MTU:
|
||||
p_cmd = attp_build_mtu_cmd(op_code, p_msg->mtu);
|
||||
break;
|
||||
|
||||
default:
|
||||
GATT_TRACE_DEBUG("attp_build_sr_msg: unknown op code = %d", op_code);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!p_cmd) {
|
||||
GATT_TRACE_ERROR("No resources");
|
||||
}
|
||||
|
||||
return p_cmd;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function attp_send_sr_msg
|
||||
**
|
||||
** Description This function sends the server response or indication message
|
||||
** to client.
|
||||
**
|
||||
** Parameter p_tcb: pointer to the connecton control block.
|
||||
** p_msg: pointer to message parameters structure.
|
||||
**
|
||||
** Returns GATT_SUCCESS if successfully sent; otherwise error code.
|
||||
**
|
||||
**
|
||||
*******************************************************************************/
|
||||
tGATT_STATUS attp_send_sr_msg (tGATT_TCB *p_tcb, BT_HDR *p_msg)
|
||||
{
|
||||
tGATT_STATUS cmd_sent = GATT_NO_RESOURCES;
|
||||
|
||||
if (p_tcb != NULL) {
|
||||
if (p_msg != NULL) {
|
||||
p_msg->offset = L2CAP_MIN_OFFSET;
|
||||
cmd_sent = attp_send_msg_to_l2cap (p_tcb, p_msg);
|
||||
}
|
||||
}
|
||||
return cmd_sent;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function attp_cl_send_cmd
|
||||
**
|
||||
** Description Send a ATT command or enqueue it.
|
||||
**
|
||||
** Returns GATT_SUCCESS if command sent
|
||||
** GATT_CONGESTED if command sent but channel congested
|
||||
** GATT_CMD_STARTED if command queue up in GATT
|
||||
** GATT_ERROR if command sending failure
|
||||
**
|
||||
*******************************************************************************/
|
||||
tGATT_STATUS attp_cl_send_cmd(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 cmd_code, BT_HDR *p_cmd)
|
||||
{
|
||||
tGATT_STATUS att_ret = GATT_SUCCESS;
|
||||
|
||||
if (p_tcb != NULL) {
|
||||
cmd_code &= ~GATT_AUTH_SIGN_MASK;
|
||||
|
||||
/* no pending request or value confirmation */
|
||||
if (p_tcb->pending_cl_req == p_tcb->next_slot_inq ||
|
||||
cmd_code == GATT_HANDLE_VALUE_CONF) {
|
||||
att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd);
|
||||
if (att_ret == GATT_CONGESTED || att_ret == GATT_SUCCESS) {
|
||||
/* do not enq cmd if handle value confirmation or set request */
|
||||
if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE) {
|
||||
gatt_start_rsp_timer (clcb_idx);
|
||||
gatt_cmd_enq(p_tcb, clcb_idx, FALSE, cmd_code, NULL);
|
||||
}
|
||||
} else {
|
||||
att_ret = GATT_INTERNAL_ERROR;
|
||||
}
|
||||
} else {
|
||||
att_ret = GATT_CMD_STARTED;
|
||||
gatt_cmd_enq(p_tcb, clcb_idx, TRUE, cmd_code, p_cmd);
|
||||
}
|
||||
} else {
|
||||
att_ret = GATT_ERROR;
|
||||
}
|
||||
|
||||
return att_ret;
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function attp_send_cl_msg
|
||||
**
|
||||
** Description This function sends the client request or confirmation message
|
||||
** to server.
|
||||
**
|
||||
** Parameter p_tcb: pointer to the connection control block.
|
||||
** clcb_idx: clcb index
|
||||
** op_code: message op code.
|
||||
** p_msg: pointer to message parameters structure.
|
||||
**
|
||||
** Returns GATT_SUCCESS if successfully sent; otherwise error code.
|
||||
**
|
||||
**
|
||||
*******************************************************************************/
|
||||
tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, tGATT_CL_MSG *p_msg)
|
||||
{
|
||||
tGATT_STATUS status = GATT_NO_RESOURCES;
|
||||
BT_HDR *p_cmd = NULL;
|
||||
UINT16 offset = 0, handle;
|
||||
|
||||
if (p_tcb != NULL) {
|
||||
switch (op_code) {
|
||||
case GATT_REQ_MTU:
|
||||
if (p_msg->mtu <= GATT_MAX_MTU_SIZE) {
|
||||
p_tcb->payload_size = p_msg->mtu;
|
||||
p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu);
|
||||
} else {
|
||||
status = GATT_ILLEGAL_PARAMETER;
|
||||
}
|
||||
break;
|
||||
|
||||
case GATT_REQ_FIND_INFO:
|
||||
case GATT_REQ_READ_BY_TYPE:
|
||||
case GATT_REQ_READ_BY_GRP_TYPE:
|
||||
if (GATT_HANDLE_IS_VALID (p_msg->browse.s_handle) &&
|
||||
GATT_HANDLE_IS_VALID (p_msg->browse.e_handle) &&
|
||||
p_msg->browse.s_handle <= p_msg->browse.e_handle) {
|
||||
p_cmd = attp_build_browse_cmd(op_code,
|
||||
p_msg->browse.s_handle,
|
||||
p_msg->browse.e_handle,
|
||||
p_msg->browse.uuid);
|
||||
} else {
|
||||
status = GATT_ILLEGAL_PARAMETER;
|
||||
}
|
||||
break;
|
||||
|
||||
case GATT_REQ_READ_BLOB:
|
||||
offset = p_msg->read_blob.offset;
|
||||
/* fall through */
|
||||
case GATT_REQ_READ:
|
||||
handle = (op_code == GATT_REQ_READ) ? p_msg->handle : p_msg->read_blob.handle;
|
||||
/* handle checking */
|
||||
if (GATT_HANDLE_IS_VALID (handle)) {
|
||||
p_cmd = attp_build_handle_cmd(op_code, handle, offset);
|
||||
} else {
|
||||
status = GATT_ILLEGAL_PARAMETER;
|
||||
}
|
||||
break;
|
||||
|
||||
case GATT_HANDLE_VALUE_CONF:
|
||||
p_cmd = attp_build_opcode_cmd(op_code);
|
||||
break;
|
||||
|
||||
case GATT_REQ_PREPARE_WRITE:
|
||||
offset = p_msg->attr_value.offset;
|
||||
/* fall through */
|
||||
case GATT_REQ_WRITE:
|
||||
case GATT_CMD_WRITE:
|
||||
case GATT_SIGN_CMD_WRITE:
|
||||
if (GATT_HANDLE_IS_VALID (p_msg->attr_value.handle)) {
|
||||
p_cmd = attp_build_value_cmd (p_tcb->payload_size,
|
||||
op_code, p_msg->attr_value.handle,
|
||||
offset,
|
||||
p_msg->attr_value.len,
|
||||
p_msg->attr_value.value);
|
||||
} else {
|
||||
status = GATT_ILLEGAL_PARAMETER;
|
||||
}
|
||||
break;
|
||||
|
||||
case GATT_REQ_EXEC_WRITE:
|
||||
p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write);
|
||||
break;
|
||||
|
||||
case GATT_REQ_FIND_TYPE_VALUE:
|
||||
p_cmd = attp_build_read_by_type_value_cmd(p_tcb->payload_size, &p_msg->find_type_value);
|
||||
break;
|
||||
|
||||
case GATT_REQ_READ_MULTI:
|
||||
case GATT_REQ_READ_MULTI_VAR:
|
||||
p_cmd = attp_build_read_multi_cmd(op_code, p_tcb->payload_size,
|
||||
p_msg->read_multi.num_handles,
|
||||
p_msg->read_multi.handles);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (p_cmd != NULL) {
|
||||
status = attp_cl_send_cmd(p_tcb, clcb_idx, op_code, p_cmd);
|
||||
}
|
||||
|
||||
} else {
|
||||
GATT_TRACE_ERROR("Peer device not connected");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,797 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2008-2012 Broadcom Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* this file contains the main GATT server attributes access request
|
||||
* handling functions.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "common/bt_target.h"
|
||||
//#include "bt_utils.h"
|
||||
|
||||
#include "stack/gatt_api.h"
|
||||
#include "gatt_int.h"
|
||||
#include "stack/sdpdefs.h"
|
||||
#include "bta/bta_gatts_co.h"
|
||||
|
||||
#if (BLE_INCLUDED == TRUE && GATTS_INCLUDED == TRUE)
|
||||
|
||||
#define BLE_GATT_SR_SUPP_FEAT_EATT_BITMASK 0x01
|
||||
#define BLE_GATT_CL_SUPP_FEAT_ROBUST_CACHING_BITMASK 0x01
|
||||
#define BLE_GATT_CL_SUPP_FEAT_EATT_BITMASK 0x02
|
||||
#define BLE_GATT_CL_SUPP_FEAT_MULTI_NOTIF_BITMASK 0x04
|
||||
#define BLE_GATT_CL_SUPP_FEAT_BITMASK 0x07
|
||||
|
||||
#define GATTP_MAX_NUM_INC_SVR 0
|
||||
|
||||
#if GATTS_ROBUST_CACHING_ENABLED
|
||||
#define GATTP_MAX_CHAR_NUM 5
|
||||
#else
|
||||
#define GATTP_MAX_CHAR_NUM 2
|
||||
#endif /* GATTS_ROBUST_CACHING_ENABLED */
|
||||
|
||||
#define GATTP_MAX_ATTR_NUM (GATTP_MAX_CHAR_NUM * 2 + GATTP_MAX_NUM_INC_SVR + 1)
|
||||
#define GATTP_MAX_CHAR_VALUE_SIZE 50
|
||||
|
||||
#ifndef GATTP_ATTR_DB_SIZE
|
||||
#define GATTP_ATTR_DB_SIZE GATT_DB_MEM_SIZE(GATTP_MAX_NUM_INC_SVR, GATTP_MAX_CHAR_NUM, GATTP_MAX_CHAR_VALUE_SIZE)
|
||||
#endif
|
||||
|
||||
static void gatt_request_cback(UINT16 conn_id, UINT32 trans_id, UINT8 op_code, tGATTS_DATA *p_data);
|
||||
static void gatt_connect_cback(tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected,
|
||||
tGATT_DISCONN_REASON reason, tBT_TRANSPORT transport);
|
||||
static void gatt_disc_res_cback(UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data);
|
||||
static void gatt_disc_cmpl_cback(UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status);
|
||||
static void gatt_cl_op_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status,
|
||||
tGATT_CL_COMPLETE *p_data);
|
||||
|
||||
static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB *p_clcb);
|
||||
|
||||
|
||||
static const tGATT_CBACK gatt_profile_cback = {
|
||||
gatt_connect_cback,
|
||||
gatt_cl_op_cmpl_cback,
|
||||
gatt_disc_res_cback,
|
||||
gatt_disc_cmpl_cback,
|
||||
gatt_request_cback,
|
||||
NULL,
|
||||
NULL
|
||||
} ;
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_profile_find_conn_id_by_bd_addr
|
||||
**
|
||||
** Description Find the connection ID by remote address
|
||||
**
|
||||
** Returns Connection ID
|
||||
**
|
||||
*******************************************************************************/
|
||||
#if (GATTS_INCLUDED == TRUE)
|
||||
UINT16 gatt_profile_find_conn_id_by_bd_addr(BD_ADDR remote_bda)
|
||||
{
|
||||
UINT16 conn_id = GATT_INVALID_CONN_ID;
|
||||
GATT_GetConnIdIfConnected (gatt_cb.gatt_if, remote_bda, &conn_id, BT_TRANSPORT_LE);
|
||||
return conn_id;
|
||||
}
|
||||
#endif ///GATTS_INCLUDED == TRUE
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_profile_find_clcb_by_conn_id
|
||||
**
|
||||
** Description find clcb by Connection ID
|
||||
**
|
||||
** Returns Pointer to the found link conenction control block.
|
||||
**
|
||||
*******************************************************************************/
|
||||
static tGATT_PROFILE_CLCB *gatt_profile_find_clcb_by_conn_id(UINT16 conn_id)
|
||||
{
|
||||
UINT8 i_clcb;
|
||||
tGATT_PROFILE_CLCB *p_clcb = NULL;
|
||||
|
||||
for (i_clcb = 0, p_clcb = gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++) {
|
||||
if (p_clcb->in_use && p_clcb->conn_id == conn_id) {
|
||||
return p_clcb;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_profile_find_clcb_by_bd_addr
|
||||
**
|
||||
** Description The function searches all LCBs with macthing bd address.
|
||||
**
|
||||
** Returns Pointer to the found link conenction control block.
|
||||
**
|
||||
*******************************************************************************/
|
||||
static tGATT_PROFILE_CLCB *gatt_profile_find_clcb_by_bd_addr(BD_ADDR bda, tBT_TRANSPORT transport)
|
||||
{
|
||||
UINT8 i_clcb;
|
||||
tGATT_PROFILE_CLCB *p_clcb = NULL;
|
||||
|
||||
for (i_clcb = 0, p_clcb = gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++) {
|
||||
if (p_clcb->in_use && p_clcb->transport == transport &&
|
||||
p_clcb->connected && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN)) {
|
||||
return p_clcb;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_profile_clcb_alloc
|
||||
**
|
||||
** Description The function allocates a GATT profile connection link control block
|
||||
**
|
||||
** Returns NULL if not found. Otherwise pointer to the connection link block.
|
||||
**
|
||||
*******************************************************************************/
|
||||
tGATT_PROFILE_CLCB *gatt_profile_clcb_alloc (UINT16 conn_id, BD_ADDR bda, tBT_TRANSPORT tranport)
|
||||
{
|
||||
UINT8 i_clcb = 0;
|
||||
tGATT_PROFILE_CLCB *p_clcb = NULL;
|
||||
|
||||
for (i_clcb = 0, p_clcb = gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++) {
|
||||
if (!p_clcb->in_use) {
|
||||
p_clcb->in_use = TRUE;
|
||||
p_clcb->conn_id = conn_id;
|
||||
p_clcb->connected = TRUE;
|
||||
p_clcb->transport = tranport;
|
||||
memcpy (p_clcb->bda, bda, BD_ADDR_LEN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i_clcb < GATT_MAX_APPS) {
|
||||
return p_clcb;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_profile_clcb_dealloc
|
||||
**
|
||||
** Description The function deallocates a GATT profile connection link control block
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void gatt_profile_clcb_dealloc (tGATT_PROFILE_CLCB *p_clcb)
|
||||
{
|
||||
memset(p_clcb, 0, sizeof(tGATT_PROFILE_CLCB));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_proc_read
|
||||
**
|
||||
** Description GATT Attributes Database Read/Read Blob Request process
|
||||
**
|
||||
** Returns GATT_SUCCESS if successfully sent; otherwise error code.
|
||||
**
|
||||
*******************************************************************************/
|
||||
tGATT_STATUS gatt_proc_read (UINT16 conn_id, tGATTS_REQ_TYPE type, tGATT_READ_REQ *p_data, tGATTS_RSP *p_rsp)
|
||||
{
|
||||
tGATT_STATUS status = GATT_NO_RESOURCES;
|
||||
UINT16 len = 0;
|
||||
UINT8 *value;
|
||||
UNUSED(type);
|
||||
|
||||
GATT_TRACE_DEBUG("%s handle %x", __func__, p_data->handle);
|
||||
|
||||
if (p_data->is_long) {
|
||||
p_rsp->attr_value.offset = p_data->offset;
|
||||
}
|
||||
|
||||
p_rsp->attr_value.handle = p_data->handle;
|
||||
#if GATTS_ROBUST_CACHING_ENABLED
|
||||
|
||||
UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
|
||||
tGATT_TCB *tcb = gatt_get_tcb_by_idx(tcb_idx);
|
||||
|
||||
/* handle request for reading client supported features */
|
||||
if (p_data->handle == gatt_cb.handle_of_cl_supported_feat) {
|
||||
if (tcb == NULL) {
|
||||
return GATT_INSUF_RESOURCE;
|
||||
}
|
||||
p_rsp->attr_value.len = 1;
|
||||
memcpy(p_rsp->attr_value.value, &tcb->cl_supp_feat, 1);
|
||||
return GATT_SUCCESS;
|
||||
}
|
||||
|
||||
/* handle request for reading database hash */
|
||||
if (p_data->handle == gatt_cb.handle_of_database_hash) {
|
||||
p_rsp->attr_value.len = BT_OCTET16_LEN;
|
||||
memcpy(p_rsp->attr_value.value, gatt_cb.database_hash, BT_OCTET16_LEN);
|
||||
gatt_sr_update_cl_status(tcb, true);
|
||||
return GATT_SUCCESS;
|
||||
}
|
||||
|
||||
/* handle request for reading server supported features */
|
||||
if (p_data->handle == gatt_cb.handle_of_sr_supported_feat) {
|
||||
p_rsp->attr_value.len = 1;
|
||||
memcpy(p_rsp->attr_value.value, &gatt_cb.gatt_sr_supported_feat_mask, 1);
|
||||
return GATT_SUCCESS;
|
||||
}
|
||||
#endif /* GATTS_ROBUST_CACHING_ENABLED */
|
||||
/* handle request for reading service changed des and the others */
|
||||
status = GATTS_GetAttributeValue(p_data->handle, &len, &value);
|
||||
if(status == GATT_SUCCESS && len > 0 && value) {
|
||||
if(len > GATT_MAX_ATTR_LEN) {
|
||||
len = GATT_MAX_ATTR_LEN;
|
||||
}
|
||||
p_rsp->attr_value.len = len;
|
||||
memcpy(p_rsp->attr_value.value, value, len);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
#if GATTS_ROBUST_CACHING_ENABLED
|
||||
static tGATT_STATUS gatt_sr_write_cl_supp_feat(UINT16 conn_id, tGATT_WRITE_REQ *p_data)
|
||||
{
|
||||
UINT8 val_new;
|
||||
UINT8 val_old;
|
||||
UINT8 val_xor;
|
||||
UINT8 val_and;
|
||||
UINT8 *p = p_data->value;
|
||||
UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
|
||||
tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
|
||||
|
||||
GATT_TRACE_DEBUG("%s len %u, feat %x", __func__, p_data->len, *p);
|
||||
|
||||
if (p_tcb == NULL) {
|
||||
GATT_TRACE_ERROR("%s no conn", __func__);
|
||||
return GATT_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (p_data->len != 1) {
|
||||
GATT_TRACE_ERROR("%s len %u", __func__, p_data->len);
|
||||
return GATT_INVALID_PDU;
|
||||
}
|
||||
|
||||
STREAM_TO_UINT8(val_new, p);
|
||||
val_new = (val_new & BLE_GATT_CL_SUPP_FEAT_BITMASK);
|
||||
|
||||
if (val_new == 0) {
|
||||
GATT_TRACE_ERROR("%s bit cannot be all zero", __func__);
|
||||
return GATT_VALUE_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
val_old = p_tcb->cl_supp_feat;
|
||||
val_xor = val_old ^ val_new;
|
||||
val_and = val_xor & val_new;
|
||||
if (val_and != val_xor) {
|
||||
GATT_TRACE_ERROR("%s bit cannot be reset", __func__);
|
||||
return GATT_VALUE_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
p_tcb->cl_supp_feat = val_new;
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
bta_gatts_co_cl_feat_save(p_tcb->peer_bda, &p_tcb->cl_supp_feat);
|
||||
#endif
|
||||
return GATT_SUCCESS;
|
||||
}
|
||||
#endif /* GATTS_ROBUST_CACHING_ENABLED */
|
||||
/******************************************************************************
|
||||
**
|
||||
** Function gatt_proc_write_req
|
||||
**
|
||||
** Description GATT server process a write request.
|
||||
**
|
||||
** Returns GATT_SUCCESS if successfully sent; otherwise error code.
|
||||
**
|
||||
*******************************************************************************/
|
||||
tGATT_STATUS gatt_proc_write_req(UINT16 conn_id, tGATTS_REQ_TYPE type, tGATT_WRITE_REQ *p_data)
|
||||
{
|
||||
if(p_data->len > GATT_MAX_ATTR_LEN) {
|
||||
p_data->len = GATT_MAX_ATTR_LEN;
|
||||
}
|
||||
#if GATTS_ROBUST_CACHING_ENABLED
|
||||
if (p_data->handle == gatt_cb.handle_of_h_r) {
|
||||
return GATT_WRITE_NOT_PERMIT;
|
||||
}
|
||||
|
||||
if (p_data->handle == gatt_cb.handle_of_cl_supported_feat) {
|
||||
return gatt_sr_write_cl_supp_feat(conn_id, p_data);
|
||||
}
|
||||
|
||||
if (p_data->handle == gatt_cb.handle_of_database_hash) {
|
||||
return GATT_WRITE_NOT_PERMIT;
|
||||
}
|
||||
|
||||
if (p_data->handle == gatt_cb.handle_of_sr_supported_feat) {
|
||||
return GATT_WRITE_NOT_PERMIT;
|
||||
}
|
||||
#endif /* GATTS_ROBUST_CACHING_ENABLED */
|
||||
return GATTS_SetAttributeValue(p_data->handle,
|
||||
p_data->len,
|
||||
p_data->value);
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_request_cback
|
||||
**
|
||||
** Description GATT profile attribute access request callback.
|
||||
**
|
||||
** Returns void.
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void gatt_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE type,
|
||||
tGATTS_DATA *p_data)
|
||||
{
|
||||
UINT8 status = GATT_INVALID_PDU;
|
||||
tGATTS_RSP rsp_msg ;
|
||||
BOOLEAN ignore = FALSE;
|
||||
GATT_TRACE_DEBUG("%s",__func__);
|
||||
memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
|
||||
|
||||
switch (type) {
|
||||
case GATTS_REQ_TYPE_READ:
|
||||
status = gatt_proc_read(conn_id, type, &p_data->read_req, &rsp_msg);
|
||||
break;
|
||||
|
||||
case GATTS_REQ_TYPE_WRITE:
|
||||
if (!p_data->write_req.need_rsp) {
|
||||
ignore = TRUE;
|
||||
}
|
||||
status = gatt_proc_write_req(conn_id, type, &p_data->write_req);
|
||||
break;
|
||||
|
||||
case GATTS_REQ_TYPE_WRITE_EXEC:
|
||||
case GATT_CMD_WRITE:
|
||||
ignore = TRUE;
|
||||
GATT_TRACE_EVENT("Ignore GATT_REQ_EXEC_WRITE/WRITE_CMD" );
|
||||
break;
|
||||
|
||||
case GATTS_REQ_TYPE_MTU:
|
||||
GATT_TRACE_EVENT("Get MTU exchange new mtu size: %d", p_data->mtu);
|
||||
ignore = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
GATT_TRACE_EVENT("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ignore) {
|
||||
GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_connect_cback
|
||||
**
|
||||
** Description Gatt profile connection callback.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void gatt_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id,
|
||||
BOOLEAN connected, tGATT_DISCONN_REASON reason,
|
||||
tBT_TRANSPORT transport)
|
||||
{
|
||||
UNUSED(gatt_if);
|
||||
|
||||
GATT_TRACE_DEBUG ("%s: from %08x%04x connected:%d conn_id=%d reason = 0x%04x", __FUNCTION__,
|
||||
(bda[0] << 24) + (bda[1] << 16) + (bda[2] << 8) + bda[3],
|
||||
(bda[4] << 8) + bda[5], connected, conn_id, reason);
|
||||
|
||||
tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_bd_addr(bda, transport);
|
||||
if (p_clcb == NULL) {
|
||||
p_clcb = gatt_profile_clcb_alloc (conn_id, bda, transport);
|
||||
}
|
||||
|
||||
if (p_clcb == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GATT_GetConnIdIfConnected (gatt_cb.gatt_if, bda, &p_clcb->conn_id, transport)) {
|
||||
p_clcb->connected = TRUE;
|
||||
p_clcb->conn_id = conn_id;
|
||||
}
|
||||
|
||||
|
||||
if (!p_clcb->connected) {
|
||||
/* wait for connection */
|
||||
return;
|
||||
}
|
||||
|
||||
if (connected) {
|
||||
p_clcb->conn_id = conn_id;
|
||||
p_clcb->connected = TRUE;
|
||||
|
||||
} else {
|
||||
gatt_profile_clcb_dealloc(p_clcb);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_profile_db_init
|
||||
**
|
||||
** Description Initializa the GATT profile attribute database.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void gatt_profile_db_init (void)
|
||||
{
|
||||
tBT_UUID app_uuid = {LEN_UUID_128, {0}};
|
||||
tBT_UUID uuid = {LEN_UUID_16, {UUID_SERVCLASS_GATT_SERVER}};
|
||||
UINT16 service_handle = 0;
|
||||
tGATT_STATUS status;
|
||||
|
||||
/* Fill our internal UUID with a fixed pattern 0x81 */
|
||||
memset (&app_uuid.uu.uuid128, 0x81, LEN_UUID_128);
|
||||
|
||||
|
||||
/* Create a GATT profile service */
|
||||
gatt_cb.gatt_if = GATT_Register(&app_uuid, &gatt_profile_cback);
|
||||
GATT_StartIf(gatt_cb.gatt_if);
|
||||
|
||||
service_handle = GATTS_CreateService (gatt_cb.gatt_if , &uuid, 0, GATTP_MAX_ATTR_NUM, TRUE);
|
||||
GATT_TRACE_DEBUG ("GATTS_CreateService: handle of service handle%x", service_handle);
|
||||
|
||||
/* add Service Changed characteristic
|
||||
*/
|
||||
uuid.uu.uuid16 = gatt_cb.gattp_attr.uuid = GATT_UUID_GATT_SRV_CHGD;
|
||||
gatt_cb.gattp_attr.service_change = 0;
|
||||
gatt_cb.gattp_attr.handle =
|
||||
gatt_cb.handle_of_h_r = GATTS_AddCharacteristic(service_handle, &uuid, 0, GATT_CHAR_PROP_BIT_INDICATE,
|
||||
NULL, NULL);
|
||||
|
||||
GATT_TRACE_DEBUG ("gatt_profile_db_init: handle of service changed%d\n",
|
||||
gatt_cb.handle_of_h_r);
|
||||
|
||||
tBT_UUID descr_uuid = {LEN_UUID_16, {GATT_UUID_CHAR_CLIENT_CONFIG}};
|
||||
uint8_t ccc_value[2] ={ 0x00, 0x00};
|
||||
|
||||
tGATT_ATTR_VAL attr_val = {
|
||||
.attr_max_len = sizeof(UINT16),
|
||||
.attr_len = sizeof(UINT16),
|
||||
.attr_val = ccc_value,
|
||||
};
|
||||
|
||||
GATTS_AddCharDescriptor (service_handle, GATT_PERM_READ | GATT_PERM_WRITE , &descr_uuid, &attr_val, NULL);
|
||||
#if GATTS_ROBUST_CACHING_ENABLED
|
||||
/* add Client Supported Features characteristic */
|
||||
uuid.uu.uuid16 = GATT_UUID_CLIENT_SUP_FEAT;
|
||||
gatt_cb.handle_of_cl_supported_feat = GATTS_AddCharacteristic(service_handle, &uuid, GATT_PERM_READ | GATT_PERM_WRITE,
|
||||
GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE, NULL, NULL);
|
||||
|
||||
/* add Database Hash characteristic */
|
||||
uuid.uu.uuid16 = GATT_UUID_GATT_DATABASE_HASH;
|
||||
gatt_cb.handle_of_database_hash = GATTS_AddCharacteristic(service_handle, &uuid, GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ, NULL, NULL);
|
||||
|
||||
/* add Server Supported Features characteristic */
|
||||
uuid.uu.uuid16 = GATT_UUID_SERVER_SUP_FEAT;
|
||||
gatt_cb.handle_of_sr_supported_feat = GATTS_AddCharacteristic(service_handle, &uuid, GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ, NULL, NULL);
|
||||
#endif /* GATTS_ROBUST_CACHING_ENABLED */
|
||||
/* start service */
|
||||
status = GATTS_StartService (gatt_cb.gatt_if, service_handle, GATTP_TRANSPORT_SUPPORTED );
|
||||
|
||||
#if (CONFIG_BT_STACK_NO_LOG)
|
||||
(void) status;
|
||||
#endif
|
||||
|
||||
GATT_TRACE_DEBUG ("gatt_profile_db_init: gatt_if=%d start status%d\n",
|
||||
gatt_cb.gatt_if, status);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_disc_res_cback
|
||||
**
|
||||
** Description Gatt profile discovery result callback
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void gatt_disc_res_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data)
|
||||
{
|
||||
GATT_TRACE_DEBUG("%s, disc_type = %d",__func__, disc_type);
|
||||
tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);
|
||||
|
||||
if (p_clcb == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (disc_type) {
|
||||
case GATT_DISC_SRVC_BY_UUID:/* stage 1 */
|
||||
p_clcb->e_handle = p_data->value.group_value.e_handle;
|
||||
p_clcb->ccc_result ++;
|
||||
break;
|
||||
|
||||
case GATT_DISC_CHAR:/* stage 2 */
|
||||
p_clcb->s_handle = p_data->value.dclr_value.val_handle;
|
||||
p_clcb->ccc_result ++;
|
||||
break;
|
||||
|
||||
case GATT_DISC_CHAR_DSCPT: /* stage 3 */
|
||||
if (p_data->type.uu.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG) {
|
||||
p_clcb->s_handle = p_data->handle;
|
||||
p_clcb->ccc_result ++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_disc_cmpl_cback
|
||||
**
|
||||
** Description Gatt profile discovery complete callback
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void gatt_disc_cmpl_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status)
|
||||
{
|
||||
GATT_TRACE_DEBUG("%s",__func__);
|
||||
tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);
|
||||
|
||||
if (p_clcb == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (status == GATT_SUCCESS && p_clcb->ccc_result > 0) {
|
||||
p_clcb->ccc_result = 0;
|
||||
p_clcb->ccc_stage ++;
|
||||
gatt_cl_start_config_ccc(p_clcb);
|
||||
} else {
|
||||
GATT_TRACE_ERROR("%s() - Register for service changed indication failure", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_cl_op_cmpl_cback
|
||||
**
|
||||
** Description Gatt profile client operation complete callback
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void gatt_cl_op_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op,
|
||||
tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
|
||||
{
|
||||
GATT_TRACE_DEBUG("%s",__func__);
|
||||
tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);
|
||||
|
||||
if (p_clcb == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (op == GATTC_OPTYPE_WRITE) {
|
||||
GATT_TRACE_DEBUG("%s() - ccc write status : %d", __FUNCTION__, status);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_cl_start_config_ccc
|
||||
**
|
||||
** Description Gatt profile start configure service change CCC
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB *p_clcb)
|
||||
{
|
||||
tGATT_DISC_PARAM srvc_disc_param;
|
||||
tGATT_VALUE ccc_value;
|
||||
|
||||
GATT_TRACE_DEBUG("%s() - stage: %d", __FUNCTION__, p_clcb->ccc_stage);
|
||||
|
||||
memset (&srvc_disc_param, 0 , sizeof(tGATT_DISC_PARAM));
|
||||
memset (&ccc_value, 0 , sizeof(tGATT_VALUE));
|
||||
|
||||
switch (p_clcb->ccc_stage) {
|
||||
case GATT_SVC_CHANGED_SERVICE: /* discover GATT service */
|
||||
srvc_disc_param.s_handle = 1;
|
||||
srvc_disc_param.e_handle = 0xffff;
|
||||
srvc_disc_param.service.len = 2;
|
||||
srvc_disc_param.service.uu.uuid16 = UUID_SERVCLASS_GATT_SERVER;
|
||||
#if (GATTC_INCLUDED == TRUE)
|
||||
if (GATTC_Discover (p_clcb->conn_id, GATT_DISC_SRVC_BY_UUID, &srvc_disc_param) != GATT_SUCCESS) {
|
||||
GATT_TRACE_ERROR("%s() - ccc service error", __FUNCTION__);
|
||||
}
|
||||
#endif ///GATTC_INCLUDED == TRUE
|
||||
break;
|
||||
|
||||
case GATT_SVC_CHANGED_CHARACTERISTIC: /* discover service change char */
|
||||
srvc_disc_param.s_handle = 1;
|
||||
srvc_disc_param.e_handle = p_clcb->e_handle;
|
||||
srvc_disc_param.service.len = 2;
|
||||
srvc_disc_param.service.uu.uuid16 = GATT_UUID_GATT_SRV_CHGD;
|
||||
#if (GATTC_INCLUDED == TRUE)
|
||||
if (GATTC_Discover (p_clcb->conn_id, GATT_DISC_CHAR, &srvc_disc_param) != GATT_SUCCESS) {
|
||||
GATT_TRACE_ERROR("%s() - ccc char error", __FUNCTION__);
|
||||
}
|
||||
#endif ///GATTC_INCLUDED == TRUE
|
||||
break;
|
||||
|
||||
case GATT_SVC_CHANGED_DESCRIPTOR: /* discover service change ccc */
|
||||
srvc_disc_param.s_handle = p_clcb->s_handle;
|
||||
srvc_disc_param.e_handle = p_clcb->e_handle;
|
||||
#if (GATTC_INCLUDED == TRUE)
|
||||
if (GATTC_Discover (p_clcb->conn_id, GATT_DISC_CHAR_DSCPT, &srvc_disc_param) != GATT_SUCCESS) {
|
||||
GATT_TRACE_ERROR("%s() - ccc char descriptor error", __FUNCTION__);
|
||||
}
|
||||
#endif ///GATTC_INCLUDED == TRUE
|
||||
break;
|
||||
|
||||
case GATT_SVC_CHANGED_CONFIGURE_CCCD: /* write ccc */
|
||||
ccc_value.handle = p_clcb->s_handle;
|
||||
ccc_value.len = 2;
|
||||
ccc_value.value[0] = GATT_CLT_CONFIG_INDICATION;
|
||||
#if (GATTC_INCLUDED == TRUE)
|
||||
if (GATTC_Write (p_clcb->conn_id, GATT_WRITE, &ccc_value) != GATT_SUCCESS) {
|
||||
GATT_TRACE_ERROR("%s() - write ccc error", __FUNCTION__);
|
||||
}
|
||||
#endif ///GATTC_INCLUDED == TRUE
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function GATT_ConfigServiceChangeCCC
|
||||
**
|
||||
** Description Configure service change indication on remote device
|
||||
**
|
||||
** Returns none
|
||||
**
|
||||
*******************************************************************************/
|
||||
void GATT_ConfigServiceChangeCCC (BD_ADDR remote_bda, BOOLEAN enable, tBT_TRANSPORT transport)
|
||||
{
|
||||
tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_bd_addr (remote_bda, transport);
|
||||
|
||||
if (p_clcb == NULL) {
|
||||
p_clcb = gatt_profile_clcb_alloc (0, remote_bda, transport);
|
||||
}
|
||||
|
||||
if (p_clcb == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GATT_GetConnIdIfConnected (gatt_cb.gatt_if, remote_bda, &p_clcb->conn_id, transport)) {
|
||||
p_clcb->connected = TRUE;
|
||||
}
|
||||
/* hold the link here */
|
||||
GATT_Connect(gatt_cb.gatt_if, remote_bda, BLE_ADDR_UNKNOWN_TYPE, TRUE, transport, FALSE);
|
||||
p_clcb->ccc_stage = GATT_SVC_CHANGED_CONNECTING;
|
||||
|
||||
if (!p_clcb->connected) {
|
||||
/* wait for connection */
|
||||
return;
|
||||
}
|
||||
|
||||
p_clcb->ccc_stage ++;
|
||||
gatt_cl_start_config_ccc(p_clcb);
|
||||
}
|
||||
|
||||
#if GATTS_ROBUST_CACHING_ENABLED
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_sr_is_cl_robust_caching_supported
|
||||
**
|
||||
** Description Check if Robust Caching is supported for the connection
|
||||
**
|
||||
** Returns true if enabled by client side, otherwise false
|
||||
**
|
||||
*******************************************************************************/
|
||||
static BOOLEAN gatt_sr_is_cl_robust_caching_supported(tGATT_TCB *p_tcb)
|
||||
{
|
||||
return (p_tcb->cl_supp_feat & BLE_GATT_CL_SUPP_FEAT_ROBUST_CACHING_BITMASK);
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_sr_is_cl_change_aware
|
||||
**
|
||||
** Description Check if the connection is change-aware
|
||||
**
|
||||
** Returns true if change aware, otherwise false
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN gatt_sr_is_cl_change_aware(tGATT_TCB *p_tcb)
|
||||
{
|
||||
// If robust caching is not supported, should always return true by default
|
||||
if (!gatt_sr_is_cl_robust_caching_supported(p_tcb)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return p_tcb->is_robust_cache_change_aware;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_sr_init_cl_status
|
||||
**
|
||||
** Description Restore status for trusted device
|
||||
**
|
||||
** Returns none
|
||||
**
|
||||
*******************************************************************************/
|
||||
void gatt_sr_init_cl_status(tGATT_TCB *p_tcb)
|
||||
{
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
bta_gatts_co_cl_feat_load(p_tcb->peer_bda, &p_tcb->cl_supp_feat);
|
||||
#endif
|
||||
|
||||
// This is used to reset bit when robust caching is disabled
|
||||
if (!GATTS_ROBUST_CACHING_ENABLED) {
|
||||
p_tcb->cl_supp_feat &= ~BLE_GATT_CL_SUPP_FEAT_ROBUST_CACHING_BITMASK;
|
||||
}
|
||||
|
||||
if (gatt_sr_is_cl_robust_caching_supported(p_tcb)) {
|
||||
BT_OCTET16 stored_hash = {0};
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
bta_gatts_co_db_hash_load(p_tcb->peer_bda, stored_hash);
|
||||
#endif
|
||||
p_tcb->is_robust_cache_change_aware = (memcmp(stored_hash, gatt_cb.database_hash, BT_OCTET16_LEN) == 0);
|
||||
} else {
|
||||
p_tcb->is_robust_cache_change_aware = true;
|
||||
}
|
||||
|
||||
GATT_TRACE_DEBUG("%s feat %x aware %d", __func__, p_tcb->cl_supp_feat, p_tcb->is_robust_cache_change_aware);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_sr_update_cl_status
|
||||
**
|
||||
** Description Update change-aware status for the remote device
|
||||
**
|
||||
** Returns none
|
||||
**
|
||||
*******************************************************************************/
|
||||
void gatt_sr_update_cl_status(tGATT_TCB *p_tcb, BOOLEAN chg_aware)
|
||||
{
|
||||
if (p_tcb == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if robust caching is not supported, do nothing
|
||||
if (!gatt_sr_is_cl_robust_caching_supported(p_tcb)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only when client status is changed from unaware to aware, we should store database hash
|
||||
if (!p_tcb->is_robust_cache_change_aware && chg_aware) {
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
bta_gatts_co_db_hash_save(p_tcb->peer_bda, gatt_cb.database_hash);
|
||||
#endif
|
||||
}
|
||||
|
||||
p_tcb->is_robust_cache_change_aware = chg_aware;
|
||||
|
||||
GATT_TRACE_DEBUG("%s status %d", __func__, chg_aware);
|
||||
}
|
||||
#endif /* GATTS_ROBUST_CACHING_ENABLED */
|
||||
#endif /* BLE_INCLUDED == TRUE && GATTS_INCLUDED == TRUE */
|
||||
@@ -0,0 +1,522 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 1999-2012 Broadcom Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* this file contains GATT authentication handling functions
|
||||
*
|
||||
******************************************************************************/
|
||||
#include "common/bt_target.h"
|
||||
#include "osi/allocator.h"
|
||||
|
||||
#if BLE_INCLUDED == TRUE
|
||||
#include <string.h>
|
||||
|
||||
#include "gatt_int.h"
|
||||
#include "stack/gatt_api.h"
|
||||
#include "btm_int.h"
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_sign_data
|
||||
**
|
||||
** Description This function sign the data for write command.
|
||||
**
|
||||
** Returns TRUE if encrypted, otherwise FALSE.
|
||||
**
|
||||
*******************************************************************************/
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
static BOOLEAN gatt_sign_data (tGATT_CLCB *p_clcb)
|
||||
{
|
||||
tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
|
||||
UINT8 *p_data = NULL, *p;
|
||||
UINT16 payload_size = p_clcb->p_tcb->payload_size;
|
||||
BOOLEAN status = FALSE;
|
||||
UINT8 *p_signature;
|
||||
|
||||
/* do not need to mark channel securoty activity for data signing */
|
||||
gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_OK);
|
||||
|
||||
p_data = (UINT8 *)osi_malloc((UINT16)(p_attr->len + 3)); /* 3 = 2 byte handle + opcode */
|
||||
|
||||
if (p_data != NULL) {
|
||||
p = p_data;
|
||||
UINT8_TO_STREAM(p, GATT_SIGN_CMD_WRITE);
|
||||
UINT16_TO_STREAM(p, p_attr->handle);
|
||||
ARRAY_TO_STREAM(p, p_attr->value, p_attr->len);
|
||||
|
||||
/* sign data length should be attribulte value length plus 2B handle + 1B op code */
|
||||
if ((payload_size - GATT_AUTH_SIGN_LEN - 3) < p_attr->len) {
|
||||
p_attr->len = payload_size - GATT_AUTH_SIGN_LEN - 3;
|
||||
}
|
||||
|
||||
p_signature = p_attr->value + p_attr->len;
|
||||
if (BTM_BleDataSignature(p_clcb->p_tcb->peer_bda,
|
||||
p_data,
|
||||
(UINT16)(p_attr->len + 3), /* 3 = 2 byte handle + opcode */
|
||||
p_signature)) {
|
||||
p_attr->len += BTM_BLE_AUTH_SIGN_LEN;
|
||||
gatt_set_ch_state(p_clcb->p_tcb, GATT_CH_OPEN);
|
||||
#if (GATTC_INCLUDED == TRUE)
|
||||
gatt_act_write(p_clcb, GATT_SEC_SIGN_DATA);
|
||||
#endif ///GATTC_INCLUDED == TRUE
|
||||
} else {
|
||||
gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, NULL);
|
||||
}
|
||||
|
||||
osi_free(p_data);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_verify_signature
|
||||
**
|
||||
** Description This function start to verify the sign data when receiving
|
||||
** the data from peer device.
|
||||
**
|
||||
** Returns
|
||||
**
|
||||
*******************************************************************************/
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
void gatt_verify_signature(tGATT_TCB *p_tcb, BT_HDR *p_buf)
|
||||
{
|
||||
UINT16 cmd_len;
|
||||
#if (GATTS_INCLUDED == TRUE)
|
||||
UINT8 op_code;
|
||||
#endif ///GATTS_INCLUDED == TRUE
|
||||
UINT8 *p, *p_orig = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
UINT32 counter;
|
||||
|
||||
if (p_buf->len < GATT_AUTH_SIGN_LEN + 4) {
|
||||
GATT_TRACE_ERROR("%s: Data length %u less than expected %u",
|
||||
__func__, p_buf->len, GATT_AUTH_SIGN_LEN + 4);
|
||||
return;
|
||||
}
|
||||
cmd_len = p_buf->len - GATT_AUTH_SIGN_LEN + 4;
|
||||
p = p_orig + cmd_len - 4;
|
||||
STREAM_TO_UINT32(counter, p);
|
||||
|
||||
if (BTM_BleVerifySignature(p_tcb->peer_bda, p_orig, cmd_len, counter, p)) {
|
||||
#if (GATTS_INCLUDED == TRUE)
|
||||
STREAM_TO_UINT8(op_code, p_orig);
|
||||
gatt_server_handle_client_req (p_tcb, op_code, (UINT16)(p_buf->len - 1), p_orig);
|
||||
#endif ///GATTS_INCLUDED == TRUE
|
||||
} else {
|
||||
/* if this is a bad signature, assume from attacker, ignore it */
|
||||
GATT_TRACE_ERROR("Signature Verification Failed, data ignored");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_sec_check_complete
|
||||
**
|
||||
** Description security check complete and proceed to data sending action.
|
||||
**
|
||||
** Returns void.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void gatt_sec_check_complete(BOOLEAN sec_check_ok, tGATT_CLCB *p_clcb, UINT8 sec_act)
|
||||
{
|
||||
if (p_clcb && p_clcb->p_tcb) {
|
||||
if (fixed_queue_is_empty(p_clcb->p_tcb->pending_enc_clcb)) {
|
||||
gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE);
|
||||
}
|
||||
#if (GATTC_INCLUDED == TRUE)
|
||||
if (!sec_check_ok) {
|
||||
gatt_end_operation(p_clcb, GATT_AUTH_FAIL, NULL);
|
||||
} else if (p_clcb->operation == GATTC_OPTYPE_WRITE) {
|
||||
gatt_act_write(p_clcb, sec_act);
|
||||
} else if (p_clcb->operation == GATTC_OPTYPE_READ) {
|
||||
gatt_act_read(p_clcb, p_clcb->counter);
|
||||
}
|
||||
#endif ///GATTC_INCLUDED == TRUE
|
||||
}
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_enc_cmpl_cback
|
||||
**
|
||||
** Description link encryption complete callback.
|
||||
**
|
||||
** Returns
|
||||
**
|
||||
*******************************************************************************/
|
||||
void gatt_enc_cmpl_cback(BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, tBTM_STATUS result)
|
||||
{
|
||||
tGATT_TCB *p_tcb;
|
||||
UINT8 sec_flag;
|
||||
BOOLEAN status = FALSE;
|
||||
UNUSED(p_ref_data);
|
||||
|
||||
GATT_TRACE_DEBUG("gatt_enc_cmpl_cback");
|
||||
if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, transport)) != NULL) {
|
||||
if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) {
|
||||
return;
|
||||
}
|
||||
tGATT_PENDING_ENC_CLCB *p_buf =
|
||||
(tGATT_PENDING_ENC_CLCB *)fixed_queue_dequeue(p_tcb->pending_enc_clcb, 0);
|
||||
if (p_buf != NULL) {
|
||||
if (result == BTM_SUCCESS) {
|
||||
if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENCRYPT_MITM ) {
|
||||
BTM_GetSecurityFlagsByTransport(bd_addr, &sec_flag, transport);
|
||||
|
||||
if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) {
|
||||
status = TRUE;
|
||||
}
|
||||
} else {
|
||||
status = TRUE;
|
||||
}
|
||||
}
|
||||
gatt_sec_check_complete(status , p_buf->p_clcb, p_tcb->sec_act);
|
||||
osi_free(p_buf);
|
||||
/* start all other pending operation in queue */
|
||||
for (size_t count = fixed_queue_length(p_tcb->pending_enc_clcb);
|
||||
count > 0; count--) {
|
||||
p_buf = (tGATT_PENDING_ENC_CLCB *)fixed_queue_dequeue(p_tcb->pending_enc_clcb, 0);
|
||||
if (p_buf != NULL) {
|
||||
gatt_security_check_start(p_buf->p_clcb);
|
||||
osi_free(p_buf);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
GATT_TRACE_ERROR("Unknown operation encryption completed");
|
||||
}
|
||||
} else {
|
||||
GATT_TRACE_ERROR("enc callback for unknown bd_addr");
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_notify_enc_cmpl
|
||||
**
|
||||
** Description link encryption complete notification for all encryption process
|
||||
** initiated outside GATT.
|
||||
**
|
||||
** Returns
|
||||
**
|
||||
*******************************************************************************/
|
||||
void gatt_notify_enc_cmpl(BD_ADDR bd_addr)
|
||||
{
|
||||
tGATT_TCB *p_tcb;
|
||||
UINT8 i = 0;
|
||||
|
||||
if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE)) != NULL) {
|
||||
for (i = 0; i < GATT_MAX_APPS; i++) {
|
||||
if (gatt_cb.cl_rcb[i].in_use && gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb) {
|
||||
(*gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb)(gatt_cb.cl_rcb[i].gatt_if, bd_addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) {
|
||||
gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
|
||||
|
||||
size_t count = fixed_queue_length(p_tcb->pending_enc_clcb);
|
||||
for (; count > 0; count--) {
|
||||
tGATT_PENDING_ENC_CLCB *p_buf =
|
||||
(tGATT_PENDING_ENC_CLCB *)fixed_queue_dequeue(p_tcb->pending_enc_clcb, 0);
|
||||
if (p_buf != NULL) {
|
||||
gatt_security_check_start(p_buf->p_clcb);
|
||||
osi_free(p_buf);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
GATT_TRACE_DEBUG("notify GATT for encryption completion of unknown device");
|
||||
}
|
||||
return;
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_set_sec_act
|
||||
**
|
||||
** Description This function set the sec_act in clcb
|
||||
**
|
||||
** Returns none
|
||||
**
|
||||
*******************************************************************************/
|
||||
void gatt_set_sec_act(tGATT_TCB *p_tcb, tGATT_SEC_ACTION sec_act)
|
||||
{
|
||||
if (p_tcb) {
|
||||
p_tcb->sec_act = sec_act;
|
||||
}
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_get_sec_act
|
||||
**
|
||||
** Description This function get the sec_act in clcb
|
||||
**
|
||||
** Returns none
|
||||
**
|
||||
*******************************************************************************/
|
||||
tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB *p_tcb)
|
||||
{
|
||||
tGATT_SEC_ACTION sec_act = GATT_SEC_NONE;
|
||||
if (p_tcb) {
|
||||
sec_act = p_tcb->sec_act;
|
||||
}
|
||||
return sec_act;
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_determine_sec_act
|
||||
**
|
||||
** Description This routine determine the security action based on auth_request and
|
||||
** current link status
|
||||
**
|
||||
** Returns tGATT_SEC_ACTION security action
|
||||
**
|
||||
*******************************************************************************/
|
||||
tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB *p_clcb )
|
||||
{
|
||||
tGATT_SEC_ACTION act = GATT_SEC_OK;
|
||||
UINT8 sec_flag;
|
||||
tGATT_TCB *p_tcb = p_clcb->p_tcb;
|
||||
tGATT_AUTH_REQ auth_req = p_clcb->auth_req;
|
||||
BOOLEAN is_link_encrypted = FALSE;
|
||||
BOOLEAN is_link_key_known = FALSE;
|
||||
BOOLEAN is_key_mitm = FALSE;
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
UINT8 key_type;
|
||||
tBTM_BLE_SEC_REQ_ACT sec_act = BTM_LE_SEC_NONE;
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
if (auth_req == GATT_AUTH_REQ_NONE ) {
|
||||
return act;
|
||||
}
|
||||
|
||||
BTM_GetSecurityFlagsByTransport(p_tcb->peer_bda, &sec_flag, p_clcb->p_tcb->transport);
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
btm_ble_link_sec_check(p_tcb->peer_bda, auth_req, &sec_act);
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
/* if a encryption is pending, need to wait */
|
||||
if (
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
sec_act == BTM_BLE_SEC_REQ_ACT_DISCARD &&
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
auth_req != GATT_AUTH_REQ_NONE) {
|
||||
return GATT_SEC_ENC_PENDING;
|
||||
}
|
||||
|
||||
if (sec_flag & (BTM_SEC_FLAG_ENCRYPTED | BTM_SEC_FLAG_LKEY_KNOWN)) {
|
||||
if (sec_flag & BTM_SEC_FLAG_ENCRYPTED) {
|
||||
is_link_encrypted = TRUE;
|
||||
}
|
||||
|
||||
is_link_key_known = TRUE;
|
||||
|
||||
if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) {
|
||||
is_key_mitm = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* first check link key upgrade required or not */
|
||||
switch (auth_req) {
|
||||
case GATT_AUTH_REQ_MITM:
|
||||
case GATT_AUTH_REQ_SIGNED_MITM:
|
||||
if (!is_key_mitm) {
|
||||
act = GATT_SEC_ENCRYPT_MITM;
|
||||
}
|
||||
break;
|
||||
|
||||
case GATT_AUTH_REQ_NO_MITM:
|
||||
case GATT_AUTH_REQ_SIGNED_NO_MITM:
|
||||
if (!is_link_key_known) {
|
||||
act = GATT_SEC_ENCRYPT_NO_MITM;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* now check link needs to be encrypted or not if the link key upgrade is not required */
|
||||
if (act == GATT_SEC_OK) {
|
||||
if (p_tcb->transport == BT_TRANSPORT_LE &&
|
||||
(p_clcb->operation == GATTC_OPTYPE_WRITE) &&
|
||||
(p_clcb->op_subtype == GATT_WRITE_NO_RSP)) {
|
||||
/* this is a write command request
|
||||
check data signing required or not */
|
||||
if (!is_link_encrypted) {
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
btm_ble_get_enc_key_type(p_tcb->peer_bda, &key_type);
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
if (
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
(key_type & BTM_LE_KEY_LCSRK) &&
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
((auth_req == GATT_AUTH_REQ_SIGNED_NO_MITM) ||
|
||||
(auth_req == GATT_AUTH_REQ_SIGNED_MITM))) {
|
||||
act = GATT_SEC_SIGN_DATA;
|
||||
} else {
|
||||
act = GATT_SEC_ENCRYPT;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!is_link_encrypted) {
|
||||
act = GATT_SEC_ENCRYPT;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return act ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_get_link_encrypt_status
|
||||
**
|
||||
** Description This routine get the encryption status of the specified link
|
||||
**
|
||||
**
|
||||
** Returns tGATT_STATUS link encryption status
|
||||
**
|
||||
*******************************************************************************/
|
||||
tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB *p_tcb)
|
||||
{
|
||||
tGATT_STATUS encrypt_status = GATT_NOT_ENCRYPTED;
|
||||
UINT8 sec_flag = 0;
|
||||
|
||||
BTM_GetSecurityFlagsByTransport(p_tcb->peer_bda, &sec_flag, p_tcb->transport);
|
||||
|
||||
if ((sec_flag & BTM_SEC_FLAG_ENCRYPTED) && (sec_flag & BTM_SEC_FLAG_LKEY_KNOWN)) {
|
||||
encrypt_status = GATT_ENCRYPED_NO_MITM;
|
||||
if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) {
|
||||
encrypt_status = GATT_ENCRYPED_MITM;
|
||||
}
|
||||
}
|
||||
|
||||
GATT_TRACE_DEBUG("gatt_get_link_encrypt_status status=0x%x", encrypt_status);
|
||||
return encrypt_status ;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_convert_sec_action
|
||||
**
|
||||
** Description Convert GATT security action enum into equivalent BTM BLE security action enum
|
||||
**
|
||||
** Returns BOOLEAN TRUE - conversation is successful
|
||||
**
|
||||
*******************************************************************************/
|
||||
static BOOLEAN gatt_convert_sec_action(tGATT_SEC_ACTION gatt_sec_act, tBTM_BLE_SEC_ACT *p_btm_sec_act )
|
||||
{
|
||||
BOOLEAN status = TRUE;
|
||||
switch (gatt_sec_act) {
|
||||
case GATT_SEC_ENCRYPT:
|
||||
*p_btm_sec_act = BTM_BLE_SEC_ENCRYPT;
|
||||
break;
|
||||
case GATT_SEC_ENCRYPT_NO_MITM:
|
||||
*p_btm_sec_act = BTM_BLE_SEC_ENCRYPT_NO_MITM;
|
||||
break;
|
||||
case GATT_SEC_ENCRYPT_MITM:
|
||||
*p_btm_sec_act = BTM_BLE_SEC_ENCRYPT_MITM;
|
||||
break;
|
||||
default:
|
||||
status = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_check_enc_req
|
||||
**
|
||||
** Description check link security.
|
||||
**
|
||||
** Returns TRUE if encrypted, otherwise FALSE.
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN gatt_security_check_start(tGATT_CLCB *p_clcb)
|
||||
{
|
||||
tGATT_TCB *p_tcb = p_clcb->p_tcb;
|
||||
tGATT_SEC_ACTION gatt_sec_act;
|
||||
tBTM_BLE_SEC_ACT btm_ble_sec_act;
|
||||
BOOLEAN status = TRUE;
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
tBTM_STATUS btm_status;
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
tGATT_SEC_ACTION sec_act_old = gatt_get_sec_act(p_tcb);
|
||||
|
||||
gatt_sec_act = gatt_determine_sec_act(p_clcb);
|
||||
|
||||
if (sec_act_old == GATT_SEC_NONE) {
|
||||
gatt_set_sec_act(p_tcb, gatt_sec_act);
|
||||
}
|
||||
|
||||
switch (gatt_sec_act ) {
|
||||
case GATT_SEC_SIGN_DATA:
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
GATT_TRACE_DEBUG("gatt_security_check_start: Do data signing");
|
||||
gatt_sign_data(p_clcb);
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
break;
|
||||
case GATT_SEC_ENCRYPT:
|
||||
case GATT_SEC_ENCRYPT_NO_MITM:
|
||||
case GATT_SEC_ENCRYPT_MITM:
|
||||
if (sec_act_old < GATT_SEC_ENCRYPT) {
|
||||
GATT_TRACE_DEBUG("gatt_security_check_start: Encrypt now or key upgreade first");
|
||||
gatt_convert_sec_action(gatt_sec_act, &btm_ble_sec_act);
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
btm_status = BTM_SetEncryption(p_tcb->peer_bda, p_tcb->transport , gatt_enc_cmpl_cback, &btm_ble_sec_act);
|
||||
if ( (btm_status != BTM_SUCCESS) && (btm_status != BTM_CMD_STARTED)) {
|
||||
GATT_TRACE_ERROR("gatt_security_check_start BTM_SetEncryption failed btm_status=%d", btm_status);
|
||||
status = FALSE;
|
||||
}
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
}
|
||||
if (status) {
|
||||
gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb);
|
||||
}
|
||||
break;
|
||||
case GATT_SEC_ENC_PENDING:
|
||||
gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb);
|
||||
/* wait for link encrypotion to finish */
|
||||
break;
|
||||
default:
|
||||
gatt_sec_check_complete(TRUE, p_clcb, gatt_sec_act);
|
||||
break;
|
||||
}
|
||||
|
||||
if (status == FALSE) {
|
||||
gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
|
||||
gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#endif /* BLE_INCLUDED */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,256 @@
|
||||
#include "common/bt_target.h"
|
||||
#include "osi/allocator.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "gatt_int.h"
|
||||
#include "stack/l2c_api.h"
|
||||
#include "l2c_int.h"
|
||||
#include "smp_int.h"
|
||||
|
||||
#if (BLE_INCLUDED == TRUE && GATTS_INCLUDED == TRUE)
|
||||
|
||||
const char *const gatt_attr_name[] = {
|
||||
"primary service",
|
||||
"secondary service",
|
||||
"included service",
|
||||
"characteristic",
|
||||
};
|
||||
|
||||
const char *const gatt_char_desc_name[] = {
|
||||
"characteristic extended properties",
|
||||
"characteristic user description",
|
||||
"client characteristic configuration",
|
||||
"server characteristic configuration",
|
||||
"characteristic presentation format",
|
||||
"characteristic aggregate format",
|
||||
};
|
||||
|
||||
static const char *gatt_get_attr_name(UINT16 uuid)
|
||||
{
|
||||
if (uuid >= GATT_UUID_PRI_SERVICE && uuid <= GATT_UUID_CHAR_DECLARE) {
|
||||
return gatt_attr_name[uuid - GATT_UUID_PRI_SERVICE];
|
||||
}
|
||||
|
||||
if (uuid >= GATT_UUID_CHAR_EXT_PROP && uuid <= GATT_UUID_CHAR_AGG_FORMAT) {
|
||||
return gatt_char_desc_name[uuid - GATT_UUID_CHAR_EXT_PROP];
|
||||
}
|
||||
|
||||
return "Unknown Attribute";
|
||||
}
|
||||
|
||||
static void attr_uuid_to_bt_uuid(void *p_attr, tBT_UUID *p_uuid)
|
||||
{
|
||||
tGATT_ATTR16 *p_attr16 = (tGATT_ATTR16 *)p_attr;
|
||||
|
||||
if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_16) {
|
||||
p_uuid->len = LEN_UUID_16;
|
||||
p_uuid->uu.uuid16 = p_attr16->uuid;
|
||||
} else if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_32) {
|
||||
tGATT_ATTR32 *p_attr32 = (tGATT_ATTR32 *)p_attr;
|
||||
p_uuid->len = LEN_UUID_32;
|
||||
p_uuid->uu.uuid32 = p_attr32->uuid;
|
||||
} else if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_128) {
|
||||
tGATT_ATTR128 *p_attr128 = (tGATT_ATTR128 *)p_attr;
|
||||
p_uuid->len = LEN_UUID_128;
|
||||
memcpy(p_uuid->uu.uuid128, p_attr128->uuid, LEN_UUID_128);
|
||||
}
|
||||
}
|
||||
|
||||
static size_t calculate_database_info_size(void)
|
||||
{
|
||||
UINT8 i;
|
||||
tGATT_SVC_DB *p_db;
|
||||
tGATT_ATTR16 *p_attr;
|
||||
size_t len = 0;
|
||||
|
||||
for (i = 0; i < GATT_MAX_SR_PROFILES; i++) {
|
||||
p_db = gatt_cb.sr_reg[i].p_db;
|
||||
if (p_db && p_db->p_attr_list) {
|
||||
p_attr = (tGATT_ATTR16 *)p_db->p_attr_list;
|
||||
while (p_attr) {
|
||||
if (p_attr->uuid == GATT_UUID_PRI_SERVICE ||
|
||||
p_attr->uuid == GATT_UUID_SEC_SERVICE) {
|
||||
// Service declaration
|
||||
len += 4 + p_attr->p_value->uuid.len;
|
||||
} else if (p_attr->uuid == GATT_UUID_INCLUDE_SERVICE) {
|
||||
// Included service declaration
|
||||
len += 8 + p_attr->p_value->incl_handle.service_type.len;
|
||||
} else if (p_attr->uuid == GATT_UUID_CHAR_DECLARE) {
|
||||
tBT_UUID char_uuid = {0};
|
||||
// Characteristic declaration
|
||||
p_attr = (tGATT_ATTR16 *)p_attr->p_next;
|
||||
attr_uuid_to_bt_uuid((void *)p_attr, &char_uuid);
|
||||
// Increment 1 to fetch characteristic uuid from value declaration attribute
|
||||
len += 7 + char_uuid.len;
|
||||
} else if (p_attr->uuid == GATT_UUID_CHAR_DESCRIPTION ||
|
||||
p_attr->uuid == GATT_UUID_CHAR_CLIENT_CONFIG ||
|
||||
p_attr->uuid == GATT_UUID_CHAR_SRVR_CONFIG ||
|
||||
p_attr->uuid == GATT_UUID_CHAR_PRESENT_FORMAT ||
|
||||
p_attr->uuid == GATT_UUID_CHAR_AGG_FORMAT) {
|
||||
// Descriptor
|
||||
len += 4;
|
||||
} else if (p_attr->uuid == GATT_UUID_CHAR_EXT_PROP) {
|
||||
// Descriptor
|
||||
len += 6;
|
||||
}
|
||||
p_attr = (tGATT_ATTR16 *) p_attr->p_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void fill_database_info(UINT8 *p_data)
|
||||
{
|
||||
UINT8 i;
|
||||
tGATT_SVC_DB *p_db;
|
||||
tGATT_ATTR16 *p_attr;
|
||||
|
||||
for (i = 0; i < GATT_MAX_SR_PROFILES; i++) {
|
||||
p_db = gatt_cb.sr_reg[i].p_db;
|
||||
if (p_db && p_db->p_attr_list) {
|
||||
p_attr = (tGATT_ATTR16 *)p_db->p_attr_list;
|
||||
while (p_attr) {
|
||||
if (p_attr->uuid == GATT_UUID_PRI_SERVICE ||
|
||||
p_attr->uuid == GATT_UUID_SEC_SERVICE) {
|
||||
// Service declaration
|
||||
UINT16_TO_STREAM(p_data, p_attr->handle);
|
||||
UINT16_TO_STREAM(p_data, p_attr->uuid);
|
||||
gatt_build_uuid_to_stream(&p_data, p_attr->p_value->uuid);
|
||||
} else if (p_attr->uuid == GATT_UUID_INCLUDE_SERVICE) {
|
||||
// Included service declaration
|
||||
UINT16_TO_STREAM(p_data, p_attr->handle);
|
||||
UINT16_TO_STREAM(p_data, GATT_UUID_INCLUDE_SERVICE);
|
||||
UINT16_TO_STREAM(p_data, p_attr->p_value->incl_handle.s_handle);
|
||||
UINT16_TO_STREAM(p_data, p_attr->p_value->incl_handle.e_handle);
|
||||
gatt_build_uuid_to_stream(&p_data, p_attr->p_value->incl_handle.service_type);
|
||||
} else if (p_attr->uuid == GATT_UUID_CHAR_DECLARE) {
|
||||
tBT_UUID char_uuid = {0};
|
||||
// Characteristic declaration
|
||||
UINT16_TO_STREAM(p_data, p_attr->handle);
|
||||
UINT16_TO_STREAM(p_data, GATT_UUID_CHAR_DECLARE);
|
||||
UINT8_TO_STREAM(p_data, p_attr->p_value->char_decl.property);
|
||||
UINT16_TO_STREAM(p_data, p_attr->p_value->char_decl.char_val_handle);
|
||||
p_attr = (tGATT_ATTR16 *)p_attr->p_next;
|
||||
attr_uuid_to_bt_uuid((void *)p_attr, &char_uuid);
|
||||
// Increment 1 to fetch characteristic uuid from value declaration attribute
|
||||
gatt_build_uuid_to_stream(&p_data, char_uuid);
|
||||
} else if (p_attr->uuid == GATT_UUID_CHAR_DESCRIPTION ||
|
||||
p_attr->uuid == GATT_UUID_CHAR_CLIENT_CONFIG ||
|
||||
p_attr->uuid == GATT_UUID_CHAR_SRVR_CONFIG ||
|
||||
p_attr->uuid == GATT_UUID_CHAR_PRESENT_FORMAT ||
|
||||
p_attr->uuid == GATT_UUID_CHAR_AGG_FORMAT) {
|
||||
// Descriptor
|
||||
UINT16_TO_STREAM(p_data, p_attr->handle);
|
||||
UINT16_TO_STREAM(p_data, p_attr->uuid);
|
||||
} else if (p_attr->uuid == GATT_UUID_CHAR_EXT_PROP) {
|
||||
// Descriptor
|
||||
UINT16_TO_STREAM(p_data, p_attr->handle);
|
||||
UINT16_TO_STREAM(p_data, p_attr->uuid);
|
||||
// TODO: process extended properties descriptor
|
||||
if (p_attr->p_value->attr_val.attr_len == 2) {
|
||||
memcpy(p_data, p_attr->p_value->attr_val.attr_val, 2);
|
||||
} else {
|
||||
UINT16_TO_STREAM(p_data, 0x0000);
|
||||
}
|
||||
}
|
||||
p_attr = (tGATT_ATTR16 *) p_attr->p_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tGATT_STATUS gatts_calculate_datebase_hash(BT_OCTET16 hash)
|
||||
{
|
||||
UINT8 tmp;
|
||||
UINT16 i;
|
||||
UINT16 j;
|
||||
size_t len;
|
||||
UINT8 *data_buf = NULL;
|
||||
|
||||
len = calculate_database_info_size();
|
||||
|
||||
data_buf = (UINT8 *)osi_malloc(len);
|
||||
if (data_buf == NULL) {
|
||||
GATT_TRACE_ERROR ("%s failed to allocate buffer (%u)\n", __func__, len);
|
||||
return GATT_NO_RESOURCES;
|
||||
}
|
||||
|
||||
fill_database_info(data_buf);
|
||||
|
||||
// reverse database info
|
||||
for (i = 0, j = len-1; i < j; i++, j--) {
|
||||
tmp = data_buf[i];
|
||||
data_buf[i] = data_buf[j];
|
||||
data_buf[j] = tmp;
|
||||
}
|
||||
|
||||
#if SMP_INCLUDED == TRUE
|
||||
BT_OCTET16 key = {0};
|
||||
aes_cipher_msg_auth_code(key, data_buf, len, 16, hash);
|
||||
//ESP_LOG_BUFFER_HEX("db hash", hash, BT_OCTET16_LEN);
|
||||
#endif
|
||||
|
||||
osi_free(data_buf);
|
||||
return GATT_SUCCESS;
|
||||
}
|
||||
|
||||
void gatts_show_local_database(void)
|
||||
{
|
||||
UINT8 i;
|
||||
tGATT_SVC_DB *p_db;
|
||||
tGATT_ATTR16 *p_attr;
|
||||
|
||||
printf("\n================= GATTS DATABASE DUMP START =================\n");
|
||||
for (i = 0; i < GATT_MAX_SR_PROFILES; i++) {
|
||||
p_db = gatt_cb.sr_reg[i].p_db;
|
||||
if (p_db && p_db->p_attr_list) {
|
||||
p_attr = (tGATT_ATTR16 *)p_db->p_attr_list;
|
||||
while (p_attr) {
|
||||
switch (p_attr->uuid) {
|
||||
case GATT_UUID_PRI_SERVICE:
|
||||
case GATT_UUID_SEC_SERVICE:
|
||||
// Service declaration
|
||||
printf("%s\n", gatt_get_attr_name(p_attr->uuid));
|
||||
printf("\tuuid %s\n", gatt_uuid_to_str(&p_attr->p_value->uuid));
|
||||
printf("\thandle %d\n", p_attr->handle);
|
||||
printf("\tend_handle %d\n",p_db->end_handle-1);
|
||||
break;
|
||||
case GATT_UUID_INCLUDE_SERVICE:
|
||||
// Included service declaration
|
||||
printf("%s\n", gatt_get_attr_name(p_attr->uuid));
|
||||
printf("\tuuid %s\t", gatt_uuid_to_str(&p_attr->p_value->incl_handle.service_type));
|
||||
printf("\thandle %d\n", p_attr->p_value->incl_handle.s_handle);
|
||||
printf("\tend_handle %d\n", p_attr->p_value->incl_handle.e_handle);
|
||||
break;
|
||||
case GATT_UUID_CHAR_DECLARE: {
|
||||
tBT_UUID char_uuid = {0};
|
||||
tGATT_ATTR16 *p_char_val;
|
||||
p_char_val = (tGATT_ATTR16 *)p_attr->p_next;
|
||||
attr_uuid_to_bt_uuid((void *)p_char_val, &char_uuid);
|
||||
|
||||
printf("%s\n", gatt_get_attr_name(p_attr->uuid));
|
||||
printf("\tuuid %s\n", gatt_uuid_to_str(&char_uuid));
|
||||
printf("\tdef_handle %d\n", p_attr->handle);
|
||||
printf("\tval_handle %d\n", p_attr->p_value->char_decl.char_val_handle);
|
||||
printf("\tperm 0x%04x, prop 0x%02x\n", p_char_val->permission, p_attr->p_value->char_decl.property);
|
||||
break;
|
||||
}
|
||||
case GATT_UUID_CHAR_EXT_PROP:
|
||||
case GATT_UUID_CHAR_DESCRIPTION:
|
||||
case GATT_UUID_CHAR_CLIENT_CONFIG:
|
||||
case GATT_UUID_CHAR_SRVR_CONFIG:
|
||||
case GATT_UUID_CHAR_PRESENT_FORMAT:
|
||||
case GATT_UUID_CHAR_AGG_FORMAT:
|
||||
printf("%s\n", gatt_get_attr_name(p_attr->uuid));
|
||||
printf("\thandle %d\n", p_attr->handle);
|
||||
break;
|
||||
}
|
||||
p_attr = (tGATT_ATTR16 *) p_attr->p_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("================= GATTS DATABASE DUMP END =================\n");
|
||||
}
|
||||
#endif /* BLE_INCLUDED == TRUE && GATTS_INCLUDED == TRUE */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,788 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 1999-2012 Broadcom Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef GATT_INT_H
|
||||
#define GATT_INT_H
|
||||
|
||||
#include "common/bt_target.h"
|
||||
#include "common/bt_trace.h"
|
||||
#include "stack/gatt_api.h"
|
||||
#include "stack/btm_ble_api.h"
|
||||
#include "stack/btu.h"
|
||||
#include "osi/fixed_queue.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define GATT_CREATE_CONN_ID(tcb_idx, gatt_if) ((UINT16) ((((UINT8)(tcb_idx) ) << 8) | ((UINT8) (gatt_if))))
|
||||
#define GATT_GET_TCB_IDX(conn_id) ((UINT8) (((UINT16) (conn_id)) >> 8))
|
||||
#define GATT_GET_GATT_IF(conn_id) ((tGATT_IF)((UINT8) (conn_id)))
|
||||
|
||||
#define GATT_GET_SR_REG_PTR(index) (&gatt_cb.sr_reg[(UINT8) (index)]);
|
||||
#define GATT_TRANS_ID_MAX 0x0fffffff /* 4 MSB is reserved */
|
||||
#define GATT_RSP_BY_APP 0x00
|
||||
#define GATT_RSP_BY_STACK 0x01
|
||||
#define GATT_RSP_DEFAULT GATT_RSP_BY_APP //need to rsp by the app.
|
||||
|
||||
/* security action for GATT write and read request */
|
||||
#define GATT_SEC_NONE 0
|
||||
#define GATT_SEC_OK 1
|
||||
#define GATT_SEC_SIGN_DATA 2 /* compute the signature for the write cmd */
|
||||
#define GATT_SEC_ENCRYPT 3 /* encrypt the link with current key */
|
||||
#define GATT_SEC_ENCRYPT_NO_MITM 4 /* unauthenticated encryption or better */
|
||||
#define GATT_SEC_ENCRYPT_MITM 5 /* authenticated encryption */
|
||||
#define GATT_SEC_ENC_PENDING 6 /* wait for link encryption pending */
|
||||
typedef UINT8 tGATT_SEC_ACTION;
|
||||
|
||||
|
||||
#define GATT_ATTR_OP_SPT_MTU (0x00000001 << 0)
|
||||
#define GATT_ATTR_OP_SPT_FIND_INFO (0x00000001 << 1)
|
||||
#define GATT_ATTR_OP_SPT_FIND_BY_TYPE (0x00000001 << 2)
|
||||
#define GATT_ATTR_OP_SPT_READ_BY_TYPE (0x00000001 << 3)
|
||||
#define GATT_ATTR_OP_SPT_READ (0x00000001 << 4)
|
||||
#define GATT_ATTR_OP_SPT_MULT_READ (0x00000001 << 5)
|
||||
#define GATT_ATTR_OP_SPT_READ_BLOB (0x00000001 << 6)
|
||||
#define GATT_ATTR_OP_SPT_READ_BY_GRP_TYPE (0x00000001 << 7)
|
||||
#define GATT_ATTR_OP_SPT_WRITE (0x00000001 << 8)
|
||||
#define GATT_ATTR_OP_SPT_WRITE_CMD (0x00000001 << 9)
|
||||
#define GATT_ATTR_OP_SPT_PREP_WRITE (0x00000001 << 10)
|
||||
#define GATT_ATTR_OP_SPT_EXE_WRITE (0x00000001 << 11)
|
||||
#define GATT_ATTR_OP_SPT_HDL_VALUE_CONF (0x00000001 << 12)
|
||||
#define GATT_ATTR_OP_SP_SIGN_WRITE (0x00000001 << 13)
|
||||
|
||||
#define GATT_INDEX_INVALID 0xff
|
||||
|
||||
#define GATT_PENDING_REQ_NONE 0
|
||||
|
||||
|
||||
#define GATT_WRITE_CMD_MASK 0xc0 /*0x1100-0000*/
|
||||
#define GATT_AUTH_SIGN_MASK 0x80 /*0x1000-0000*/
|
||||
#define GATT_AUTH_SIGN_LEN 12
|
||||
|
||||
#define GATT_HDR_SIZE 3 /* 1B opcode + 2B handle */
|
||||
|
||||
/* wait for ATT cmd response timeout value */
|
||||
#define GATT_WAIT_FOR_RSP_TOUT 30
|
||||
#define GATT_WAIT_FOR_DISC_RSP_TOUT 15
|
||||
#define GATT_REQ_RETRY_LIMIT 2
|
||||
#define GATT_WAIT_FOR_IND_ACK_TOUT 5
|
||||
|
||||
/* characteristic descriptor type */
|
||||
#define GATT_DESCR_EXT_DSCPTOR 1 /* Characteristic Extended Properties */
|
||||
#define GATT_DESCR_USER_DSCPTOR 2 /* Characteristic User Description */
|
||||
#define GATT_DESCR_CLT_CONFIG 3 /* Client Characteristic Configuration */
|
||||
#define GATT_DESCR_SVR_CONFIG 4 /* Server Characteristic Configuration */
|
||||
#define GATT_DESCR_PRES_FORMAT 5 /* Characteristic Presentation Format */
|
||||
#define GATT_DESCR_AGGR_FORMAT 6 /* Characteristic Aggregate Format */
|
||||
#define GATT_DESCR_VALID_RANGE 7 /* Characteristic Valid Range */
|
||||
#define GATT_DESCR_UNKNOWN 0xff
|
||||
|
||||
#define GATT_SEC_FLAG_LKEY_UNAUTHED BTM_SEC_FLAG_LKEY_KNOWN
|
||||
#define GATT_SEC_FLAG_LKEY_AUTHED BTM_SEC_FLAG_LKEY_AUTHED
|
||||
#define GATT_SEC_FLAG_ENCRYPTED BTM_SEC_FLAG_ENCRYPTED
|
||||
#define GATT_SEC_FLAG_AUTHORIZATION BTM_SEC_FLAG_AUTHORIZED
|
||||
typedef UINT8 tGATT_SEC_FLAG;
|
||||
|
||||
/* Find Information Response Type
|
||||
*/
|
||||
#define GATT_INFO_TYPE_PAIR_16 0x01
|
||||
#define GATT_INFO_TYPE_PAIR_128 0x02
|
||||
|
||||
#define GATTS_SEND_SERVICE_CHANGE_AUTO 0
|
||||
#define GATTS_SEND_SERVICE_CHANGE_MANUAL 1
|
||||
|
||||
/* GATT client FIND_TYPE_VALUE_Request data */
|
||||
typedef struct {
|
||||
tBT_UUID uuid; /* type of attribute to be found */
|
||||
UINT16 s_handle; /* starting handle */
|
||||
UINT16 e_handle; /* ending handle */
|
||||
UINT16 value_len; /* length of the attribute value */
|
||||
UINT8 value[GATT_MAX_MTU_SIZE]; /* pointer to the attribute value to be found */
|
||||
} tGATT_FIND_TYPE_VALUE;
|
||||
|
||||
/* client request message to ATT protocol
|
||||
*/
|
||||
typedef union {
|
||||
tGATT_READ_BY_TYPE browse; /* read by type request */
|
||||
tGATT_FIND_TYPE_VALUE find_type_value;/* find by type value */
|
||||
tGATT_READ_MULTI read_multi; /* read multiple request */
|
||||
tGATT_READ_PARTIAL read_blob; /* read blob */
|
||||
tGATT_VALUE attr_value; /* write request */
|
||||
/* prepare write */
|
||||
/* write blob */
|
||||
UINT16 handle; /* read, handle value confirmation */
|
||||
UINT16 mtu;
|
||||
tGATT_EXEC_FLAG exec_write; /* execute write */
|
||||
} tGATT_CL_MSG;
|
||||
|
||||
/* error response strucutre */
|
||||
typedef struct {
|
||||
UINT16 handle;
|
||||
UINT8 cmd_code;
|
||||
UINT8 reason;
|
||||
} tGATT_ERROR;
|
||||
|
||||
/* Execute write response structure */
|
||||
typedef struct {
|
||||
UINT8 op_code;
|
||||
}__attribute__((packed)) tGATT_EXEC_WRITE_RSP;
|
||||
|
||||
/* Write request response structure */
|
||||
typedef struct {
|
||||
UINT8 op_code;
|
||||
}__attribute__((packed)) tGATT_WRITE_REQ_RSP;
|
||||
|
||||
/* server response message to ATT protocol
|
||||
*/
|
||||
typedef union {
|
||||
/* data type member event */
|
||||
tGATT_VALUE attr_value; /* READ, HANDLE_VALUE_IND, PREPARE_WRITE */
|
||||
/* READ_BLOB, READ_BY_TYPE */
|
||||
tGATT_ERROR error; /* ERROR_RSP */
|
||||
UINT16 handle; /* WRITE, WRITE_BLOB */
|
||||
UINT16 mtu; /* exchange MTU request */
|
||||
} tGATT_SR_MSG;
|
||||
|
||||
/* Characteristic declaration attribute value
|
||||
*/
|
||||
typedef struct {
|
||||
tGATT_CHAR_PROP property;
|
||||
UINT16 char_val_handle;
|
||||
} tGATT_CHAR_DECL;
|
||||
|
||||
/* attribute value maintained in the server database
|
||||
*/
|
||||
typedef union {
|
||||
tBT_UUID uuid; /* service declaration */
|
||||
tGATT_CHAR_DECL char_decl; /* characteristic declaration */
|
||||
tGATT_INCL_SRVC incl_handle; /* included service */
|
||||
tGATT_ATTR_VAL attr_val;
|
||||
} tGATT_ATTR_VALUE;
|
||||
|
||||
/* Attribute UUID type
|
||||
*/
|
||||
#define GATT_ATTR_UUID_TYPE_16 0
|
||||
#define GATT_ATTR_UUID_TYPE_128 1
|
||||
#define GATT_ATTR_UUID_TYPE_32 2
|
||||
typedef UINT8 tGATT_ATTR_UUID_TYPE;
|
||||
|
||||
/* 16 bits UUID Attribute in server database
|
||||
*/
|
||||
typedef struct {
|
||||
void *p_next; /* pointer to the next attribute, either tGATT_ATTR16 or tGATT_ATTR128 */
|
||||
tGATT_ATTR_VALUE *p_value;
|
||||
tGATT_ATTR_UUID_TYPE uuid_type;
|
||||
tGATT_PERM permission;
|
||||
tGATTS_ATTR_CONTROL control;
|
||||
tGATT_ATTR_MASK mask;
|
||||
UINT16 handle;
|
||||
UINT16 uuid;
|
||||
} tGATT_ATTR16;
|
||||
|
||||
/* 32 bits UUID Attribute in server database
|
||||
*/
|
||||
typedef struct {
|
||||
void *p_next; /* pointer to the next attribute, either tGATT_ATTR16, tGATT_ATTR32 or tGATT_ATTR128 */
|
||||
tGATT_ATTR_VALUE *p_value;
|
||||
tGATT_ATTR_UUID_TYPE uuid_type;
|
||||
tGATT_PERM permission;
|
||||
tGATTS_ATTR_CONTROL control;
|
||||
tGATT_ATTR_MASK mask;
|
||||
UINT16 handle;
|
||||
UINT32 uuid;
|
||||
} tGATT_ATTR32;
|
||||
|
||||
|
||||
/* 128 bits UUID Attribute in server database
|
||||
*/
|
||||
typedef struct {
|
||||
void *p_next; /* pointer to the next attribute, either tGATT_ATTR16 or tGATT_ATTR128 */
|
||||
tGATT_ATTR_VALUE *p_value;
|
||||
tGATT_ATTR_UUID_TYPE uuid_type;
|
||||
tGATT_PERM permission;
|
||||
tGATTS_ATTR_CONTROL control;
|
||||
tGATT_ATTR_MASK mask;
|
||||
UINT16 handle;
|
||||
UINT8 uuid[LEN_UUID_128];
|
||||
} tGATT_ATTR128;
|
||||
|
||||
/* Service Database definition
|
||||
*/
|
||||
typedef struct {
|
||||
void *p_attr_list; /* pointer to the first attribute, either tGATT_ATTR16 or tGATT_ATTR128 */
|
||||
UINT8 *p_free_mem; /* Pointer to free memory */
|
||||
fixed_queue_t *svc_buffer; /* buffer queue used for service database */
|
||||
UINT32 mem_free; /* Memory still available */
|
||||
UINT16 end_handle; /* Last handle number */
|
||||
UINT16 next_handle; /* Next usable handle value */
|
||||
} tGATT_SVC_DB;
|
||||
|
||||
/* Data Structure used for GATT server */
|
||||
/* A GATT registration record consists of a handle, and 1 or more attributes */
|
||||
/* A service registration information record consists of beginning and ending */
|
||||
/* attribute handle, service UUID and a set of GATT server callback. */
|
||||
typedef struct {
|
||||
tGATT_SVC_DB *p_db; /* pointer to the service database */
|
||||
tBT_UUID app_uuid; /* applicatino UUID */
|
||||
UINT32 sdp_handle; /* primamry service SDP handle */
|
||||
UINT16 service_instance; /* service instance number */
|
||||
UINT16 type; /* service type UUID, primary or secondary */
|
||||
UINT16 s_hdl; /* service starting handle */
|
||||
UINT16 e_hdl; /* service ending handle */
|
||||
tGATT_IF gatt_if; /* this service is belong to which application */
|
||||
BOOLEAN in_use;
|
||||
} tGATT_SR_REG;
|
||||
|
||||
#define GATT_LISTEN_TO_ALL 0xff
|
||||
#define GATT_LISTEN_TO_NONE 0
|
||||
|
||||
/* Data Structure used for GATT server */
|
||||
/* An GATT registration record consists of a handle, and 1 or more attributes */
|
||||
/* A service registration information record consists of beginning and ending */
|
||||
/* attribute handle, service UUID and a set of GATT server callback. */
|
||||
|
||||
typedef struct {
|
||||
tBT_UUID app_uuid128;
|
||||
tGATT_CBACK app_cb;
|
||||
tGATT_IF gatt_if; /* one based */
|
||||
BOOLEAN in_use;
|
||||
UINT8 listening; /* if adv for all has been enabled */
|
||||
} tGATT_REG;
|
||||
|
||||
|
||||
|
||||
|
||||
/* command queue for each connection */
|
||||
typedef struct {
|
||||
BT_HDR *p_cmd;
|
||||
UINT16 clcb_idx;
|
||||
UINT8 op_code;
|
||||
BOOLEAN to_send;
|
||||
} tGATT_CMD_Q;
|
||||
|
||||
|
||||
#if GATT_MAX_SR_PROFILES <= 8
|
||||
typedef UINT8 tGATT_APP_MASK;
|
||||
#elif GATT_MAX_SR_PROFILES <= 16
|
||||
typedef UINT16 tGATT_APP_MASK;
|
||||
#elif GATT_MAX_SR_PROFILES <= 32
|
||||
typedef UINT32 tGATT_APP_MASK;
|
||||
#endif
|
||||
|
||||
/* command details for each connection */
|
||||
typedef struct {
|
||||
BT_HDR *p_rsp_msg;
|
||||
UINT32 trans_id;
|
||||
tGATT_READ_MULTI multi_req;
|
||||
fixed_queue_t *multi_rsp_q;
|
||||
UINT16 handle;
|
||||
UINT8 op_code;
|
||||
UINT8 status;
|
||||
UINT8 cback_cnt[GATT_MAX_APPS];
|
||||
} tGATT_SR_CMD;
|
||||
|
||||
#define GATT_CH_CLOSE 0
|
||||
#define GATT_CH_CLOSING 1
|
||||
#define GATT_CH_CONN 2
|
||||
#define GATT_CH_CFG 3
|
||||
#define GATT_CH_OPEN 4
|
||||
|
||||
typedef UINT8 tGATT_CH_STATE;
|
||||
|
||||
#define GATT_GATT_START_HANDLE 1
|
||||
#define GATT_GAP_START_HANDLE 20
|
||||
#define GATT_APP_START_HANDLE 40
|
||||
|
||||
typedef struct hdl_cfg {
|
||||
UINT16 gatt_start_hdl;
|
||||
UINT16 gap_start_hdl;
|
||||
UINT16 app_start_hdl;
|
||||
} tGATT_HDL_CFG;
|
||||
|
||||
typedef struct hdl_list_elem {
|
||||
struct hdl_list_elem *p_next;
|
||||
struct hdl_list_elem *p_prev;
|
||||
tGATTS_HNDL_RANGE asgn_range; /* assigned handle range */
|
||||
tGATT_SVC_DB svc_db;
|
||||
BOOLEAN in_use;
|
||||
} tGATT_HDL_LIST_ELEM;
|
||||
|
||||
typedef struct {
|
||||
tGATT_HDL_LIST_ELEM *p_first;
|
||||
tGATT_HDL_LIST_ELEM *p_last;
|
||||
UINT16 count;
|
||||
} tGATT_HDL_LIST_INFO;
|
||||
|
||||
|
||||
typedef struct srv_list_elem {
|
||||
struct srv_list_elem *p_next;
|
||||
struct srv_list_elem *p_prev;
|
||||
UINT16 s_hdl;
|
||||
UINT8 i_sreg;
|
||||
BOOLEAN in_use;
|
||||
BOOLEAN is_primary;
|
||||
} tGATT_SRV_LIST_ELEM;
|
||||
|
||||
|
||||
typedef struct {
|
||||
tGATT_SRV_LIST_ELEM *p_last_primary;
|
||||
tGATT_SRV_LIST_ELEM *p_first;
|
||||
tGATT_SRV_LIST_ELEM *p_last;
|
||||
UINT16 count;
|
||||
} tGATT_SRV_LIST_INFO;
|
||||
|
||||
/* prepare write queue data */
|
||||
typedef struct{
|
||||
//len: length of value
|
||||
tGATT_ATTR16 *p_attr;
|
||||
UINT16 len;
|
||||
UINT8 op_code;
|
||||
UINT16 handle;
|
||||
UINT16 offset;
|
||||
UINT8 value[2];
|
||||
}__attribute__((packed)) tGATT_PREPARE_WRITE_QUEUE_DATA;
|
||||
|
||||
/* structure to store prepare write packts information */
|
||||
typedef struct{
|
||||
//only store prepare write packets which need
|
||||
//to be responded by stack (not by application)
|
||||
fixed_queue_t *queue;
|
||||
|
||||
//store the total number of prepare write packets
|
||||
//including that should be responded by stack or by application
|
||||
UINT16 total_num;
|
||||
|
||||
//store application error code for prepare write,
|
||||
//invalid offset && invalid length
|
||||
UINT8 error_code_app;
|
||||
}tGATT_PREPARE_WRITE_RECORD;
|
||||
|
||||
typedef struct {
|
||||
fixed_queue_t *pending_enc_clcb; /* pending encryption channel q */
|
||||
tGATT_SEC_ACTION sec_act;
|
||||
BD_ADDR peer_bda;
|
||||
tBT_TRANSPORT transport;
|
||||
UINT32 trans_id;
|
||||
|
||||
UINT16 att_lcid; /* L2CAP channel ID for ATT */
|
||||
UINT16 payload_size;
|
||||
|
||||
tGATT_CH_STATE ch_state;
|
||||
UINT8 ch_flags;
|
||||
|
||||
tGATT_IF app_hold_link[GATT_MAX_APPS];
|
||||
|
||||
/* server needs */
|
||||
/* server response data */
|
||||
#if (GATTS_INCLUDED == TRUE)
|
||||
tGATT_SR_CMD sr_cmd;
|
||||
#endif ///GATTS_INCLUDED == TRUE
|
||||
UINT16 indicate_handle;
|
||||
fixed_queue_t *pending_ind_q;
|
||||
|
||||
TIMER_LIST_ENT conf_timer_ent; /* peer confirm to indication timer */
|
||||
|
||||
UINT8 prep_cnt[GATT_MAX_APPS];
|
||||
UINT8 ind_count;
|
||||
|
||||
tGATT_CMD_Q cl_cmd_q[GATT_CL_MAX_LCB];
|
||||
TIMER_LIST_ENT ind_ack_timer_ent; /* local app confirm to indication timer */
|
||||
UINT8 pending_cl_req;
|
||||
UINT8 next_slot_inq; /* index of next available slot in queue */
|
||||
|
||||
/* client supported feature */
|
||||
UINT8 cl_supp_feat;
|
||||
/* server supported feature */
|
||||
UINT8 sr_supp_feat;
|
||||
/* if false, should handle database out of sync */
|
||||
BOOLEAN is_robust_cache_change_aware;
|
||||
|
||||
BOOLEAN in_use;
|
||||
UINT8 tcb_idx;
|
||||
tGATT_PREPARE_WRITE_RECORD prepare_write_record; /* prepare write packets record */
|
||||
} tGATT_TCB;
|
||||
|
||||
|
||||
/* logic channel */
|
||||
typedef struct {
|
||||
UINT16 next_disc_start_hdl; /* starting handle for the next inc srvv discovery */
|
||||
tGATT_DISC_RES result;
|
||||
BOOLEAN wait_for_read_rsp;
|
||||
} tGATT_READ_INC_UUID128;
|
||||
typedef struct {
|
||||
tGATT_TCB *p_tcb; /* associated TCB of this CLCB */
|
||||
tGATT_REG *p_reg; /* owner of this CLCB */
|
||||
UINT8 sccb_idx;
|
||||
UINT8 *p_attr_buf; /* attribute buffer for read multiple, prepare write */
|
||||
tBT_UUID uuid;
|
||||
UINT16 conn_id; /* connection handle */
|
||||
UINT16 clcb_idx;
|
||||
UINT16 s_handle; /* starting handle of the active request */
|
||||
UINT16 e_handle; /* ending handle of the active request */
|
||||
UINT16 counter; /* used as offset, attribute length, num of prepare write */
|
||||
UINT16 start_offset;
|
||||
tGATT_AUTH_REQ auth_req; /* authentication requirement */
|
||||
UINT8 operation; /* one logic channel can have one operation active */
|
||||
UINT8 op_subtype; /* operation subtype */
|
||||
UINT8 status; /* operation status */
|
||||
BOOLEAN first_read_blob_after_read;
|
||||
tGATT_READ_INC_UUID128 read_uuid128;
|
||||
BOOLEAN in_use;
|
||||
TIMER_LIST_ENT rsp_timer_ent; /* peer response timer */
|
||||
UINT8 retry_count;
|
||||
|
||||
} tGATT_CLCB;
|
||||
|
||||
typedef struct {
|
||||
tGATT_CLCB *p_clcb;
|
||||
} tGATT_PENDING_ENC_CLCB;
|
||||
|
||||
|
||||
#define GATT_SIGN_WRITE 1
|
||||
#define GATT_VERIFY_SIGN_DATA 2
|
||||
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
tGATT_CLCB *p_clcb;
|
||||
} tGATT_SIGN_WRITE_OP;
|
||||
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
tGATT_TCB *p_tcb;
|
||||
BT_HDR *p_data;
|
||||
|
||||
} tGATT_VERIFY_SIGN_OP;
|
||||
|
||||
|
||||
typedef struct {
|
||||
UINT16 clcb_idx;
|
||||
BOOLEAN in_use;
|
||||
} tGATT_SCCB;
|
||||
|
||||
typedef struct {
|
||||
UINT16 handle;
|
||||
UINT16 uuid;
|
||||
UINT32 service_change;
|
||||
} tGATT_SVC_CHG;
|
||||
|
||||
typedef struct {
|
||||
tGATT_IF gatt_if[GATT_MAX_APPS];
|
||||
tGATT_IF listen_gif[GATT_MAX_APPS];
|
||||
BD_ADDR remote_bda;
|
||||
BOOLEAN in_use;
|
||||
} tGATT_BG_CONN_DEV;
|
||||
|
||||
#define GATT_SVC_CHANGED_CONNECTING 1 /* wait for connection */
|
||||
#define GATT_SVC_CHANGED_SERVICE 2 /* GATT service discovery */
|
||||
#define GATT_SVC_CHANGED_CHARACTERISTIC 3 /* service change char discovery */
|
||||
#define GATT_SVC_CHANGED_DESCRIPTOR 4 /* service change CCC discoery */
|
||||
#define GATT_SVC_CHANGED_CONFIGURE_CCCD 5 /* config CCC */
|
||||
|
||||
typedef struct {
|
||||
UINT16 conn_id;
|
||||
BOOLEAN in_use;
|
||||
BOOLEAN connected;
|
||||
BD_ADDR bda;
|
||||
tBT_TRANSPORT transport;
|
||||
|
||||
/* GATT service change CCC related variables */
|
||||
UINT8 ccc_stage;
|
||||
UINT8 ccc_result;
|
||||
UINT16 s_handle;
|
||||
UINT16 e_handle;
|
||||
} tGATT_PROFILE_CLCB;
|
||||
|
||||
typedef struct {
|
||||
list_t *p_tcb_list;
|
||||
fixed_queue_t *sign_op_queue;
|
||||
|
||||
tGATT_SR_REG sr_reg[GATT_MAX_SR_PROFILES];
|
||||
UINT16 next_handle; /* next available handle */
|
||||
tGATT_SVC_CHG gattp_attr; /* GATT profile attribute service change */
|
||||
tGATT_IF gatt_if;
|
||||
#if (GATTS_INCLUDED == TRUE)
|
||||
tGATT_HDL_LIST_INFO hdl_list_info;
|
||||
tGATT_HDL_LIST_ELEM hdl_list[GATT_MAX_SR_PROFILES];
|
||||
tGATT_SRV_LIST_INFO srv_list_info;
|
||||
tGATT_SRV_LIST_ELEM srv_list[GATT_MAX_SR_PROFILES];
|
||||
#endif ///GATTS_INCLUDED == TRUE
|
||||
fixed_queue_t *srv_chg_clt_q; /* service change clients queue */
|
||||
fixed_queue_t *pending_new_srv_start_q; /* pending new service start queue */
|
||||
tGATT_REG cl_rcb[GATT_MAX_APPS];
|
||||
list_t *p_clcb_list; /* connection link control block*/
|
||||
tGATT_SCCB sccb[GATT_MAX_SCCB]; /* sign complete callback function GATT_MAX_SCCB <= GATT_CL_MAX_LCB */
|
||||
UINT8 trace_level;
|
||||
UINT16 def_mtu_size;
|
||||
|
||||
#if GATT_CONFORMANCE_TESTING == TRUE
|
||||
BOOLEAN enable_err_rsp;
|
||||
UINT8 req_op_code;
|
||||
UINT8 err_status;
|
||||
UINT16 handle;
|
||||
#endif
|
||||
#if (GATTS_INCLUDED == TRUE)
|
||||
tGATT_PROFILE_CLCB profile_clcb[GATT_MAX_APPS];
|
||||
#endif ///GATTS_INCLUDED == TRUE
|
||||
UINT16 handle_of_h_r; /* Handle of the handles reused characteristic value */
|
||||
#if GATTS_ROBUST_CACHING_ENABLED
|
||||
UINT16 handle_of_database_hash;
|
||||
UINT16 handle_of_cl_supported_feat;
|
||||
UINT16 handle_of_sr_supported_feat;
|
||||
BT_OCTET16 database_hash;
|
||||
UINT8 gatt_sr_supported_feat_mask;
|
||||
UINT8 gatt_cl_supported_feat_mask;
|
||||
|
||||
#endif
|
||||
tGATT_APPL_INFO cb_info;
|
||||
|
||||
|
||||
|
||||
tGATT_HDL_CFG hdl_cfg;
|
||||
tGATT_BG_CONN_DEV bgconn_dev[GATT_MAX_BG_CONN_DEV];
|
||||
|
||||
BOOLEAN auto_disc; /* internal use: true for auto discovering after connected */
|
||||
UINT8 srv_chg_mode; /* internal use: service change mode */
|
||||
tGATTS_RSP rsp; /* use to read internal service attribute */
|
||||
} tGATT_CB;
|
||||
|
||||
typedef struct{
|
||||
UINT16 local_mtu;
|
||||
} tGATT_DEFAULT;
|
||||
|
||||
#define GATT_SIZE_OF_SRV_CHG_HNDL_RANGE 4
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern tGATT_DEFAULT gatt_default;
|
||||
|
||||
/* Global GATT data */
|
||||
#if GATT_DYNAMIC_MEMORY == FALSE
|
||||
extern tGATT_CB gatt_cb;
|
||||
#else
|
||||
extern tGATT_CB *gatt_cb_ptr;
|
||||
#define gatt_cb (*gatt_cb_ptr)
|
||||
#endif
|
||||
|
||||
#if GATT_CONFORMANCE_TESTING == TRUE
|
||||
extern void gatt_set_err_rsp(BOOLEAN enable, UINT8 req_op_code, UINT8 err_status);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* internal functions */
|
||||
extern void gatt_init (void);
|
||||
extern void gatt_free(void);
|
||||
|
||||
/* from gatt_main.c */
|
||||
extern BOOLEAN gatt_disconnect (tGATT_TCB *p_tcb);
|
||||
extern BOOLEAN gatt_act_connect (tGATT_REG *p_reg, BD_ADDR bd_addr, tBLE_ADDR_TYPE bd_addr_type, tBT_TRANSPORT transport, BOOLEAN is_aux);
|
||||
extern BOOLEAN gatt_connect (BD_ADDR rem_bda, tBLE_ADDR_TYPE bd_addr_type, tGATT_TCB *p_tcb, tBT_TRANSPORT transport, BOOLEAN is_aux);
|
||||
extern void gatt_data_process (tGATT_TCB *p_tcb, BT_HDR *p_buf);
|
||||
extern void gatt_update_app_use_link_flag ( tGATT_IF gatt_if, tGATT_TCB *p_tcb, BOOLEAN is_add, BOOLEAN check_acl_link);
|
||||
|
||||
extern void gatt_profile_db_init(void);
|
||||
extern void gatt_set_ch_state(tGATT_TCB *p_tcb, tGATT_CH_STATE ch_state);
|
||||
extern tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB *p_tcb);
|
||||
extern void gatt_init_srv_chg(void);
|
||||
extern void gatt_proc_srv_chg (void);
|
||||
extern tGATT_STATUS gatt_send_srv_chg_ind (BD_ADDR peer_bda);
|
||||
extern void gatt_chk_srv_chg(tGATTS_SRV_CHG *p_srv_chg_clt);
|
||||
extern void gatt_add_a_bonded_dev_for_srv_chg (BD_ADDR bda);
|
||||
|
||||
/* from gatt_attr.c */
|
||||
extern UINT16 gatt_profile_find_conn_id_by_bd_addr(BD_ADDR bda);
|
||||
|
||||
|
||||
/* Functions provided by att_protocol.c */
|
||||
extern tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, tGATT_CL_MSG *p_msg);
|
||||
extern BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, UINT8 op_code, tGATT_SR_MSG *p_msg);
|
||||
extern tGATT_STATUS attp_send_sr_msg (tGATT_TCB *p_tcb, BT_HDR *p_msg);
|
||||
extern tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP);
|
||||
|
||||
/* utility functions */
|
||||
extern UINT8 *gatt_dbg_op_name(UINT8 op_code);
|
||||
#if (SDP_INCLUDED == TRUE && CLASSIC_BT_GATT_INCLUDED == TRUE)
|
||||
extern UINT32 gatt_add_sdp_record (tBT_UUID *p_uuid, UINT16 start_hdl, UINT16 end_hdl);
|
||||
#endif ///SDP_INCLUDED == TRUE && CLASSIC_BT_GATT_INCLUDED == TRUE
|
||||
extern BOOLEAN gatt_parse_uuid_from_cmd(tBT_UUID *p_uuid, UINT16 len, UINT8 **p_data);
|
||||
extern UINT8 gatt_build_uuid_to_stream(UINT8 **p_dst, tBT_UUID uuid);
|
||||
extern BOOLEAN gatt_uuid_compare(tBT_UUID src, tBT_UUID tar);
|
||||
extern void gatt_convert_uuid32_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT32 uuid_32);
|
||||
extern char *gatt_uuid_to_str(const tBT_UUID *uuid);
|
||||
extern void gatt_sr_get_sec_info(BD_ADDR rem_bda, tBT_TRANSPORT transport, UINT8 *p_sec_flag, UINT8 *p_key_size);
|
||||
extern void gatt_start_rsp_timer(UINT16 clcb_idx);
|
||||
extern void gatt_start_conf_timer(tGATT_TCB *p_tcb);
|
||||
extern void gatt_rsp_timeout(TIMER_LIST_ENT *p_tle);
|
||||
extern void gatt_ind_ack_timeout(TIMER_LIST_ENT *p_tle);
|
||||
extern void gatt_start_ind_ack_timer(tGATT_TCB *p_tcb);
|
||||
extern tGATT_STATUS gatt_send_error_rsp(tGATT_TCB *p_tcb, UINT8 err_code, UINT8 op_code, UINT16 handle, BOOLEAN deq);
|
||||
extern void gatt_dbg_display_uuid(tBT_UUID bt_uuid);
|
||||
extern tGATT_PENDING_ENC_CLCB *gatt_add_pending_enc_channel_clcb(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb );
|
||||
|
||||
extern tGATTS_PENDING_NEW_SRV_START *gatt_sr_is_new_srv_chg(tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, UINT16 svc_inst);
|
||||
|
||||
extern BOOLEAN gatt_is_srv_chg_ind_pending (tGATT_TCB *p_tcb);
|
||||
extern tGATTS_SRV_CHG *gatt_is_bda_in_the_srv_chg_clt_list (BD_ADDR bda);
|
||||
|
||||
extern BOOLEAN gatt_find_the_connected_bda(UINT8 start_idx, BD_ADDR bda, UINT8 *p_found_idx, tBT_TRANSPORT *p_transport);
|
||||
extern void gatt_set_srv_chg(void);
|
||||
extern void gatt_delete_dev_from_srv_chg_clt_list(BD_ADDR bd_addr);
|
||||
extern tGATT_VALUE *gatt_add_pending_ind(tGATT_TCB *p_tcb, tGATT_VALUE *p_ind);
|
||||
extern tGATTS_PENDING_NEW_SRV_START *gatt_add_pending_new_srv_start( tGATTS_HNDL_RANGE *p_new_srv_start);
|
||||
extern void gatt_free_srvc_db_buffer_app_id(tBT_UUID *p_app_id);
|
||||
extern BOOLEAN gatt_update_listen_mode(void);
|
||||
extern BOOLEAN gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb);
|
||||
|
||||
/* reserved handle list */
|
||||
extern tGATT_HDL_LIST_ELEM *gatt_find_hdl_buffer_by_app_id (tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, UINT16 svc_inst);
|
||||
extern tGATT_HDL_LIST_ELEM *gatt_find_hdl_buffer_by_handle(UINT16 handle);
|
||||
extern tGATT_HDL_LIST_ELEM *gatt_find_hdl_buffer_by_attr_handle(UINT16 attr_handle);
|
||||
extern tGATT_HDL_LIST_ELEM *gatt_alloc_hdl_buffer(void);
|
||||
extern void gatt_free_hdl_buffer(tGATT_HDL_LIST_ELEM *p);
|
||||
extern void gatt_free_attr_value_buffer(tGATT_HDL_LIST_ELEM *p);
|
||||
extern BOOLEAN gatt_is_last_attribute(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_start, tBT_UUID value);
|
||||
extern void gatt_update_last_pri_srv_info(tGATT_SRV_LIST_INFO *p_list);
|
||||
extern BOOLEAN gatt_add_a_srv_to_list(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_new);
|
||||
extern BOOLEAN gatt_remove_a_srv_from_list(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_remove);
|
||||
extern BOOLEAN gatt_add_an_item_to_list(tGATT_HDL_LIST_INFO *p_list, tGATT_HDL_LIST_ELEM *p_new);
|
||||
extern BOOLEAN gatt_remove_an_item_from_list(tGATT_HDL_LIST_INFO *p_list, tGATT_HDL_LIST_ELEM *p_remove);
|
||||
extern tGATTS_SRV_CHG *gatt_add_srv_chg_clt(tGATTS_SRV_CHG *p_srv_chg);
|
||||
|
||||
/* for background connection */
|
||||
extern BOOLEAN gatt_update_auto_connect_dev (tGATT_IF gatt_if, BOOLEAN add, BD_ADDR bd_addr, BOOLEAN is_initiator);
|
||||
extern BOOLEAN gatt_is_bg_dev_for_app(tGATT_BG_CONN_DEV *p_dev, tGATT_IF gatt_if);
|
||||
extern BOOLEAN gatt_remove_bg_dev_for_app(tGATT_IF gatt_if, BD_ADDR bd_addr);
|
||||
extern UINT8 gatt_get_num_apps_for_bg_dev(BD_ADDR bd_addr);
|
||||
extern BOOLEAN gatt_find_app_for_bg_dev(BD_ADDR bd_addr, tGATT_IF *p_gatt_if);
|
||||
extern tGATT_BG_CONN_DEV *gatt_find_bg_dev(BD_ADDR remote_bda);
|
||||
extern void gatt_deregister_bgdev_list(tGATT_IF gatt_if);
|
||||
extern void gatt_reset_bgdev_list(void);
|
||||
|
||||
/* server function */
|
||||
extern UINT8 gatt_sr_find_i_rcb_by_handle(UINT16 handle);
|
||||
extern UINT8 gatt_sr_find_i_rcb_by_app_id(tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, UINT16 svc_inst);
|
||||
extern UINT8 gatt_sr_alloc_rcb(tGATT_HDL_LIST_ELEM *p_list);
|
||||
extern tGATT_STATUS gatt_sr_process_app_rsp (tGATT_TCB *p_tcb, tGATT_IF gatt_if, UINT32 trans_id, UINT8 op_code, tGATT_STATUS status, tGATTS_RSP *p_msg);
|
||||
extern void gatt_server_handle_client_req (tGATT_TCB *p_tcb, UINT8 op_code,
|
||||
UINT16 len, UINT8 *p_data);
|
||||
extern void gatt_sr_send_req_callback(UINT16 conn_id, UINT32 trans_id,
|
||||
UINT8 op_code, tGATTS_DATA *p_req_data);
|
||||
extern UINT32 gatt_sr_enqueue_cmd (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 handle);
|
||||
extern BOOLEAN gatt_cancel_open(tGATT_IF gatt_if, BD_ADDR bda);
|
||||
|
||||
/* */
|
||||
|
||||
extern tGATT_REG *gatt_get_regcb (tGATT_IF gatt_if);
|
||||
extern BOOLEAN gatt_is_clcb_allocated (UINT16 conn_id);
|
||||
extern tGATT_CLCB *gatt_clcb_alloc (UINT16 conn_id);
|
||||
extern void gatt_clcb_dealloc (tGATT_CLCB *p_clcb);
|
||||
extern tGATT_CLCB *gatt_clcb_find_by_conn_id(UINT16 conn_id);
|
||||
extern tGATT_CLCB *gatt_clcb_find_by_idx(UINT16 cclcb_idx);
|
||||
|
||||
extern void gatt_sr_copy_prep_cnt_to_cback_cnt(tGATT_TCB *p_tcb );
|
||||
extern BOOLEAN gatt_sr_is_cback_cnt_zero(tGATT_TCB *p_tcb );
|
||||
extern BOOLEAN gatt_sr_is_prep_cnt_zero(tGATT_TCB *p_tcb );
|
||||
extern void gatt_sr_reset_cback_cnt(tGATT_TCB *p_tcb );
|
||||
extern void gatt_sr_reset_prep_cnt(tGATT_TCB *p_tcb );
|
||||
extern void gatt_sr_update_cback_cnt(tGATT_TCB *p_tcb, tGATT_IF gatt_if, BOOLEAN is_inc, BOOLEAN is_reset_first);
|
||||
extern void gatt_sr_update_prep_cnt(tGATT_TCB *p_tcb, tGATT_IF gatt_if, BOOLEAN is_inc, BOOLEAN is_reset_first);
|
||||
|
||||
extern BOOLEAN gatt_find_app_hold_link(tGATT_TCB *p_tcb, UINT8 start_idx, UINT8 *p_found_idx, tGATT_IF *p_gatt_if);
|
||||
extern BOOLEAN gatt_find_specific_app_in_hold_link(tGATT_TCB *p_tcb, tGATT_IF p_gatt_if);
|
||||
extern UINT8 gatt_num_apps_hold_link(tGATT_TCB *p_tcb);
|
||||
extern UINT8 gatt_num_clcb_by_bd_addr(BD_ADDR bda);
|
||||
extern tGATT_TCB *gatt_find_tcb_by_cid(UINT16 lcid);
|
||||
extern tGATT_TCB *gatt_allocate_tcb_by_bdaddr(BD_ADDR bda, tBT_TRANSPORT transport);
|
||||
extern tGATT_TCB *gatt_get_tcb_by_idx(UINT8 tcb_idx);
|
||||
extern tGATT_TCB *gatt_find_tcb_by_addr(BD_ADDR bda, tBT_TRANSPORT transport);
|
||||
extern BOOLEAN gatt_send_ble_burst_data (BD_ADDR remote_bda, BT_HDR *p_buf);
|
||||
extern void gatt_tcb_free( tGATT_TCB *p_tcb);
|
||||
|
||||
/* GATT client functions */
|
||||
extern void gatt_dequeue_sr_cmd (tGATT_TCB *p_tcb);
|
||||
extern UINT8 gatt_send_write_msg(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, UINT16 handle,
|
||||
UINT16 len, UINT16 offset, UINT8 *p_data);
|
||||
extern void gatt_cleanup_upon_disc(BD_ADDR bda, UINT16 reason, tBT_TRANSPORT transport);
|
||||
extern void gatt_end_operation(tGATT_CLCB *p_clcb, tGATT_STATUS status, void *p_data);
|
||||
|
||||
extern void gatt_act_discovery(tGATT_CLCB *p_clcb);
|
||||
extern void gatt_act_read(tGATT_CLCB *p_clcb, UINT16 offset);
|
||||
extern void gatt_act_write(tGATT_CLCB *p_clcb, UINT8 sec_act);
|
||||
extern UINT8 gatt_act_send_browse(tGATT_TCB *p_tcb, UINT16 index, UINT8 op, UINT16 s_handle, UINT16 e_handle,
|
||||
tBT_UUID uuid);
|
||||
extern tGATT_CLCB *gatt_cmd_dequeue(tGATT_TCB *p_tcb, UINT8 *p_opcode);
|
||||
extern BOOLEAN gatt_cmd_enq(tGATT_TCB *p_tcb, UINT16 clcb_idx, BOOLEAN to_send, UINT8 op_code, BT_HDR *p_buf);
|
||||
extern void gatt_client_handle_server_rsp (tGATT_TCB *p_tcb, UINT8 op_code,
|
||||
UINT16 len, UINT8 *p_data);
|
||||
extern void gatt_send_queue_write_cancel (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_EXEC_FLAG flag);
|
||||
|
||||
/* gatt_auth.c */
|
||||
extern BOOLEAN gatt_security_check_start(tGATT_CLCB *p_clcb);
|
||||
extern void gatt_verify_signature(tGATT_TCB *p_tcb, BT_HDR *p_buf);
|
||||
extern tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB *p_clcb );
|
||||
extern tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB *p_tcb);
|
||||
extern tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB *p_tcb);
|
||||
extern void gatt_set_sec_act(tGATT_TCB *p_tcb, tGATT_SEC_ACTION sec_act);
|
||||
|
||||
/* gatt_db.c */
|
||||
extern BOOLEAN gatts_init_service_db (tGATT_SVC_DB *p_db, tBT_UUID *p_service, BOOLEAN is_pri, UINT16 s_hdl, UINT16 num_handle);
|
||||
extern UINT16 gatts_add_included_service (tGATT_SVC_DB *p_db, UINT16 s_handle, UINT16 e_handle, tBT_UUID service);
|
||||
extern UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm,
|
||||
tGATT_CHAR_PROP property,
|
||||
tBT_UUID *p_char_uuid, tGATT_ATTR_VAL *attr_val,
|
||||
tGATTS_ATTR_CONTROL *control);
|
||||
extern UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm,
|
||||
tBT_UUID *p_dscp_uuid, tGATT_ATTR_VAL *attr_val,
|
||||
tGATTS_ATTR_CONTROL *control);
|
||||
|
||||
extern tGATT_STATUS gatts_set_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle,
|
||||
UINT16 length, UINT8 *value);
|
||||
extern tGATT_STATUS gatts_get_attr_value_internal(UINT16 attr_handle, UINT16 *length, UINT8 **value);
|
||||
extern tGATT_STATUS gatts_get_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle,
|
||||
UINT16 *length, UINT8 **value);
|
||||
extern BOOLEAN gatts_is_auto_response(UINT16 attr_handle);
|
||||
extern tGATT_STATUS gatts_db_read_attr_value_by_type (tGATT_TCB *p_tcb, tGATT_SVC_DB *p_db, UINT8 op_code, BT_HDR *p_rsp, UINT16 s_handle,
|
||||
UINT16 e_handle, tBT_UUID type, UINT16 *p_len, tGATT_SEC_FLAG sec_flag, UINT8 key_size, UINT32 trans_id, UINT16 *p_cur_handle);
|
||||
extern tGATT_STATUS gatts_read_attr_value_by_handle(tGATT_TCB *p_tcb, tGATT_SVC_DB *p_db, UINT8 op_code, UINT16 handle, UINT16 offset,
|
||||
UINT8 *p_value, UINT16 *p_len, UINT16 mtu, tGATT_SEC_FLAG sec_flag, UINT8 key_size, UINT32 trans_id);
|
||||
extern tGATT_STATUS gatts_write_attr_value_by_handle(tGATT_SVC_DB *p_db,
|
||||
UINT16 handle, UINT16 offset,
|
||||
UINT8 *p_value, UINT16 len);
|
||||
extern tGATT_STATUS gatts_write_attr_perm_check (tGATT_SVC_DB *p_db, UINT8 op_code, UINT16 handle, UINT16 offset, UINT8 *p_data,
|
||||
UINT16 len, tGATT_SEC_FLAG sec_flag, UINT8 key_size);
|
||||
extern tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB *p_db, BOOLEAN is_long, UINT16 handle, tGATT_SEC_FLAG sec_flag, UINT8 key_size);
|
||||
extern void gatts_update_srv_list_elem(UINT8 i_sreg, UINT16 handle, BOOLEAN is_primary);
|
||||
extern tBT_UUID *gatts_get_service_uuid (tGATT_SVC_DB *p_db);
|
||||
|
||||
extern BOOLEAN gatt_check_connection_state_by_tcb(tGATT_TCB *p_tcb);
|
||||
|
||||
extern void gatt_reset_bgdev_list(void);
|
||||
extern uint16_t gatt_get_local_mtu(void);
|
||||
extern void gatt_set_local_mtu(uint16_t mtu);
|
||||
|
||||
extern tGATT_STATUS gatts_calculate_datebase_hash(BT_OCTET16 hash);
|
||||
extern void gatts_show_local_database(void);
|
||||
|
||||
extern BOOLEAN gatt_sr_is_cl_change_aware(tGATT_TCB *p_tcb);
|
||||
extern void gatt_sr_init_cl_status(tGATT_TCB *p_tcb);
|
||||
extern void gatt_sr_update_cl_status(tGATT_TCB *tcb, BOOLEAN chg_aware);
|
||||
#endif
|
||||
Reference in New Issue
Block a user