diff --git a/components/bt/host/bluedroid/api/esp_gatts_api.c b/components/bt/host/bluedroid/api/esp_gatts_api.c index ceaf047875c..c93b2bdc96b 100644 --- a/components/bt/host/bluedroid/api/esp_gatts_api.c +++ b/components/bt/host/bluedroid/api/esp_gatts_api.c @@ -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; } } diff --git a/components/bt/host/bluedroid/api/include/api/esp_gatts_api.h b/components/bt/host/bluedroid/api/include/api/esp_gatts_api.h index 875ddbc9a11..09e49b8733e 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_gatts_api.h +++ b/components/bt/host/bluedroid/api/include/api/esp_gatts_api.h @@ -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); diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gatts_act.c b/components/bt/host/bluedroid/bta/gatt/bta_gatts_act.c index 9688b5d2bc9..ec8129e6847 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gatts_act.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gatts_act.c @@ -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); diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gatts_api.c b/components/bt/host/bluedroid/bta/gatt/bta_gatts_api.c index 358b6939913..f8774de77c5 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gatts_api.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gatts_api.c @@ -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 { diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gatts_main.c b/components/bt/host/bluedroid/bta/gatt/bta_gatts_main.c index 6444321437a..2c78d2df8ef 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gatts_main.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gatts_main.c @@ -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; diff --git a/components/bt/host/bluedroid/bta/include/bta/bta_gatt_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_gatt_api.h index d18badf2d51..6aa59059f68 100644 --- a/components/bt/host/bluedroid/bta/include/bta/bta_gatt_api.h +++ b/components/bt/host/bluedroid/bta/include/bta/bta_gatt_api.h @@ -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 */ diff --git a/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatts.c b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatts.c index af060c80b65..b816eb3d6d2 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatts.c +++ b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatts.c @@ -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; diff --git a/components/bt/host/bluedroid/stack/gatt/gatt_auth.c b/components/bt/host/bluedroid/stack/gatt/gatt_auth.c index 0a033e1ae04..19ad2bc4cad 100644 --- a/components/bt/host/bluedroid/stack/gatt/gatt_auth.c +++ b/components/bt/host/bluedroid/stack/gatt/gatt_auth.c @@ -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; diff --git a/components/bt/host/bluedroid/stack/gatt/gatt_sr.c b/components/bt/host/bluedroid/stack/gatt/gatt_sr.c index 62b170b1a26..b30fd173f0e 100644 --- a/components/bt/host/bluedroid/stack/gatt/gatt_sr.c +++ b/components/bt/host/bluedroid/stack/gatt/gatt_sr.c @@ -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); + } } } diff --git a/components/bt/host/bluedroid/stack/gatt/gatt_utils.c b/components/bt/host/bluedroid/stack/gatt/gatt_utils.c index 0782a32c16e..552177df82c 100644 --- a/components/bt/host/bluedroid/stack/gatt/gatt_utils.c +++ b/components/bt/host/bluedroid/stack/gatt/gatt_utils.c @@ -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) } /*******************************************************************************