mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
fix(ble/bluedroid): fix GATT server busy errors and sr_cmd handling
This commit is contained in:
@@ -73,6 +73,48 @@ tGATT_STATUS gatt_send_packet (tGATT_TCB *p_tcb, UINT8 *p_data, UINT16 len)
|
||||
return status;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_sr_next_trans_id
|
||||
**
|
||||
** Description Allocate the next transaction ID in [1, GATT_TRANS_ID_MAX - 1].
|
||||
** Zero is reserved for enqueue failure (sr_cmd busy).
|
||||
**
|
||||
*******************************************************************************/
|
||||
static UINT32 gatt_sr_next_trans_id(tGATT_TCB *p_tcb)
|
||||
{
|
||||
UINT32 trans_id = p_tcb->trans_id % GATT_TRANS_ID_MAX;
|
||||
|
||||
trans_id = (trans_id + 1) % GATT_TRANS_ID_MAX;
|
||||
if (trans_id == 0) {
|
||||
trans_id = 1;
|
||||
}
|
||||
p_tcb->trans_id = trans_id;
|
||||
return trans_id;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_sr_busy_error_code
|
||||
**
|
||||
** Description Pick an ATT error code for a request received while another
|
||||
** server procedure is pending. Common profile codes (0xFE) are
|
||||
** not valid for all request types per ATT Table 3.44.
|
||||
**
|
||||
*******************************************************************************/
|
||||
static UINT8 gatt_sr_busy_error_code(UINT8 op_code)
|
||||
{
|
||||
switch (op_code) {
|
||||
case GATT_REQ_FIND_TYPE_VALUE:
|
||||
return GATT_REQ_NOT_SUPPORTED;
|
||||
case GATT_REQ_FIND_INFO:
|
||||
/* ATT Table 3.44: only Invalid Handle (0x01) and Not Found (0x0A) are valid. */
|
||||
return GATT_NOT_FOUND;
|
||||
default:
|
||||
return GATT_PRC_IN_PROGRESS;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function gatt_sr_enqueue_cmd
|
||||
@@ -88,21 +130,20 @@ UINT32 gatt_sr_enqueue_cmd (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 handle)
|
||||
tGATT_SR_CMD *p_cmd = &p_tcb->sr_cmd;
|
||||
UINT32 trans_id = 0;
|
||||
|
||||
if ( (p_cmd->op_code == 0) ||
|
||||
(op_code == GATT_HANDLE_VALUE_CONF)) { /* no pending request */
|
||||
if (op_code == GATT_CMD_WRITE ||
|
||||
op_code == GATT_SIGN_CMD_WRITE ||
|
||||
op_code == GATT_REQ_MTU ||
|
||||
op_code == GATT_HANDLE_VALUE_CONF) {
|
||||
trans_id = ++p_tcb->trans_id;
|
||||
} else {
|
||||
p_cmd->trans_id = ++p_tcb->trans_id;
|
||||
p_cmd->op_code = op_code;
|
||||
p_cmd->handle = handle;
|
||||
p_cmd->status = GATT_NOT_FOUND;
|
||||
p_tcb->trans_id %= GATT_TRANS_ID_MAX;
|
||||
trans_id = p_cmd->trans_id;
|
||||
}
|
||||
/* No-tracking ops do not occupy sr_cmd and may arrive while a request is pending. */
|
||||
if (op_code == GATT_CMD_WRITE ||
|
||||
op_code == GATT_SIGN_CMD_WRITE ||
|
||||
op_code == GATT_REQ_MTU ||
|
||||
op_code == GATT_HANDLE_VALUE_CONF) {
|
||||
return gatt_sr_next_trans_id(p_tcb);
|
||||
}
|
||||
|
||||
if (p_cmd->op_code == 0) {
|
||||
p_cmd->trans_id = gatt_sr_next_trans_id(p_tcb);
|
||||
p_cmd->op_code = op_code;
|
||||
p_cmd->handle = handle;
|
||||
p_cmd->status = GATT_NOT_FOUND;
|
||||
trans_id = p_cmd->trans_id;
|
||||
}
|
||||
|
||||
return trans_id;
|
||||
@@ -564,6 +605,7 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U
|
||||
BOOLEAN sr_cmd_already_dequeued = FALSE;
|
||||
tGATT_PREPARE_WRITE_RECORD *prepare_record = NULL;
|
||||
tGATT_PREPARE_WRITE_QUEUE_DATA * queue_data = NULL;
|
||||
tGATTS_DATA sr_data = {0};
|
||||
|
||||
/* Fix: Validate minimum length (flags: 1 byte) */
|
||||
if (len < 1) {
|
||||
@@ -587,6 +629,7 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U
|
||||
|
||||
/* mask the flag */
|
||||
flag &= GATT_PREP_WRITE_EXEC;
|
||||
sr_data.exec_write = flag;
|
||||
|
||||
prepare_record = &(p_tcb->prepare_write_record);
|
||||
queue_num = fixed_queue_length(prepare_record->queue);
|
||||
@@ -663,7 +706,7 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U
|
||||
gatt_sr_send_req_callback(conn_id,
|
||||
trans_id,
|
||||
GATTS_REQ_TYPE_WRITE_EXEC,
|
||||
(tGATTS_DATA *)&flag);
|
||||
&sr_data);
|
||||
p_tcb->prep_cnt[i] = 0;
|
||||
}
|
||||
}
|
||||
@@ -745,7 +788,7 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U
|
||||
gatt_sr_send_req_callback(conn_id,
|
||||
trans_id,
|
||||
GATTS_REQ_TYPE_WRITE_EXEC,
|
||||
(tGATTS_DATA *)&flag);
|
||||
&sr_data);
|
||||
p_tcb->prep_cnt[i] = 0;
|
||||
}
|
||||
}
|
||||
@@ -773,6 +816,7 @@ void gatt_process_read_multi_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U
|
||||
tGATT_STATUS err = GATT_SUCCESS;
|
||||
UINT8 sec_flag, key_size;
|
||||
tGATTS_RSP *p_msg;
|
||||
BOOLEAN sr_cmd_enqueued = FALSE;
|
||||
|
||||
GATT_TRACE_DEBUG("gatt_process_read_multi_req" );
|
||||
p_tcb->sr_cmd.multi_req.num_handles = 0;
|
||||
@@ -831,6 +875,7 @@ void gatt_process_read_multi_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U
|
||||
|
||||
if (err == GATT_SUCCESS) {
|
||||
if ((trans_id = gatt_sr_enqueue_cmd (p_tcb, op_code, p_tcb->sr_cmd.multi_req.handles[0])) != 0) {
|
||||
sr_cmd_enqueued = TRUE;
|
||||
gatt_sr_reset_cback_cnt(p_tcb); /* read multiple use multi_rsp_q's count*/
|
||||
|
||||
for (ll = 0; ll < p_tcb->sr_cmd.multi_req.num_handles; ll ++) {
|
||||
@@ -854,12 +899,16 @@ void gatt_process_read_multi_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U
|
||||
|
||||
if (err == GATT_SUCCESS || err == GATT_STACK_RSP) {
|
||||
gatt_sr_process_app_rsp(p_tcb, gatt_cb.sr_reg[i_rcb].gatt_if , trans_id, op_code, GATT_SUCCESS, p_msg);
|
||||
} else if (err != GATT_PENDING && err != GATT_BUSY) {
|
||||
osi_free(p_msg);
|
||||
break;
|
||||
}
|
||||
/* either not using or done using the buffer, release it now */
|
||||
osi_free(p_msg);
|
||||
} else {
|
||||
err = GATT_NO_RESOURCES;
|
||||
gatt_dequeue_sr_cmd(p_tcb);
|
||||
sr_cmd_enqueued = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -869,7 +918,7 @@ void gatt_process_read_multi_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U
|
||||
}
|
||||
/* in theroy BUSY is not possible(should already been checked), protected check */
|
||||
if (err != GATT_SUCCESS && err != GATT_STACK_RSP && err != GATT_PENDING && err != GATT_BUSY) {
|
||||
gatt_send_error_rsp(p_tcb, err, op_code, handle, FALSE);
|
||||
gatt_send_error_rsp(p_tcb, err, op_code, handle, sr_cmd_enqueued);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -909,7 +958,7 @@ static tGATT_STATUS gatt_build_primary_service_rsp (BT_HDR *p_msg, tGATT_TCB *p_
|
||||
p_rcb->type == GATT_UUID_PRI_SERVICE) {
|
||||
if ((p_uuid = gatts_get_service_uuid (p_rcb->p_db)) != NULL) {
|
||||
if (op_code == GATT_REQ_READ_BY_GRP_TYPE) {
|
||||
handle_len = 4 + p_uuid->len;
|
||||
handle_len = 4 + gatt_get_uuid_stream_len(*p_uuid);
|
||||
}
|
||||
|
||||
/* get the length byte in the response */
|
||||
@@ -1189,11 +1238,15 @@ static void gatts_process_find_info(tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len,
|
||||
if (p_rcb->in_use &&
|
||||
!(p_rcb->s_hdl > e_hdl ||
|
||||
p_rcb->e_hdl < s_hdl)) {
|
||||
reason = gatt_build_find_info_rsp(p_rcb, p_msg, &buf_len, s_hdl, e_hdl);
|
||||
if (reason == GATT_NO_RESOURCES) {
|
||||
tGATT_STATUS build_status = gatt_build_find_info_rsp(p_rcb, p_msg, &buf_len, s_hdl, e_hdl);
|
||||
if (build_status == GATT_SUCCESS) {
|
||||
reason = GATT_SUCCESS;
|
||||
} else if (build_status == GATT_NO_RESOURCES) {
|
||||
reason = GATT_SUCCESS;
|
||||
break;
|
||||
}
|
||||
/* GATT_NOT_FOUND for this service: keep reason (do not discard
|
||||
* attributes already added from other services). */
|
||||
}
|
||||
p_srv = p_srv->p_next;
|
||||
}
|
||||
@@ -1230,6 +1283,7 @@ static void gatts_process_mtu_req (tGATT_TCB *p_tcb, UINT16 len, UINT8 *p_data)
|
||||
UINT8 *p = p_data, i;
|
||||
BT_HDR *p_buf;
|
||||
UINT16 conn_id;
|
||||
tGATTS_DATA sr_data = {0};
|
||||
|
||||
#if (BLE_EATT_INCLUDED == TRUE)
|
||||
/* Exchange MTU applies to Legacy ATT bearer only (Core Spec Vol 3 Part G 5.3). */
|
||||
@@ -1267,11 +1321,12 @@ static void gatts_process_mtu_req (tGATT_TCB *p_tcb, UINT16 len, UINT8 *p_data)
|
||||
/* Notify all registered application with new MTU size. Us a transaction ID */
|
||||
/* of 0, as no response is allowed from applications */
|
||||
|
||||
sr_data.mtu = p_tcb->payload_size;
|
||||
for (i = 0; i < GATT_MAX_APPS; i ++) {
|
||||
if (gatt_cb.cl_rcb[i].in_use ) {
|
||||
conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_cb.cl_rcb[i].gatt_if);
|
||||
gatt_sr_send_req_callback(conn_id, 0, GATTS_REQ_TYPE_MTU,
|
||||
(tGATTS_DATA *)&p_tcb->payload_size);
|
||||
&sr_data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1379,7 +1434,13 @@ void gatts_process_read_by_type_req(tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len,
|
||||
}
|
||||
p_srv = p_srv->p_next;
|
||||
}
|
||||
*p = (UINT8)p_msg->offset;
|
||||
/* Defensive: Read By Type response record length is a 1-octet field (<= 255). */
|
||||
if (p_msg->offset > UINT8_MAX) {
|
||||
GATT_TRACE_ERROR("%s: invalid ReadByType pair_len=%u (>255)", __func__, p_msg->offset);
|
||||
reason = GATT_INVALID_PDU;
|
||||
} else {
|
||||
*p = (UINT8)p_msg->offset;
|
||||
}
|
||||
p_msg->offset = L2CAP_MIN_OFFSET;
|
||||
}
|
||||
}
|
||||
@@ -1831,7 +1892,7 @@ void gatts_process_attribute_req (tGATT_TCB *p_tcb, UINT8 op_code,
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static void gatts_proc_srv_chg_ind_ack(tGATT_TCB *p_tcb )
|
||||
void gatts_proc_srv_chg_ind_ack(tGATT_TCB *p_tcb )
|
||||
{
|
||||
tGATTS_SRV_CHG_REQ req;
|
||||
tGATTS_SRV_CHG *p_buf = NULL;
|
||||
@@ -1904,6 +1965,10 @@ void gatts_process_value_conf(tGATT_TCB *p_tcb, UINT8 op_code)
|
||||
for (i = 0; i < GATT_MAX_SR_PROFILES; i ++, p_rcb ++) {
|
||||
if (p_rcb->in_use && p_rcb->s_hdl <= handle && p_rcb->e_hdl >= handle) {
|
||||
trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle);
|
||||
if (trans_id == 0) {
|
||||
GATT_TRACE_ERROR("%s: no trans_id for handle conf 0x%04x", __func__, handle);
|
||||
continue;
|
||||
}
|
||||
conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_rcb->gatt_if);
|
||||
tGATTS_DATA p_data = {0};
|
||||
p_data.handle = handle;
|
||||
@@ -1912,6 +1977,15 @@ void gatts_process_value_conf(tGATT_TCB *p_tcb, UINT8 op_code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Retry Service Changed if a previous attempt was deferred (GATT_BUSY). */
|
||||
{
|
||||
tGATTS_SRV_CHG *p_srv_chg_clt;
|
||||
|
||||
if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda)) != NULL) {
|
||||
gatt_chk_srv_chg(p_srv_chg_clt);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
GATT_TRACE_ERROR("unexpected handle value confirmation");
|
||||
}
|
||||
@@ -2012,10 +2086,14 @@ static BOOLEAN gatts_handle_db_out_of_sync(tGATT_TCB *p_tcb, UINT8 op_code,
|
||||
void gatt_server_handle_client_req (tGATT_TCB *p_tcb, UINT8 op_code,
|
||||
UINT16 len, UINT8 *p_data)
|
||||
{
|
||||
/* there is pending command, discard this one */
|
||||
if (!gatt_sr_cmd_empty(p_tcb) && op_code != GATT_HANDLE_VALUE_CONF) {
|
||||
GATT_TRACE_WARNING("%s discard command opcode=%02x", __func__, op_code);
|
||||
return;
|
||||
if (!gatt_sr_cmd_empty(p_tcb)) {
|
||||
if (op_code == GATT_CMD_WRITE || op_code == GATT_SIGN_CMD_WRITE) {
|
||||
/* ATT commands have no flow control and may arrive while a request is pending. */
|
||||
} else if (op_code != GATT_HANDLE_VALUE_CONF && op_code != GATT_REQ_MTU) {
|
||||
GATT_TRACE_WARNING("%s reject opcode=%02x, procedure in progress", __func__, op_code);
|
||||
gatt_send_error_rsp(p_tcb, gatt_sr_busy_error_code(op_code), op_code, 0, FALSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* the size of the message may not be bigger than the local max PDU size*/
|
||||
|
||||
Reference in New Issue
Block a user