fix(ble/bluedroid): fix GATT server lifecycle and callbacks

(cherry picked from commit 54a1e31916)

Co-authored-by: zhiweijian <zhiweijian@espressif.com>
This commit is contained in:
Zhi Wei Jian
2026-06-10 19:53:43 +08:00
parent 56f64635ec
commit bbea975df8
10 changed files with 445 additions and 130 deletions

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -384,7 +384,9 @@ esp_err_t esp_ble_gatts_set_attr_value(uint16_t attr_handle, uint16_t length, co
esp_gatt_status_t esp_ble_gatts_get_attr_value(uint16_t attr_handle, uint16_t *length, const uint8_t **value)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_GATT_WRONG_STATE;
}
if (length == NULL || value == NULL) {
return ESP_GATT_INVALID_PDU;
@@ -463,20 +465,44 @@ esp_err_t esp_ble_gatts_send_service_change_indication(esp_gatt_if_t gatts_if, e
static esp_err_t esp_ble_gatts_add_char_desc_param_check(esp_attr_value_t *char_val, esp_attr_control_t *control)
{
if ((control != NULL) && ((control->auto_rsp != ESP_GATT_AUTO_RSP) && (control->auto_rsp != ESP_GATT_RSP_BY_APP))){
LOG_ERROR("Error in %s, line=%d, control->auto_rsp should be set to ESP_GATT_AUTO_RSP or ESP_GATT_RSP_BY_APP\n",\
__func__, __LINE__);
return ESP_ERR_INVALID_ARG;
if ((control != NULL) &&
(control->auto_rsp != ESP_GATT_AUTO_RSP) &&
(control->auto_rsp != ESP_GATT_RSP_BY_APP)) {
return ESP_ERR_INVALID_ARG;
}
if ((control != NULL) && (control->auto_rsp == ESP_GATT_AUTO_RSP)){
if (char_val == NULL){
LOG_ERROR("Error in %s, line=%d, for stack respond attribute, char_val should not be NULL here\n",\
__func__, __LINE__);
/* Validate attribute value regardless of auto_rsp to avoid deep-copy waste and leaks. */
if (char_val != NULL) {
bool invalid = false;
if (char_val->attr_max_len > ESP_GATT_MAX_ATTR_LEN) {
invalid = true;
}
if (char_val->attr_len > ESP_GATT_MAX_ATTR_LEN) {
invalid = true;
}
/* Always require attr_len <= attr_max_len to avoid leaks and wasteful allocations. */
if (char_val->attr_len > char_val->attr_max_len) {
invalid = true;
}
if (invalid) {
LOG_ERROR("%s bad attr len=%u/%u lim=%u",
__func__,
(unsigned)char_val->attr_len,
(unsigned)char_val->attr_max_len,
(unsigned)ESP_GATT_MAX_ATTR_LEN);
return ESP_ERR_INVALID_ARG;
} else if (char_val->attr_max_len == 0){
LOG_ERROR("Error in %s, line=%d, for stack respond attribute, attribute max length should not be 0\n",\
__func__, __LINE__);
}
}
if ((control != NULL) && (control->auto_rsp == ESP_GATT_AUTO_RSP)) {
if (char_val == NULL) {
return ESP_ERR_INVALID_ARG;
}
/* For stack auto response, attr_max_len must be non-zero. */
if (char_val->attr_max_len == 0) {
return ESP_ERR_INVALID_ARG;
}
}

View File

@@ -548,9 +548,11 @@ esp_err_t esp_ble_gatts_set_attr_value(uint16_t attr_handle, uint16_t length, co
* 2. `attr_handle` must be greater than 0.
*
* @return
* - ESP_OK: Success
* - ESP_GATT_OK: Success
* - ESP_GATT_WRONG_STATE: Bluedroid stack is not enabled
* - ESP_GATT_INVALID_PDU: NULL pointer to `length` or `value`
* - ESP_GATT_INVALID_HANDLE: Invalid `attr_handle`
* - ESP_FAIL: Failure due to other reasons
* - Other `esp_gatt_status_t` values: Failure due to other reasons
*/
esp_gatt_status_t esp_ble_gatts_get_attr_value(uint16_t attr_handle, uint16_t *length, const uint8_t **value);

View File

@@ -173,11 +173,12 @@ void bta_gatts_api_disable(tBTA_GATTS_CB *p_cb)
void bta_gatts_register(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg)
{
tBTA_GATTS_INT_START_IF *p_buf;
tBTA_GATTS cb_data;
tBTA_GATTS cb_data = {0};
tBTA_GATT_STATUS status = BTA_GATT_OK;
UINT8 i, first_unuse = 0xff;
memset(&cb_data, 0, sizeof(tBTA_GATTS));
cb_data.reg_oper.server_if = BTA_GATTS_INVALID_IF;
memcpy(&cb_data.reg_oper.uuid, &p_msg->api_reg.app_uuid, sizeof(tBT_UUID));
if (p_cb->enabled == FALSE) {
bta_gatts_enable(p_cb);
@@ -188,6 +189,7 @@ void bta_gatts_register(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg)
if (gatt_uuid_compare(p_cb->rcb[i].app_uuid, p_msg->api_reg.app_uuid)) {
APPL_TRACE_ERROR("application already registered.\n");
status = BTA_GATT_DUP_REG;
cb_data.reg_oper.server_if = p_cb->rcb[i].gatt_if;
break;
}
}
@@ -201,8 +203,6 @@ void bta_gatts_register(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg)
}
}
cb_data.reg_oper.server_if = BTA_GATTS_INVALID_IF;
memcpy(&cb_data.reg_oper.uuid, &p_msg->api_reg.app_uuid, sizeof(tBT_UUID));
if (first_unuse != 0xff) {
APPL_TRACE_VERBOSE("register application first_unuse rcb_idx = %d", first_unuse);
@@ -274,7 +274,8 @@ void bta_gatts_deregister(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg)
tBTA_GATT_STATUS status = BTA_GATT_ERROR;
tBTA_GATTS_CBACK *p_cback = NULL;
UINT8 i;
tBTA_GATTS cb_data;
UINT8 j;
tBTA_GATTS cb_data = {0};
cb_data.reg_oper.server_if = p_msg->api_dereg.server_if;
cb_data.reg_oper.status = status;
@@ -287,6 +288,12 @@ void bta_gatts_deregister(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg)
/* deregister the app */
GATT_Deregister(p_cb->rcb[i].gatt_if);
for (j = 0; j < BTA_GATTS_MAX_SRVC_NUM; j ++) {
if (p_cb->srvc_cb[j].in_use && p_cb->srvc_cb[j].rcb_idx == i) {
memset(&p_cb->srvc_cb[j], 0, sizeof(tBTA_GATTS_SRVC_CB));
}
}
/* reset cb */
memset(&p_cb->rcb[i], 0, sizeof(tBTA_GATTS_RCB));
cb_data.reg_oper.status = status;
@@ -323,6 +330,16 @@ void bta_gatts_create_srvc(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg)
APPL_TRACE_DEBUG("create service rcb_idx = %d", rcb_idx);
if (rcb_idx != BTA_GATTS_INVALID_APP) {
/*
* Populate callback data with the request context early so the app can
* identify which create-service request failed even if resource
* allocation fails before we call into GATT.
*/
cb_data.create.server_if = p_cb->rcb[rcb_idx].gatt_if;
cb_data.create.is_primary = p_msg->api_create_svc.is_pri;
memcpy(&cb_data.create.uuid, &p_msg->api_create_svc.service_uuid, sizeof(tBT_UUID));
cb_data.create.svc_instance = p_msg->api_create_svc.inst;
if ((srvc_idx = bta_gatts_alloc_srvc_cb(p_cb, rcb_idx)) != BTA_GATTS_INVALID_APP) {
/* create the service now */
service_id = GATTS_CreateService (p_cb->rcb[rcb_idx].gatt_if,
@@ -345,7 +362,7 @@ void bta_gatts_create_srvc(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg)
cb_data.create.server_if = p_cb->rcb[rcb_idx].gatt_if;
} else {
cb_data.status = BTA_GATT_ERROR;
cb_data.create.server_if = p_cb->rcb[rcb_idx].gatt_if;
memset(&p_cb->srvc_cb[srvc_idx], 0, sizeof(tBTA_GATTS_SRVC_CB));
APPL_TRACE_ERROR("service creation failed.");
}
@@ -374,7 +391,7 @@ void bta_gatts_add_include_srvc(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA *
{
tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx];
UINT16 attr_id = 0;
tBTA_GATTS cb_data;
tBTA_GATTS cb_data = {0};
attr_id = GATTS_AddIncludeService(p_msg->api_add_incl_srvc.hdr.layer_specific,
p_msg->api_add_incl_srvc.included_service_id);
@@ -406,7 +423,7 @@ void bta_gatts_add_char(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA *p_msg)
{
tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx];
UINT16 attr_id = 0;
tBTA_GATTS cb_data;
tBTA_GATTS cb_data = {0};
tGATT_ATTR_VAL *p_attr_val = NULL;
tGATTS_ATTR_CONTROL *p_control = NULL;
@@ -436,8 +453,9 @@ void bta_gatts_add_char(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA *p_msg)
} else {
cb_data.add_result.status = BTA_GATT_ERROR;
}
if((p_attr_val != NULL) && (p_attr_val->attr_val != NULL)){
osi_free(p_attr_val->attr_val);
if (p_msg->api_add_char.attr_val.attr_val != NULL) {
osi_free(p_msg->api_add_char.attr_val.attr_val);
p_msg->api_add_char.attr_val.attr_val = NULL;
}
if (p_rcb->p_cback) {
@@ -458,7 +476,7 @@ void bta_gatts_add_char_descr(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA *p_
{
tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx];
UINT16 attr_id = 0;
tBTA_GATTS cb_data;
tBTA_GATTS cb_data = {0};
tGATT_ATTR_VAL *p_attr_val = NULL;
tGATTS_ATTR_CONTROL *p_control = NULL;
@@ -486,8 +504,9 @@ void bta_gatts_add_char_descr(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA *p_
} else {
cb_data.add_result.status = BTA_GATT_ERROR;
}
if((p_attr_val != NULL) && (p_attr_val->attr_val != NULL)){
osi_free(p_attr_val->attr_val);
if (p_msg->api_add_char_descr.attr_val.attr_val != NULL) {
osi_free(p_msg->api_add_char_descr.attr_val.attr_val);
p_msg->api_add_char_descr.attr_val.attr_val = NULL;
}
if (p_rcb->p_cback) {
@@ -509,7 +528,7 @@ void bta_gatts_set_attr_value(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA *p_
{
tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx];
UINT16 service_id = p_srvc_cb->service_id;
tBTA_GATTS cb_data;
tBTA_GATTS cb_data = {0};
tBTA_GATT_STATUS gatts_status;
gatts_status = GATTS_SetAttributeValue(p_msg->api_set_val.hdr.layer_specific,
p_msg->api_set_val.length,
@@ -543,11 +562,27 @@ void bta_gatts_set_attr_value(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA *p_
tGATT_STATUS bta_gatts_get_attr_value(UINT16 attr_handle, UINT16 *length, UINT8 **value)
{
if (GATTS_GetAttributeValueInternal(attr_handle, length, value) == 0) {
return 0;
tGATT_STATUS status = GATTS_GetAttributeValueInternal(attr_handle, length, value);
if (status == GATT_SUCCESS) {
return GATT_SUCCESS;
}
return GATTS_GetAttributeValue(attr_handle, length, value);
/*
* Only fall back to the service database when the handle is not part of
* internal GAP/GATT services. For any other internal read error, preserve
* the original status to avoid masking failures as "success with len=0".
*/
if (status != GATT_NOT_FOUND) {
if (length) {
*length = 0;
}
if (value) {
*value = NULL;
}
return status;
}
return GATTS_GetAttributeValue(attr_handle, length, value);
}
/*******************************************************************************
@@ -562,10 +597,10 @@ tGATT_STATUS bta_gatts_get_attr_value(UINT16 attr_handle, UINT16 *length, UINT8
void bta_gatts_delete_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA *p_msg)
{
tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx];
tBTA_GATTS cb_data;
tBTA_GATTS cb_data = {0};
cb_data.srvc_oper.server_if = p_rcb->gatt_if;
cb_data.srvc_oper.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific;
cb_data.srvc_oper.service_id = p_srvc_cb->service_id;
if (GATTS_DeleteService(p_rcb->gatt_if,
&p_srvc_cb->service_uuid,
@@ -574,6 +609,12 @@ void bta_gatts_delete_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA *p_
memset(p_srvc_cb, 0, sizeof(tBTA_GATTS_SRVC_CB));
} else {
cb_data.srvc_oper.status = BTA_GATT_ERROR;
/*
* GATTS_DeleteService() only fails when the service (or app registration)
* cannot be found in the stack. Keeping srvc_cb "in_use" would permanently
* leak a slot and eventually prevent creating new services.
*/
memset(p_srvc_cb, 0, sizeof(tBTA_GATTS_SRVC_CB));
}
if (p_rcb->p_cback) {
@@ -593,10 +634,10 @@ void bta_gatts_delete_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA *p_
void bta_gatts_start_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA *p_msg)
{
tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx];
tBTA_GATTS cb_data;
tBTA_GATTS cb_data = {0};
cb_data.srvc_oper.server_if = p_rcb->gatt_if;
cb_data.srvc_oper.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific;
cb_data.srvc_oper.service_id = p_srvc_cb->service_id;
if (GATTS_StartService(p_rcb->gatt_if,
p_srvc_cb->service_id,
@@ -624,7 +665,7 @@ void bta_gatts_start_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA *p_m
void bta_gatts_stop_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA *p_msg)
{
tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx];
tBTA_GATTS cb_data;
tBTA_GATTS cb_data = {0};
UNUSED(p_msg);
GATTS_StopService(p_srvc_cb->service_id);
@@ -651,14 +692,65 @@ void bta_gatts_send_rsp (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg)
{
UNUSED(p_cb);
if (GATTS_SendRsp (p_msg->api_rsp.hdr.layer_specific,
p_msg->api_rsp.trans_id,
p_msg->api_rsp.status,
(tGATTS_RSP *)p_msg->api_rsp.p_rsp) != GATT_SUCCESS) {
APPL_TRACE_ERROR("Sending response failed\n");
tGATT_STATUS ret = GATTS_SendRsp(p_msg->api_rsp.hdr.layer_specific,
p_msg->api_rsp.trans_id,
p_msg->api_rsp.status,
(tGATTS_RSP *)p_msg->api_rsp.p_rsp);
if (ret == GATT_CONGESTED) {
APPL_TRACE_WARNING("%s: rsp ok but congested", __func__);
} else if (ret != GATT_SUCCESS) {
APPL_TRACE_ERROR("%s: send rsp fail 0x%02x", __func__, ret);
}
}
/*******************************************************************************
**
** Function bta_gatts_send_conf_evt_to_app
**
** Description Build a BTA_GATTS_CONF_EVT and dispatch it to the application
** via the supplied RCB callback. The RCB callback is
** btc_gatts_inter_cb (registered by BTA_GATTS_AppRegister), which
** internally posts to the BTC task via btc_transfer_context, so
** delivery is asynchronous w.r.t. the BTA task.
**
** If |value| is non-NULL and |value_len| > 0, the buffer is
** duplicated for the duration of the callback and freed before
** this helper returns. On allocation failure the callback is
** still dispatched with value=NULL/data_len=0 so the application
** does not stall waiting for CONF_EVT.
**
** Returns void
**
*******************************************************************************/
static void bta_gatts_send_conf_evt_to_app(tBTA_GATTS_RCB *p_rcb,
UINT16 conn_id, UINT16 handle,
tBTA_GATT_STATUS status,
const UINT8 *value, UINT16 value_len)
{
if (p_rcb == NULL || p_rcb->p_cback == NULL) {
return;
}
tBTA_GATTS cb_data = {0};
cb_data.req_data.status = status;
cb_data.req_data.conn_id = conn_id;
cb_data.req_data.handle = handle;
cb_data.req_data.value = NULL;
cb_data.req_data.data_len = 0;
if (value != NULL && value_len > 0) {
cb_data.req_data.value = (uint8_t *)osi_malloc(value_len);
if (cb_data.req_data.value != NULL) {
memcpy(cb_data.req_data.value, value, value_len);
cb_data.req_data.data_len = value_len;
} else {
APPL_TRACE_ERROR("%s, malloc(%u) failed", __func__, (unsigned)value_len);
}
}
(*p_rcb->p_cback)(BTA_GATTS_CONF_EVT, &cb_data);
if (cb_data.req_data.value != NULL) {
osi_free(cb_data.req_data.value);
}
}
/*******************************************************************************
**
** Function bta_gatts_indicate_handle
@@ -672,71 +764,108 @@ void bta_gatts_indicate_handle (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg)
{
tBTA_GATTS_SRVC_CB *p_srvc_cb;
tBTA_GATTS_RCB *p_rcb = NULL;
tBTA_GATTS_RCB *p_srvc_rcb = NULL;
tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER;
tGATT_IF gatt_if;
BD_ADDR remote_bda;
tBTA_TRANSPORT transport;
tBTA_GATTS cb_data;
p_srvc_cb = bta_gatts_find_srvc_cb_by_attr_id (p_cb, p_msg->api_indicate.attr_id);
if (p_srvc_cb ) {
p_srvc_rcb = &p_cb->rcb[p_srvc_cb->rcb_idx];
if (GATT_GetConnectionInfor(p_msg->api_indicate.hdr.layer_specific,
&gatt_if, remote_bda, &transport)) {
p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if);
if (p_msg->api_indicate.need_confirm) {
status = GATTS_HandleValueIndication (p_msg->api_indicate.hdr.layer_specific,
p_msg->api_indicate.attr_id,
p_msg->api_indicate.len,
p_msg->api_indicate.value);
if (p_rcb != p_srvc_rcb) {
if (p_rcb == NULL) {
APPL_TRACE_ERROR("%s: no RCB for gatt_if %d", __func__, gatt_if);
} else {
APPL_TRACE_ERROR("%s: if mismatch svc owner", __func__);
}
if (!p_msg->api_indicate.need_confirm) {
l2ble_update_att_acl_pkt_num(L2CA_DECREASE_BTU_NUM, NULL);
}
status = BTA_GATT_ILLEGAL_PARAMETER;
} else {
l2ble_update_att_acl_pkt_num(L2CA_DECREASE_BTU_NUM, NULL);
status = GATTS_HandleValueNotification (p_msg->api_indicate.hdr.layer_specific,
p_msg->api_indicate.attr_id,
p_msg->api_indicate.len,
p_msg->api_indicate.value);
}
if (p_msg->api_indicate.need_confirm) {
status = GATTS_HandleValueIndication (p_msg->api_indicate.hdr.layer_specific,
p_msg->api_indicate.attr_id,
p_msg->api_indicate.len,
p_msg->api_indicate.value);
} else {
l2ble_update_att_acl_pkt_num(L2CA_DECREASE_BTU_NUM, NULL);
status = GATTS_HandleValueNotification (p_msg->api_indicate.hdr.layer_specific,
p_msg->api_indicate.attr_id,
p_msg->api_indicate.len,
p_msg->api_indicate.value);
}
#if (CLASSIC_BT_INCLUDED == TRUE)
/* if over BR_EDR, inform PM for mode change */
if (transport == BTA_TRANSPORT_BR_EDR) {
bta_sys_busy(BTA_ID_GATTS, BTA_ALL_APP_ID, remote_bda);
bta_sys_idle(BTA_ID_GATTS, BTA_ALL_APP_ID, remote_bda);
}
/* if over BR_EDR, inform PM for mode change */
if (transport == BTA_TRANSPORT_BR_EDR) {
bta_sys_busy(BTA_ID_GATTS, BTA_ALL_APP_ID, remote_bda);
bta_sys_idle(BTA_ID_GATTS, BTA_ALL_APP_ID, remote_bda);
}
#endif // #if (CLASSIC_BT_INCLUDED == TRUE)
}
} else {
APPL_TRACE_ERROR("Unknown connection ID: %d fail sending notification",
p_msg->api_indicate.hdr.layer_specific);
if (!p_msg->api_indicate.need_confirm) {
l2ble_update_att_acl_pkt_num(L2CA_DECREASE_BTU_NUM, NULL);
}
}
if ((status != GATT_SUCCESS || !p_msg->api_indicate.need_confirm) &&
p_rcb && p_cb->rcb[p_srvc_cb->rcb_idx].p_cback) {
cb_data.req_data.status = status;
cb_data.req_data.conn_id = p_msg->api_indicate.hdr.layer_specific;
cb_data.req_data.value = NULL;
cb_data.req_data.data_len = 0;
cb_data.req_data.handle = p_msg->api_indicate.attr_id;
if (p_msg->api_indicate.len > 0) {
cb_data.req_data.value = (uint8_t *) osi_malloc(p_msg->api_indicate.len);
if (cb_data.req_data.value != NULL) {
memset(cb_data.req_data.value, 0, p_msg->api_indicate.len);
cb_data.req_data.data_len = p_msg->api_indicate.len;
memcpy(cb_data.req_data.value, p_msg->api_indicate.value, p_msg->api_indicate.len);
} else {
APPL_TRACE_ERROR("%s, malloc failed", __func__);
}
}
(*p_rcb->p_cback)(BTA_GATTS_CONF_EVT, &cb_data);
if (cb_data.req_data.value != NULL) {
osi_free(cb_data.req_data.value);
cb_data.req_data.value = NULL;
}
if (status != GATT_SUCCESS || !p_msg->api_indicate.need_confirm) {
/* BTA_GATTS_CONF_EVT must be delivered to the application that
* initiated the indicate/notify, i.e. the owner of the connection
* (p_rcb resolved from conn_id's gatt_if). Fall back to the
* service-owning RCB only when the conn_id could not be resolved
* (link already torn down) so the application does not stall
* waiting for CONF_EVT. */
tBTA_GATTS_RCB *p_target_rcb = (p_rcb != NULL) ? p_rcb : p_srvc_rcb;
bta_gatts_send_conf_evt_to_app(p_target_rcb,
p_msg->api_indicate.hdr.layer_specific,
p_msg->api_indicate.attr_id,
status,
p_msg->api_indicate.value,
p_msg->api_indicate.len);
}
} else {
APPL_TRACE_ERROR("Not a registered service attribute ID: 0x%04x",
p_msg->api_indicate.attr_id);
if (!p_msg->api_indicate.need_confirm) {
/* Notifications increment the BTU counter in BTA_GATTS_HandleValueIndication();
* indications do not. So only balance the counter on the notification path. */
l2ble_update_att_acl_pkt_num(L2CA_DECREASE_BTU_NUM, NULL);
} else {
/* Indication path: the application is waiting for BTA_GATTS_CONF_EVT to know
* the request is finished. Make a best-effort attempt to deliver an error event
* so the app does not stall. Do NOT touch the BTU counter here, since indications
* never incremented it. */
if (GATT_GetConnectionInfor(p_msg->api_indicate.hdr.layer_specific,
&gatt_if, remote_bda, &transport)) {
p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if);
if (p_rcb && p_rcb->p_cback) {
bta_gatts_send_conf_evt_to_app(p_rcb,
p_msg->api_indicate.hdr.layer_specific,
p_msg->api_indicate.attr_id,
BTA_GATT_ILLEGAL_PARAMETER,
NULL, 0);
} else {
APPL_TRACE_ERROR("%s: no RCB if=%d, drop CONF", __func__, gatt_if);
}
} else {
/* conn_id is invalid (e.g. link already torn down). We have no gatt_if, so we
* cannot locate the owning RCB to deliver the callback. The application is
* expected to clean up pending indications on BTA_GATTS_DISCONNECT_EVT. */
APPL_TRACE_ERROR("%s: bad conn_id %d, drop CONF", __func__, p_msg->api_indicate.hdr.layer_specific);
}
}
}
}
@@ -916,13 +1045,11 @@ static void bta_gatts_send_request_cback (UINT16 conn_id,
UINT32 trans_id,
tGATTS_REQ_TYPE req_type, tGATTS_DATA *p_data)
{
tBTA_GATTS cb_data;
tBTA_GATTS cb_data = {0};
tBTA_GATTS_RCB *p_rcb;
tGATT_IF gatt_if;
tBTA_GATT_TRANSPORT transport;
memset(&cb_data, 0 , sizeof(tBTA_GATTS));
if (GATT_GetConnectionInfor(conn_id, &gatt_if, cb_data.req_data.remote_bda, &transport)) {
p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if);
@@ -974,10 +1101,10 @@ static void bta_gatts_conn_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id,
gatt_if, conn_id, connected, reason);
APPL_TRACE_DEBUG("bta_gatts_conn_cback bda :%02x-%02x-%02x-%02x-%02x-%02x ",
bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
/*
bt_bdaddr_t bdaddr;
bdcpy(bdaddr.address, bda);
/*
if (connected)
btif_debug_conn_state(bdaddr, BTIF_DEBUG_CONNECTED, GATT_CONN_UNKNOWN);
else
@@ -1033,7 +1160,7 @@ static void bta_gatts_conn_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id,
*******************************************************************************/
static void bta_gatts_cong_cback (UINT16 conn_id, BOOLEAN congested)
{
tBTA_GATTS cb_data;
tBTA_GATTS cb_data = {0};
cb_data.congest.conn_id = conn_id;
cb_data.congest.congested = congested;
btc_congest_callback(&cb_data);

View File

@@ -93,6 +93,7 @@ void BTA_GATTS_AppRegister(const tBT_UUID * p_app_uuid, tBTA_GATTS_CBACK *p_cbac
}
if ((p_buf = (tBTA_GATTS_API_REG *) osi_malloc(sizeof(tBTA_GATTS_API_REG))) != NULL) {
memset(p_buf, 0, sizeof(*p_buf));
p_buf->hdr.event = BTA_GATTS_API_REG_EVT;
if (p_app_uuid != NULL) {
@@ -237,16 +238,23 @@ void BTA_GATTS_AddCharacteristic (UINT16 service_id, const tBT_UUID * p_char_u
}
if(attr_val != NULL){
p_buf->attr_val.attr_len = attr_val->attr_len;
p_buf->attr_val.attr_max_len = attr_val->attr_max_len;
if(len != 0){
p_buf->attr_val.attr_val = (uint8_t *)osi_malloc(len);
if(p_buf->attr_val.attr_val != NULL){
memcpy(p_buf->attr_val.attr_val, attr_val->attr_val, len);
} else {
p_buf->attr_val.attr_len = 0;
p_buf->attr_val.attr_max_len = 0;
APPL_TRACE_ERROR("Allocate fail for %s\n", __func__);
if (attr_val->attr_max_len == 0) {
p_buf->attr_val.attr_len = 0;
if (len != 0) {
APPL_TRACE_WARNING("%s: max_len 0, drop len %u", __func__, len);
}
} else {
p_buf->attr_val.attr_len = attr_val->attr_len;
if(len != 0){
p_buf->attr_val.attr_val = (uint8_t *)osi_malloc(len);
if(p_buf->attr_val.attr_val != NULL){
memcpy(p_buf->attr_val.attr_val, attr_val->attr_val, len);
} else {
p_buf->attr_val.attr_len = 0;
p_buf->attr_val.attr_max_len = 0;
APPL_TRACE_ERROR("alloc fail %s", __func__);
}
}
}
}
@@ -299,19 +307,27 @@ void BTA_GATTS_AddCharDescriptor (UINT16 service_id,
}
if(attr_val != NULL){
p_buf->attr_val.attr_len = attr_val->attr_len;
p_buf->attr_val.attr_max_len = attr_val->attr_max_len;
value_len = attr_val->attr_len;
if (value_len != 0){
p_buf->attr_val.attr_val = (uint8_t*)osi_malloc(value_len);
if(p_buf->attr_val.attr_val != NULL){
memcpy(p_buf->attr_val.attr_val, attr_val->attr_val, value_len);
if (attr_val->attr_max_len == 0) {
p_buf->attr_val.attr_len = 0;
value_len = attr_val->attr_len;
if (value_len != 0) {
APPL_TRACE_WARNING("%s: max_len 0, drop len %u", __func__, value_len);
}
else{
p_buf->attr_val.attr_len = 0;
p_buf->attr_val.attr_max_len = 0;
APPL_TRACE_ERROR("Allocate fail for %s\n", __func__);
} else {
p_buf->attr_val.attr_len = attr_val->attr_len;
value_len = attr_val->attr_len;
if (value_len != 0){
p_buf->attr_val.attr_val = (uint8_t*)osi_malloc(value_len);
if(p_buf->attr_val.attr_val != NULL){
memcpy(p_buf->attr_val.attr_val, attr_val->attr_val, value_len);
}
else{
p_buf->attr_val.attr_len = 0;
p_buf->attr_val.attr_max_len = 0;
APPL_TRACE_ERROR("alloc fail %s", __func__);
}
}
}
}
@@ -501,8 +517,10 @@ void BTA_SetAttributeValue(UINT16 attr_handle, UINT16 length, UINT8 *value)
memset(p_buf, 0, len);
p_buf->hdr.event = BTA_GATTS_API_SET_ATTR_VAL_EVT;
p_buf->hdr.layer_specific = attr_handle;
p_buf->length = length;
if(value != NULL){
if (value == NULL) {
p_buf->length = 0;
} else {
p_buf->length = length;
if((p_buf->value = (UINT8 *)osi_malloc(length)) != NULL){
memcpy(p_buf->value, value, length);
} else {

View File

@@ -132,6 +132,16 @@ BOOLEAN bta_gatts_hdl_event(BT_HDR *p_msg)
if (p_srvc_cb != NULL) {
bta_gatts_srvc_build_act[p_msg->event - BTA_GATTS_API_ADD_INCL_SRVC_EVT](p_srvc_cb, (tBTA_GATTS_DATA *) p_msg);
} else {
tBTA_GATTS_DATA *p_data = (tBTA_GATTS_DATA *)p_msg;
if (p_msg->event == BTA_GATTS_API_ADD_CHAR_EVT &&
p_data->api_add_char.attr_val.attr_val != NULL) {
osi_free(p_data->api_add_char.attr_val.attr_val);
p_data->api_add_char.attr_val.attr_val = NULL;
} else if (p_msg->event == BTA_GATTS_API_ADD_DESCR_EVT &&
p_data->api_add_char_descr.attr_val.attr_val != NULL) {
osi_free(p_data->api_add_char_descr.attr_val.attr_val);
p_data->api_add_char_descr.attr_val.attr_val = NULL;
}
APPL_TRACE_ERROR("service not created\n");
}
break;

View File

@@ -676,10 +676,17 @@ typedef union {
add char : BTA_GATTS_ADD_CHAR_EVT
add char descriptor: BTA_GATTS_ADD_CHAR_DESCR_EVT */
tBAT_GATTS_ATTR_VAL_RESULT attr_val;
tBTA_GATTS_REQ req_data;
tBTA_GATTS_REQ req_data; /* BTA_GATTS_READ_EVT, BTA_GATTS_WRITE_EVT,
BTA_GATTS_EXEC_WRITE_EVT, BTA_GATTS_MTU_EVT,
BTA_GATTS_CONF_EVT (handle/value/data_len
are carried here, not in `confirm`) */
tBTA_GATTS_CONN conn; /* BTA_GATTS_CONN_EVT */
tBTA_GATTS_CONGEST congest; /* BTA_GATTS_CONGEST_EVT callback data */
tBTA_GATTS_CONF confirm; /* BTA_GATTS_CONF_EVT callback data */
tBTA_GATTS_CONF confirm; /* Deprecated: retained for source/ABI compatibility
only. BTA_GATTS_CONF_EVT actually uses `req_data`
because handle/value/data_len are required by the
public API. Do NOT add new producers/consumers
that read or write this member. */
tBTA_GATTS_CLOSE close; /* BTA_GATTS_CLOSE_EVT callback data */
tBTA_GATTS_OPEN open; /* BTA_GATTS_OPEN_EVT callback data */
tBTA_GATTS_CANCEL_OPEN cancel_open; /* tBTA_GATTS_CANCEL_OPEN callback data */

View File

@@ -244,7 +244,7 @@ static void btc_gatts_act_create_attr_tab(esp_gatts_attr_db_t *gatts_attr_db,
{
uint16_t uuid = 0;
future_t *future_p;
esp_ble_gatts_cb_param_t param;
esp_ble_gatts_cb_param_t param = {0};
param.add_attr_tab.status = ESP_GATT_OK;
param.add_attr_tab.num_handle = max_nb_attr;
@@ -509,11 +509,43 @@ static esp_gatt_status_t btc_gatts_check_valid_attr_tab(esp_gatts_attr_db_t *gat
uint16_t uuid = 0;
for(int i = 0; i < max_nb_attr; i++) {
if(gatts_attr_db[i].att_desc.uuid_length != ESP_UUID_LEN_16) {
const esp_attr_desc_t *desc = &gatts_attr_db[i].att_desc;
/* Reject absurd attribute sizes regardless of row type. Mirrors the per-call
* guard in esp_ble_gatts_add_char_desc_param_check() so that the attribute
* table API enforces the same upper bound. */
if (desc->max_length > ESP_GATT_MAX_ATTR_LEN ||
desc->length > ESP_GATT_MAX_ATTR_LEN) {
BTC_TRACE_ERROR("%s attr[%d] len %u/max %u>%u",
__func__, i,
(unsigned)desc->length,
(unsigned)desc->max_length,
(unsigned)ESP_GATT_MAX_ATTR_LEN);
return ESP_GATT_INVALID_ATTR_LEN;
}
/* When max_length is non-zero the row carries a stack-stored attribute
* value: gatts_add_char_descr()/gatts_add_characteristic() will allocate
* max_length bytes and memcpy length bytes into it. Reject length > max_length
* here so the table API matches esp_ble_gatts_add_char_desc_param_check(),
* fails fast with a clear error to the app, and also avoids the BTA-layer
* out-of-bounds read in BTA_GATTS_AddCharDescriptor() when the caller's
* source buffer is sized to max_length. Rows with max_length == 0 carry
* declarations (service UUID, char property byte, include-service descriptor)
* whose length is unrelated to max_length, so they are skipped. */
if (desc->max_length != 0 && desc->length > desc->max_length) {
BTC_TRACE_ERROR("%s attr[%d] len %u>max %u",
__func__, i,
(unsigned)desc->length,
(unsigned)desc->max_length);
return ESP_GATT_INVALID_ATTR_LEN;
}
if(desc->uuid_length != ESP_UUID_LEN_16) {
continue;
}
uuid = (gatts_attr_db[i].att_desc.uuid_p[1] << 8) + (gatts_attr_db[i].att_desc.uuid_p[0]);
uuid = (desc->uuid_p[1] << 8) + (desc->uuid_p[0]);
switch(uuid) {
case ESP_GATT_UUID_PRI_SERVICE:
case ESP_GATT_UUID_SEC_SERVICE:
@@ -594,9 +626,56 @@ esp_gatt_status_t btc_gatts_show_local_database(void)
return ESP_GATT_OK;
}
/* BTA passes a pointer to the active tBTA_GATTS union member (often a small stack
* object). Only copy that member's size — sizeof(tBTA_GATTS) would read past it. */
static int btc_gatts_cb_event_param_len(tBTA_GATTS_EVT event)
{
switch (event) {
case BTA_GATTS_REG_EVT:
case BTA_GATTS_DEREG_EVT:
return (int)sizeof(tBTA_GATTS_REG_OPER);
case BTA_GATTS_READ_EVT:
case BTA_GATTS_WRITE_EVT:
case BTA_GATTS_EXEC_WRITE_EVT:
case BTA_GATTS_MTU_EVT:
case BTA_GATTS_CONF_EVT:
return (int)sizeof(tBTA_GATTS_REQ);
case BTA_GATTS_CREATE_EVT:
return (int)sizeof(tBTA_GATTS_CREATE);
case BTA_GATTS_ADD_INCL_SRVC_EVT:
case BTA_GATTS_ADD_CHAR_EVT:
case BTA_GATTS_ADD_CHAR_DESCR_EVT:
return (int)sizeof(tBTA_GATTS_ADD_RESULT);
case BTA_GATTS_DELELTE_EVT:
case BTA_GATTS_START_EVT:
case BTA_GATTS_STOP_EVT:
return (int)sizeof(tBTA_GATTS_SRVC_OPER);
case BTA_GATTS_SET_ATTR_VAL_EVT:
return (int)sizeof(tBAT_GATTS_ATTR_VAL_RESULT);
case BTA_GATTS_CONNECT_EVT:
case BTA_GATTS_DISCONNECT_EVT:
return (int)sizeof(tBTA_GATTS_CONN);
case BTA_GATTS_OPEN_EVT:
return (int)sizeof(tBTA_GATTS_OPEN);
case BTA_GATTS_CANCEL_OPEN_EVT:
return (int)sizeof(tBTA_GATTS_CANCEL_OPEN);
case BTA_GATTS_CLOSE_EVT:
return (int)sizeof(tBTA_GATTS_CLOSE);
case BTA_GATTS_LISTEN_EVT:
return (int)sizeof(tBTA_GATT_STATUS);
case BTA_GATTS_CONGEST_EVT:
return (int)sizeof(tBTA_GATTS_CONGEST);
case BTA_GATTS_SEND_SERVICE_CHANGE_EVT:
return (int)sizeof(tBTA_GATTS_SERVICE_CHANGE);
default:
return (int)sizeof(tBTA_GATTS);
}
}
static void btc_gatts_cb_param_copy_req(btc_msg_t *msg, void *p_dest, void *p_src)
{
uint16_t event = msg->act;
int copy_len = btc_gatts_cb_event_param_len((tBTA_GATTS_EVT)event);
tBTA_GATTS *p_dest_data = (tBTA_GATTS *) p_dest;
tBTA_GATTS *p_src_data = (tBTA_GATTS *) p_src;
@@ -605,8 +684,7 @@ static void btc_gatts_cb_param_copy_req(btc_msg_t *msg, void *p_dest, void *p_sr
return;
}
// Copy basic structure first
memcpy(p_dest_data, p_src_data, sizeof(tBTA_GATTS));
memcpy(p_dest_data, p_src_data, (size_t)copy_len);
// Allocate buffer for request data if necessary
switch (event) {
@@ -622,6 +700,21 @@ static void btc_gatts_cb_param_copy_req(btc_msg_t *msg, void *p_dest, void *p_sr
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
}
break;
case BTA_GATTS_CONF_EVT:
/* bta_gatts_indicate_handle frees req_data.value after returning from this
* callback; duplicate the buffer so the queued BTC handler does not UAF. */
if (p_src_data->req_data.value != NULL && p_src_data->req_data.data_len > 0) {
p_dest_data->req_data.value = (uint8_t *)osi_malloc(p_src_data->req_data.data_len);
if (p_dest_data->req_data.value != NULL) {
memcpy(p_dest_data->req_data.value, p_src_data->req_data.value,
p_src_data->req_data.data_len);
} else {
BTC_TRACE_ERROR("%s CONF_EVT no mem", __func__);
p_dest_data->req_data.value = NULL;
p_dest_data->req_data.data_len = 0;
}
}
break;
default:
break;
@@ -643,6 +736,10 @@ static void btc_gatts_cb_param_copy_free(btc_msg_t *msg)
}
break;
case BTA_GATTS_CONF_EVT:
if (p_data && p_data->req_data.value) {
osi_free(p_data->req_data.value);
p_data->req_data.value = NULL;
}
break;
default:
break;
@@ -709,7 +806,7 @@ static void btc_gatts_inter_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
future_ready(btc_creat_tab_env.complete_future, result);
return;
}
status = btc_transfer_context(&msg, p_data, sizeof(tBTA_GATTS),
status = btc_transfer_context(&msg, p_data, btc_gatts_cb_event_param_len(event),
btc_gatts_cb_param_copy_req, btc_gatts_cb_param_copy_free);
if (status != BT_STATUS_SUCCESS) {
@@ -786,7 +883,7 @@ void btc_gatts_call_handler(btc_msg_t *msg)
arg->send_ind.value_len, arg->send_ind.value, arg->send_ind.need_confirm);
break;
case BTC_GATTS_ACT_SEND_RESPONSE: {
esp_ble_gatts_cb_param_t param;
esp_ble_gatts_cb_param_t param = {0};
esp_gatt_rsp_t *p_rsp = arg->send_rsp.rsp;
if (p_rsp) {
@@ -1099,7 +1196,7 @@ void btc_gatts_cb_handler(btc_msg_t *msg)
void btc_congest_callback(tBTA_GATTS *param)
{
esp_ble_gatts_cb_param_t esp_param;
esp_ble_gatts_cb_param_t esp_param = {0};
esp_gatt_if_t gatts_if = BTC_GATT_GET_GATT_IF(param->congest.conn_id);
esp_param.congest.conn_id = BTC_GATT_GET_CONN_ID(param->congest.conn_id);
esp_param.congest.congested = param->congest.congested;

View File

@@ -171,7 +171,7 @@ void gatt_sec_check_complete(BOOLEAN sec_check_ok, tGATT_CLCB *p_clcb, UINT8 s
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;
UINT8 sec_flag = 0;
BOOLEAN status = FALSE;
UNUSED(p_ref_data);
@@ -185,9 +185,8 @@ void gatt_enc_cmpl_cback(BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_d
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) {
if (BTM_GetSecurityFlagsByTransport(bd_addr, &sec_flag, transport) &&
(sec_flag & BTM_SEC_FLAG_LKEY_AUTHED)) {
status = TRUE;
}
} else {
@@ -305,7 +304,7 @@ tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB *p_tcb)
tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB *p_clcb )
{
tGATT_SEC_ACTION act = GATT_SEC_OK;
UINT8 sec_flag;
UINT8 sec_flag = 0;
tGATT_TCB *p_tcb = p_clcb->p_tcb;
tGATT_AUTH_REQ auth_req = p_clcb->auth_req;
BOOLEAN is_link_encrypted = FALSE;

View File

@@ -754,8 +754,7 @@ void gatt_process_read_multi_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U
for (ll = 0; ll < p_tcb->sr_cmd.multi_req.num_handles; ll ++) {
if ((p_msg = (tGATTS_RSP *)osi_malloc(sizeof(tGATTS_RSP))) != NULL) {
memset(p_msg, 0, sizeof(tGATTS_RSP))
;
memset(p_msg, 0, sizeof(tGATTS_RSP));
handle = p_tcb->sr_cmd.multi_req.handles[ll];
i_rcb = gatt_sr_find_i_rcb_by_handle(handle);
@@ -1496,10 +1495,17 @@ void gatt_attr_process_prepare_write (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 hand
}
}
/* sr_cmd enqueued at handle but no attribute branch ran (null DB/list or no exact handle). */
if (trans_id != 0 && !is_need_prepare_write_rsp && !is_need_queue_data &&
status == GATT_SUCCESS) {
status = GATT_INVALID_HANDLE;
}
if (is_need_queue_data){
queue_data = (tGATT_PREPARE_WRITE_QUEUE_DATA *)osi_malloc(len + sizeof(tGATT_PREPARE_WRITE_QUEUE_DATA));
if (queue_data == NULL){
status = GATT_PREPARE_Q_FULL;
is_need_prepare_write_rsp = FALSE;
} else {
queue_data->p_attr = p_attr_temp;
queue_data->len = len;
@@ -1509,7 +1515,16 @@ void gatt_attr_process_prepare_write (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 hand
if (prepare_record->queue == NULL) {
prepare_record->queue = fixed_queue_new(QUEUE_SIZE_MAX);
}
fixed_queue_enqueue(prepare_record->queue, queue_data, FIXED_QUEUE_MAX_TIMEOUT);
if (prepare_record->queue == NULL ||
fixed_queue_length(prepare_record->queue) >=
fixed_queue_capacity(prepare_record->queue)) {
osi_free(queue_data);
queue_data = NULL;
status = GATT_PREPARE_Q_FULL;
is_need_prepare_write_rsp = FALSE;
} else {
fixed_queue_enqueue(prepare_record->queue, queue_data, FIXED_QUEUE_MAX_TIMEOUT);
}
}
}

View File

@@ -690,6 +690,9 @@ BOOLEAN gatt_add_an_item_to_list(tGATT_HDL_LIST_INFO *p_list, tGATT_HDL_LIST_ELE
p_new->p_prev = p_old->p_prev;
p_new->p_next = p_old;
if (p_old->p_prev != NULL) {
p_old->p_prev->p_next = p_new;
}
p_old->p_prev = p_new;
break;
@@ -1231,6 +1234,10 @@ BOOLEAN gatt_parse_uuid_from_cmd(tBT_UUID *p_uuid_rec, UINT16 uuid_size, UINT8 *
void gatt_start_rsp_timer(UINT16 clcb_idx)
{
tGATT_CLCB *p_clcb = gatt_clcb_find_by_idx(clcb_idx);
if (p_clcb == NULL) {
GATT_TRACE_ERROR("%s: no CLCB for clcb_idx=0x%x", __func__, clcb_idx);
return;
}
p_clcb->rsp_timer_ent.param = (TIMER_PARAM_TYPE)p_clcb;
btu_start_timer (&p_clcb->rsp_timer_ent, BTU_TTYPE_ATT_WAIT_FOR_RSP,
GATT_WAIT_FOR_RSP_TOUT);
@@ -2305,10 +2312,17 @@ void gatt_cleanup_upon_disc(BD_ADDR bda, UINT16 reason, tBT_TRANSPORT transport)
UINT8 i;
UINT16 conn_id;
tGATT_REG *p_reg = NULL;
#if (GATTS_INCLUDED == TRUE)
BD_ADDR bda_local;
#endif
GATT_TRACE_DEBUG ("gatt_cleanup_upon_disc ");
#if (GATTS_INCLUDED == TRUE)
/* Copy in case bda points into p_tcb->peer_bda, which is invalid after gatt_tcb_free. */
memcpy(bda_local, bda, BD_ADDR_LEN);
#endif
if ((p_tcb = gatt_find_tcb_by_addr(bda, transport)) != NULL) {
GATT_TRACE_DEBUG ("found p_tcb ");
gatt_set_ch_state(p_tcb, GATT_CH_CLOSE);
@@ -2357,7 +2371,7 @@ void gatt_cleanup_upon_disc(BD_ADDR bda, UINT16 reason, tBT_TRANSPORT transport)
BTM_Recovery_Pre_State();
}
#if (GATTS_INCLUDED == TRUE)
gatt_delete_dev_from_srv_chg_clt_list(bda);
gatt_delete_dev_from_srv_chg_clt_list(bda_local);
#endif // (GATTS_INCLUDED == TRUE)
}
/*******************************************************************************