Merge branch 'bugfix/fix_bluedroid_ai_review_bugs_20260427_v5.4' into 'release/v5.4'

Bugfix/fix bluedroid ai review bugs 20260427 (5.4)

See merge request espressif/esp-idf!49539
This commit is contained in:
Island
2026-06-15 11:04:00 +08:00
137 changed files with 4018 additions and 1394 deletions
@@ -34,7 +34,7 @@ esp_ble_cte_cb_t esp_ble_cte_get_callback(void)
#if (BLE_FEAT_CTE_CONNECTIONLESS_EN == TRUE)
esp_err_t esp_ble_cte_set_connectionless_trans_params(esp_ble_cte_connless_trans_params_t *cte_trans_params)
{
btc_msg_t msg;
btc_msg_t msg = {0};
btc_ble_cte_args_t arg;
memset(&arg, 0, sizeof(arg));
@@ -42,7 +42,15 @@ esp_err_t esp_ble_cte_set_connectionless_trans_params(esp_ble_cte_connless_trans
return ESP_ERR_INVALID_STATE;
}
if ((cte_trans_params == NULL) || (cte_trans_params->antenna_ids == NULL)) {
if (cte_trans_params == NULL) {
return ESP_ERR_INVALID_ARG;
}
/*
* Per Core Spec, switching_pattern_len and Antenna_IDs is ignored when no switching pattern is used
* For AoA CTE type, the transmitter does not
* switch antenna, so Antenna_IDs may be omitted as well.
*/
if ((cte_trans_params->cte_type != ESP_BLE_CTE_TYPE_AOA) && (cte_trans_params->antenna_ids == NULL)) {
return ESP_ERR_INVALID_ARG;
}
// The controller has performed parameter checking, and the host will no longer verify the validity of these parameters repeatedly.
@@ -72,15 +80,24 @@ esp_err_t esp_ble_cte_set_connectionless_trans_params(esp_ble_cte_connless_trans
arg.cte_trans_params.cte_len = cte_trans_params->cte_len;
arg.cte_trans_params.cte_type = cte_trans_params->cte_type;
arg.cte_trans_params.cte_count = cte_trans_params->cte_count;
arg.cte_trans_params.switching_pattern_len = cte_trans_params->switching_pattern_len;
arg.cte_trans_params.antenna_ids = cte_trans_params->antenna_ids;
/* For AoA CTE type, the transmitter does not switch antenna; normalize
* switching_pattern_len and antenna_ids so the BTC layer does not perform
* an unnecessary deep copy of data that the controller will ignore.
*/
if (cte_trans_params->cte_type != ESP_BLE_CTE_TYPE_AOA) {
arg.cte_trans_params.switching_pattern_len = cte_trans_params->switching_pattern_len;
arg.cte_trans_params.antenna_ids = cte_trans_params->antenna_ids;
} else {
arg.cte_trans_params.switching_pattern_len = 0;
arg.cte_trans_params.antenna_ids = NULL;
}
return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_cte_args_t), btc_ble_cte_arg_deep_copy, btc_ble_cte_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
esp_err_t esp_ble_cte_set_connectionless_trans_enable(esp_ble_cte_trans_enable_params_t *cte_trans_enable)
{
btc_msg_t msg;
btc_msg_t msg = {0};
btc_ble_cte_args_t arg;
memset(&arg, 0, sizeof(arg));
@@ -108,7 +125,7 @@ esp_err_t esp_ble_cte_set_connectionless_trans_enable(esp_ble_cte_trans_enable_p
esp_err_t esp_ble_cte_set_connectionless_iq_sampling_enable(esp_ble_cte_iq_sampling_params_t *iq_sampling_en)
{
btc_msg_t msg;
btc_msg_t msg = {0};
btc_ble_cte_args_t arg;
memset(&arg, 0, sizeof(arg));
@@ -169,7 +186,7 @@ esp_err_t esp_ble_cte_set_connectionless_iq_sampling_enable(esp_ble_cte_iq_sampl
#if (BLE_FEAT_CTE_CONNECTION_EN == TRUE)
esp_err_t esp_ble_cte_set_connection_receive_params(esp_ble_cte_recv_params_params_t *cte_recv_params)
{
btc_msg_t msg;
btc_msg_t msg = {0};
btc_ble_cte_args_t arg;
memset(&arg, 0, sizeof(arg));
@@ -221,7 +238,7 @@ esp_err_t esp_ble_cte_set_connection_receive_params(esp_ble_cte_recv_params_para
esp_err_t esp_ble_cte_set_connection_transmit_params(esp_ble_cte_conn_trans_params_t *cte_conn_trans_params)
{
btc_msg_t msg;
btc_msg_t msg = {0};
btc_ble_cte_args_t arg;
memset(&arg, 0, sizeof(arg));
@@ -229,9 +246,19 @@ esp_err_t esp_ble_cte_set_connection_transmit_params(esp_ble_cte_conn_trans_para
return ESP_ERR_INVALID_STATE;
}
if ((cte_conn_trans_params == NULL) || (cte_conn_trans_params->antenna_ids == NULL)) {
if (cte_conn_trans_params == NULL) {
return ESP_ERR_INVALID_ARG;
}
/*
* Per Core Spec, switching_pattern_len and Antenna_IDs is ignored when no switching pattern is used
* For AoA CTE type, the transmitter does not
* switch antenna, so Antenna_IDs may be omitted as well.
*/
if ((cte_conn_trans_params->cte_types & (ESP_BLE_CTE_TYPES_AOD_RESPONSE_WITH_1US | ESP_BLE_CTE_TYPES_AOD_RESPONSE_WITH_2US)) &&
(cte_conn_trans_params->antenna_ids == NULL)) {
return ESP_ERR_INVALID_ARG;
}
// The controller has performed parameter checking, and the host will no longer verify the validity of these parameters repeatedly.
#if (0)
if ((cte_conn_trans_params->switching_pattern_len < ESP_BLE_CTE_MIN_SWITCHING_PATTERN_LENGTH) ||
@@ -251,15 +278,25 @@ esp_err_t esp_ble_cte_set_connection_transmit_params(esp_ble_cte_conn_trans_para
arg.cte_conn_trans_params.conn_handle = cte_conn_trans_params->conn_handle;
arg.cte_conn_trans_params.cte_types = cte_conn_trans_params->cte_types;
arg.cte_conn_trans_params.switching_pattern_len = cte_conn_trans_params->switching_pattern_len;
arg.cte_conn_trans_params.antenna_ids = cte_conn_trans_params->antenna_ids;
/* Antenna switching is only required for AoD CTE responses; when only AoA
* is enabled, normalize switching_pattern_len and antenna_ids so the BTC
* layer does not perform an unnecessary deep copy of data that the
* controller will ignore.
*/
if (cte_conn_trans_params->cte_types & (ESP_BLE_CTE_TYPES_AOD_RESPONSE_WITH_1US | ESP_BLE_CTE_TYPES_AOD_RESPONSE_WITH_2US)) {
arg.cte_conn_trans_params.switching_pattern_len = cte_conn_trans_params->switching_pattern_len;
arg.cte_conn_trans_params.antenna_ids = cte_conn_trans_params->antenna_ids;
} else {
arg.cte_conn_trans_params.switching_pattern_len = 0;
arg.cte_conn_trans_params.antenna_ids = NULL;
}
return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_cte_args_t), btc_ble_cte_arg_deep_copy, btc_ble_cte_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
esp_err_t esp_ble_cte_connection_cte_request_enable(esp_ble_cte_req_en_params_t *cte_conn_req_en)
{
btc_msg_t msg;
btc_msg_t msg = {0};
btc_ble_cte_args_t arg;
memset(&arg, 0, sizeof(arg));
@@ -302,7 +339,7 @@ esp_err_t esp_ble_cte_connection_cte_request_enable(esp_ble_cte_req_en_params_t
esp_err_t esp_ble_cte_connection_cte_response_enable(esp_ble_cte_rsp_en_params_t *cte_conn_rsp_en)
{
btc_msg_t msg;
btc_msg_t msg = {0};
btc_ble_cte_args_t arg;
memset(&arg, 0, sizeof(arg));
@@ -334,7 +371,7 @@ esp_err_t esp_ble_cte_connection_cte_response_enable(esp_ble_cte_rsp_en_params_t
esp_err_t esp_ble_cte_read_antenna_information(void)
{
btc_msg_t msg;
btc_msg_t msg = {0};
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_ERR_INVALID_STATE;
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -63,7 +63,8 @@ esp_err_t esp_ble_iso_create_big(esp_ble_iso_big_creat_params_t *big_creat_param
if (big_creat_param->rtn > 0x1E) {
return ESP_ERR_INVALID_ARG;
}
if ((big_creat_param->phy != 0x01) && (big_creat_param->phy != 0x02) && (big_creat_param->phy != 0x04)) {
/* phy is a bit field: bit0=1M, bit1=2M, bit2=Coded (HCI_LE_Create_BIG, Core Spec): at least one bit. */
if ((big_creat_param->phy == 0) || (big_creat_param->phy & ~0x07)) {
return ESP_ERR_INVALID_ARG;
}
if (big_creat_param->packing > 0x01) {
@@ -118,7 +119,9 @@ esp_err_t esp_ble_iso_create_big_test(esp_ble_iso_big_creat_test_params_t *big_c
if (big_creat_test_param->max_pdu < 0x0001 || big_creat_test_param->max_pdu > 0x00FB) {
return ESP_ERR_INVALID_ARG;
}
if ((big_creat_test_param->phy != 0x01) && (big_creat_test_param->phy != 0x02) && (big_creat_test_param->phy != 0x04)) {
/* HCI_LE_Create_BIG_Test (Core Spec): host shall set exactly one of 1M / 2M / Coded PHY. */
if ((big_creat_test_param->phy != 0x01) && (big_creat_test_param->phy != 0x02) &&
(big_creat_test_param->phy != 0x04)) {
return ESP_ERR_INVALID_ARG;
}
if (big_creat_test_param->framing > BLE_ISO_FRAMING_FRAMED_PDU_UNSEGMENTABLE_MODE) {
@@ -15,6 +15,9 @@
#include "btc/btc_ble_storage.h"
#include "esp_random.h"
/* Hard upper bound to prevent excessive allocations in BTC/BTA layers. */
#define ESP_GAP_BLE_EXT_ADV_DATA_MAX_LEN 1650U
esp_err_t esp_ble_gap_register_callback(esp_gap_ble_cb_t callback)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
@@ -158,7 +161,22 @@ esp_err_t esp_ble_gap_update_conn_params(esp_ble_conn_update_params_t *params)
ESP_BLE_IS_VALID_PARAM(params->max_int, BLE_CONN_INT_MIN_HOST_CHECK, ESP_BLE_CONN_INT_MAX) &&
ESP_BLE_IS_VALID_PARAM(params->timeout, ESP_BLE_CONN_SUP_TOUT_MIN, ESP_BLE_CONN_SUP_TOUT_MAX) &&
(params->latency <= ESP_BLE_CONN_LATENCY_MAX) &&
((params->timeout * 10) >= ((1 + params->latency) * ((params->max_int * 5) >> 1))) && params->min_int <= params->max_int) {
/*
* Core Spec (Vol 6, Part B, Section 4.5.2):
* supervision_timeout shall be strictly greater than
* (1 + connSlaveLatency) * connIntervalMax * 2.
*
* Here:
* - timeout is in 10 ms units
* - max_int is in 1.25 ms units
*
* Convert both sides into 0.5 ms units to avoid truncation:
* (timeout * 10 ms) -> timeout * 20 (0.5 ms units)
* (max_int * 1.25 ms * 2) -> max_int * 5 (0.5 ms units)
*/
(((uint32_t)params->timeout * 20U) >
((uint32_t)(1U + (uint32_t)params->latency) * (uint32_t)params->max_int * 5U)) &&
(params->min_int <= params->max_int)) {
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
@@ -339,7 +357,7 @@ esp_err_t esp_ble_gap_update_whitelist(bool add_remove, esp_bd_addr_t remote_bda
return ESP_ERR_INVALID_STATE;
}
if (!remote_bda){
return ESP_ERR_INVALID_SIZE;
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
@@ -369,7 +387,7 @@ esp_err_t esp_ble_gap_clear_whitelist(void)
esp_err_t esp_ble_gap_get_whitelist_size(uint16_t *length)
{
if (length == NULL) {
return ESP_FAIL;
return ESP_ERR_INVALID_ARG;
}
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_get_whitelist_size(length);
@@ -397,7 +415,9 @@ esp_err_t esp_ble_gap_set_prefer_conn_params(esp_bd_addr_t bd_addr,
ESP_BLE_IS_VALID_PARAM(max_conn_int, BLE_CONN_INT_MIN_HOST_CHECK, ESP_BLE_CONN_INT_MAX) &&
ESP_BLE_IS_VALID_PARAM(supervision_tout, ESP_BLE_CONN_SUP_TOUT_MIN, ESP_BLE_CONN_SUP_TOUT_MAX) &&
(slave_latency <= ESP_BLE_CONN_LATENCY_MAX) &&
((supervision_tout * 10) >= ((1 + slave_latency) * ((max_conn_int * 5) >> 1))) && min_conn_int <= max_conn_int) {
(((uint32_t)supervision_tout * 20U) >
((uint32_t)(1U + (uint32_t)slave_latency) * (uint32_t)max_conn_int * 5U)) &&
(min_conn_int <= max_conn_int)) {
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
@@ -678,7 +698,7 @@ esp_err_t esp_ble_gap_set_security_param(esp_ble_sm_param_t param_type,
uint32_t passkey = 0;
for(uint8_t i = 0; i < len; i++)
{
passkey += (((uint8_t *)value)[i]<<(8*i));
passkey += ((uint32_t)((const uint8_t *)value)[i] << (8U * (uint32_t)i));
}
if(passkey > 999999) {
return ESP_ERR_INVALID_ARG;
@@ -846,6 +866,15 @@ esp_err_t esp_ble_get_bond_device_list(int *dev_num, esp_ble_bond_dev_t *dev_lis
*dev_num = dev_num_total;
}
/*
* The storage layer updates some fields using |= (e.g. key_mask). Ensure
* the caller-provided list is zero-initialized to avoid propagating
* uninitialized heap contents (including padding) back to the caller.
*/
if (*dev_num > 0) {
memset(dev_list, 0, sizeof(*dev_list) * (size_t)(*dev_num));
}
ret = btc_storage_get_bonded_ble_devices_list(dev_list, *dev_num);
return (ret == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
@@ -1293,6 +1322,10 @@ esp_err_t esp_ble_gap_config_ext_adv_data_raw(uint8_t instance, uint16_t length,
return ESP_ERR_INVALID_ARG;
}
if (length > ESP_GAP_BLE_EXT_ADV_DATA_MAX_LEN) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
@@ -1319,6 +1352,10 @@ esp_err_t esp_ble_gap_config_ext_scan_rsp_data_raw(uint8_t instance, uint16_t le
return ESP_ERR_INVALID_ARG;
}
if (length > ESP_GAP_BLE_EXT_ADV_DATA_MAX_LEN) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
msg.act = BTC_GAP_BLE_CFG_EXT_SCAN_RSP_DATA_RAW;
@@ -1454,6 +1491,10 @@ esp_err_t esp_ble_gap_config_periodic_adv_data_raw(uint8_t instance, uint16_t le
return ESP_ERR_INVALID_ARG;
}
if (length > ESP_GAP_BLE_EXT_ADV_DATA_MAX_LEN) {
return ESP_ERR_INVALID_ARG;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GAP_BLE;
@@ -1751,7 +1792,8 @@ esp_err_t esp_ble_gap_prefer_ext_connect_params_set(esp_bd_addr_t addr,
ESP_BLE_IS_VALID_PARAM(phy_1m_conn_params->interval_max, BLE_CONN_INT_MIN_HOST_CHECK, ESP_BLE_CONN_INT_MAX) &&
ESP_BLE_IS_VALID_PARAM(phy_1m_conn_params->supervision_timeout, ESP_BLE_CONN_SUP_TOUT_MIN, ESP_BLE_CONN_SUP_TOUT_MAX) &&
(phy_1m_conn_params->latency <= ESP_BLE_CONN_LATENCY_MAX) &&
((phy_1m_conn_params->supervision_timeout * 10) >= ((1 + phy_1m_conn_params->latency) * ((phy_1m_conn_params->interval_max * 5) >> 1))) &&
(((uint32_t)phy_1m_conn_params->supervision_timeout * 20U) >
((uint32_t)(1U + (uint32_t)phy_1m_conn_params->latency) * (uint32_t)phy_1m_conn_params->interval_max * 5U)) &&
(phy_1m_conn_params->interval_min <= phy_1m_conn_params->interval_max)) {
memcpy(&arg.set_ext_conn_params.phy_1m_conn_params, phy_1m_conn_params, sizeof(esp_ble_gap_conn_params_t));
@@ -1775,7 +1817,8 @@ esp_err_t esp_ble_gap_prefer_ext_connect_params_set(esp_bd_addr_t addr,
ESP_BLE_IS_VALID_PARAM(phy_2m_conn_params->interval_max, BLE_CONN_INT_MIN_HOST_CHECK, ESP_BLE_CONN_INT_MAX) &&
ESP_BLE_IS_VALID_PARAM(phy_2m_conn_params->supervision_timeout, ESP_BLE_CONN_SUP_TOUT_MIN, ESP_BLE_CONN_SUP_TOUT_MAX) &&
(phy_2m_conn_params->latency <= ESP_BLE_CONN_LATENCY_MAX) &&
((phy_2m_conn_params->supervision_timeout * 10) >= ((1 + phy_2m_conn_params->latency) * ((phy_2m_conn_params->interval_max * 5) >> 1))) &&
(((uint32_t)phy_2m_conn_params->supervision_timeout * 20U) >
((uint32_t)(1U + (uint32_t)phy_2m_conn_params->latency) * (uint32_t)phy_2m_conn_params->interval_max * 5U)) &&
(phy_2m_conn_params->interval_min <= phy_2m_conn_params->interval_max)) {
memcpy(&arg.set_ext_conn_params.phy_2m_conn_params, phy_2m_conn_params, sizeof(esp_ble_gap_conn_params_t));
@@ -1799,7 +1842,8 @@ esp_err_t esp_ble_gap_prefer_ext_connect_params_set(esp_bd_addr_t addr,
ESP_BLE_IS_VALID_PARAM(phy_coded_conn_params->interval_max, BLE_CONN_INT_MIN_HOST_CHECK, ESP_BLE_CONN_INT_MAX) &&
ESP_BLE_IS_VALID_PARAM(phy_coded_conn_params->supervision_timeout, ESP_BLE_CONN_SUP_TOUT_MIN, ESP_BLE_CONN_SUP_TOUT_MAX) &&
(phy_coded_conn_params->latency <= ESP_BLE_CONN_LATENCY_MAX) &&
((phy_coded_conn_params->supervision_timeout * 10) >= ((1 + phy_coded_conn_params->latency) * ((phy_coded_conn_params->interval_max * 5) >> 1))) &&
(((uint32_t)phy_coded_conn_params->supervision_timeout * 20U) >
((uint32_t)(1U + (uint32_t)phy_coded_conn_params->latency) * (uint32_t)phy_coded_conn_params->interval_max * 5U)) &&
(phy_coded_conn_params->interval_min <= phy_coded_conn_params->interval_max)) {
memcpy(&arg.set_ext_conn_params.phy_coded_conn_params, phy_coded_conn_params, sizeof(esp_ble_gap_conn_params_t));
@@ -397,7 +397,9 @@ esp_err_t esp_ble_gattc_search_service(esp_gatt_if_t gattc_if, uint16_t conn_id,
esp_gatt_status_t esp_ble_gattc_get_service(esp_gatt_if_t gattc_if, uint16_t conn_id, esp_bt_uuid_t *svc_uuid,
esp_gattc_service_elem_t *result, uint16_t *count, uint16_t offset)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_GATT_WRONG_STATE;
}
if (result == NULL || count == NULL || *count == 0) {
return ESP_GATT_INVALID_PDU;
@@ -415,14 +417,16 @@ esp_gatt_status_t esp_ble_gattc_get_all_char(esp_gatt_if_t gattc_if,
esp_gattc_char_elem_t *result,
uint16_t *count, uint16_t offset)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_GATT_WRONG_STATE;
}
if (result == NULL || count == NULL || *count == 0) {
return ESP_GATT_INVALID_PDU;
}
if ((start_handle == 0) && (end_handle == 0)) {
if ((start_handle == 0 && end_handle == 0) || start_handle > end_handle) {
*count = 0;
return ESP_GATT_INVALID_HANDLE;
}
@@ -437,7 +441,9 @@ esp_gatt_status_t esp_ble_gattc_get_all_descr(esp_gatt_if_t gattc_if,
esp_gattc_descr_elem_t *result,
uint16_t *count, uint16_t offset)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_GATT_WRONG_STATE;
}
if (char_handle == 0) {
return ESP_GATT_INVALID_HANDLE;
@@ -459,13 +465,15 @@ esp_gatt_status_t esp_ble_gattc_get_char_by_uuid(esp_gatt_if_t gattc_if,
esp_gattc_char_elem_t *result,
uint16_t *count)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_GATT_WRONG_STATE;
}
if (result == NULL || count == NULL || *count == 0) {
return ESP_GATT_INVALID_PDU;
}
if (start_handle == 0 && end_handle == 0) {
if ((start_handle == 0 && end_handle == 0) || start_handle > end_handle) {
*count = 0;
return ESP_GATT_INVALID_HANDLE;
}
@@ -484,12 +492,19 @@ esp_gatt_status_t esp_ble_gattc_get_descr_by_uuid(esp_gatt_if_t gattc_if,
esp_gattc_descr_elem_t *result,
uint16_t *count)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_GATT_WRONG_STATE;
}
if (result == NULL || count == NULL || *count == 0) {
return ESP_GATT_INVALID_PDU;
}
if ((start_handle == 0 && end_handle == 0) || start_handle > end_handle) {
*count = 0;
return ESP_GATT_INVALID_HANDLE;
}
uint16_t conn_hdl = BTC_GATT_CREATE_CONN_ID(gattc_if, conn_id);
return btc_ble_gattc_get_descr_by_uuid(conn_hdl, start_handle, end_handle, char_uuid, descr_uuid, result, count);
}
@@ -501,7 +516,9 @@ esp_gatt_status_t esp_ble_gattc_get_descr_by_char_handle(esp_gatt_if_t gattc_if,
esp_gattc_descr_elem_t *result,
uint16_t *count)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_GATT_WRONG_STATE;
}
if (result == NULL || count == NULL || *count == 0) {
return ESP_GATT_INVALID_PDU;
@@ -524,13 +541,15 @@ esp_gatt_status_t esp_ble_gattc_get_include_service(esp_gatt_if_t gattc_if,
esp_gattc_incl_svc_elem_t *result,
uint16_t *count)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_GATT_WRONG_STATE;
}
if (result == NULL || count == NULL || *count == 0) {
return ESP_GATT_INVALID_PDU;
}
if (start_handle == 0 && end_handle == 0) {
if ((start_handle == 0 && end_handle == 0) || start_handle > end_handle) {
*count = 0;
return ESP_GATT_INVALID_HANDLE;
}
@@ -547,13 +566,17 @@ esp_gatt_status_t esp_ble_gattc_get_attr_count(esp_gatt_if_t gattc_if,
uint16_t char_handle,
uint16_t *count)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_GATT_WRONG_STATE;
}
if (count == NULL) {
return ESP_GATT_INVALID_PDU;
}
if ((start_handle == 0 && end_handle == 0) && (type != ESP_GATT_DB_DESCRIPTOR)) {
/* start_handle/end_handle are ignored for ESP_GATT_DB_DESCRIPTOR (see esp_gattc_api.h). */
if (type != ESP_GATT_DB_DESCRIPTOR &&
((start_handle == 0 && end_handle == 0) || start_handle > end_handle)) {
*count = 0;
return ESP_GATT_INVALID_HANDLE;
}
@@ -565,14 +588,16 @@ esp_gatt_status_t esp_ble_gattc_get_attr_count(esp_gatt_if_t gattc_if,
esp_gatt_status_t esp_ble_gattc_get_db(esp_gatt_if_t gattc_if, uint16_t conn_id, uint16_t start_handle, uint16_t end_handle,
esp_gattc_db_elem_t *db, uint16_t *count)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_GATT_WRONG_STATE;
}
if (db == NULL || count == NULL || *count == 0) {
return ESP_GATT_INVALID_PDU;
}
if (start_handle == 0 && end_handle == 0) {
if ((start_handle == 0 && end_handle == 0) || start_handle > end_handle) {
*count = 0;
return ESP_GATT_INVALID_HANDLE;
}
@@ -644,10 +669,14 @@ esp_err_t esp_ble_gattc_read_by_type (esp_gatt_if_t gattc_if,
return ESP_FAIL;
}
if (start_handle == 0 || end_handle == 0) {
if ((start_handle == 0 && end_handle == 0) || start_handle > end_handle) {
return ESP_GATT_INVALID_HANDLE;
}
if (start_handle == 0) {
start_handle = 1;
}
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GATTC;
msg.act = BTC_GATTC_ACT_READ_BY_TYPE;
@@ -670,7 +699,12 @@ esp_err_t esp_ble_gattc_read_multiple(esp_gatt_if_t gattc_if,
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if ((read_multi == NULL) || (read_multi->num_attr == 0) || (read_multi->num_attr > ESP_GATT_MAX_READ_MULTI_HANDLES)) {
if (read_multi == NULL) {
return ESP_ERR_INVALID_ARG;
}
uint8_t num_attr = read_multi->num_attr;
if ((num_attr == 0) || (num_attr > ESP_GATT_MAX_READ_MULTI_HANDLES)) {
return ESP_ERR_INVALID_ARG;
}
@@ -689,10 +723,10 @@ esp_err_t esp_ble_gattc_read_multiple(esp_gatt_if_t gattc_if,
msg.pid = BTC_PID_GATTC;
msg.act = BTC_GATTC_ACT_READ_MULTIPLE_CHAR;
arg.read_multiple.conn_id = BTC_GATT_CREATE_CONN_ID(gattc_if, conn_id);
arg.read_multiple.num_attr = read_multi->num_attr;
arg.read_multiple.num_attr = num_attr;
arg.read_multiple.auth_req = auth_req;
memcpy(arg.read_multiple.handles, read_multi->handles, sizeof(uint16_t)*read_multi->num_attr);
memcpy(arg.read_multiple.handles, read_multi->handles, sizeof(uint16_t) * num_attr);
return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gattc_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
@@ -707,7 +741,12 @@ esp_err_t esp_ble_gattc_read_multiple_variable(esp_gatt_if_t gattc_if,
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if ((read_multi == NULL) || (read_multi->num_attr == 0) || (read_multi->num_attr > ESP_GATT_MAX_READ_MULTI_HANDLES)) {
if (read_multi == NULL) {
return ESP_ERR_INVALID_ARG;
}
uint8_t num_attr = read_multi->num_attr;
if ((num_attr == 0) || (num_attr > ESP_GATT_MAX_READ_MULTI_HANDLES)) {
return ESP_ERR_INVALID_ARG;
}
@@ -726,9 +765,9 @@ esp_err_t esp_ble_gattc_read_multiple_variable(esp_gatt_if_t gattc_if,
msg.pid = BTC_PID_GATTC;
msg.act = BTC_GATTC_ACT_READ_MULTIPLE_VARIABLE_CHAR;
arg.read_multiple.conn_id = BTC_GATT_CREATE_CONN_ID(gattc_if, conn_id);
arg.read_multiple.num_attr = read_multi->num_attr;
arg.read_multiple.num_attr = num_attr;
arg.read_multiple.auth_req = auth_req;
memcpy(arg.read_multiple.handles, read_multi->handles, sizeof(uint16_t)*read_multi->num_attr);
memcpy(arg.read_multiple.handles, read_multi->handles, sizeof(uint16_t) * num_attr);
return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gattc_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
@@ -829,6 +868,10 @@ esp_err_t esp_ble_gattc_write_char_descr (esp_gatt_if_t gattc_if,
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if ((value_len > 0) && (value == NULL)) {
return ESP_ERR_INVALID_ARG;
}
tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(conn_id);
if (!gatt_check_connection_state_by_tcb(p_tcb)) {
LOG_WARN("%s, The connection not created.", __func__);
@@ -873,6 +916,10 @@ esp_err_t esp_ble_gattc_prepare_write(esp_gatt_if_t gattc_if,
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if ((value_len > 0) && (value == NULL)) {
return ESP_ERR_INVALID_ARG;
}
tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(conn_id);
if (!gatt_check_connection_state_by_tcb(p_tcb)) {
LOG_WARN("%s, The connection not created.", __func__);
@@ -915,6 +962,10 @@ esp_err_t esp_ble_gattc_prepare_write_char_descr(esp_gatt_if_t gattc_if,
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if ((value_len > 0) && (value == NULL)) {
return ESP_ERR_INVALID_ARG;
}
tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(conn_id);
if (!gatt_check_connection_state_by_tcb(p_tcb)) {
LOG_WARN("%s, The connection not created.", __func__);
@@ -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;
}
}
@@ -69,7 +69,7 @@ typedef enum {
#define BLE_ISO_WORST_CASE_SCA_LEVEL_20_PPM (0x07)
#define BLE_ISO_PACKING_SEQUENTIAL (0x00)
#define BLE_ISO_PACKING_INTERLEAVED (0x00)
#define BLE_ISO_PACKING_INTERLEAVED (0x01)
#define BLE_ISO_FRAMING_UNFRAMED_PDU (0x00)
#define BLE_ISO_FRAMING_FRAMED_PDU_SEGMENTABLE_MODE (0x01)
@@ -2532,7 +2532,6 @@ typedef union {
*/
struct ble_cs_read_local_supp_caps_evt {
esp_bt_status_t status; /*!< Indicate channel sounding read local supported capabilities command successfully completed */
uint16_t conn_handle; /*!< Connection Handle */
uint8_t num_config_supported; /*!< Number of CS configurations supported per connection */
uint16_t max_consecutive_proc_supported; /*!< 0x0000: Support for both a fixed number of consecutive CS procedures and for an indefinite number of CS procedures until termination
0x0001 to 0xFFFF: Maximum number of consecutive CS procedures supported */
@@ -3113,6 +3112,11 @@ esp_err_t esp_ble_gap_add_device_to_resolving_list(esp_bd_addr_t peer_addr, uint
/**
* @brief This function clears the random address for the application
*
* @note This function shall not be used when:
* - Advertising is enabled,
* - Scanning is enabled, or
* - any LE connection exists / a create connection command is pending.
*
* @return
* - ESP_OK : success
* - other : failed
@@ -519,8 +519,12 @@ esp_err_t esp_ble_gattc_search_service(esp_gatt_if_t gattc_if, uint16_t conn_id,
* 2. `esp_ble_gattc_cache_refresh` can be used to discover services again.
*
* @return
* - ESP_OK: Success
* - ESP_FAIL: Failure
* - ESP_GATT_OK: Success
* - ESP_GATT_WRONG_STATE: Bluedroid stack is not enabled
* - ESP_GATT_INVALID_PDU: NULL pointer to `result` or NULL pointer to `count` or the count value is 0
* - ESP_GATT_NOT_FOUND: No matching service was found in the local cache
* - ESP_GATT_INVALID_OFFSET: `offset` is out of range of the matched services
* - ESP_GATT_NO_RESOURCES: Failed to allocate memory for the UUID lookup
*/
esp_gatt_status_t esp_ble_gattc_get_service(esp_gatt_if_t gattc_if, uint16_t conn_id, esp_bt_uuid_t *svc_uuid,
esp_gattc_service_elem_t *result, uint16_t *count, uint16_t offset);
@@ -538,13 +542,17 @@ esp_gatt_status_t esp_ble_gattc_get_service(esp_gatt_if_t gattc_if, uint16_t con
*
* @note
* 1. This API does not trigger any event.
* 2. `start_handle` must be greater than 0, and smaller than `end_handle`.
* 2. `start_handle` must not be greater than `end_handle`, and `start_handle` and
* `end_handle` must not both be 0. 0 is allowed for `start_handle` alone and matches
* cached attributes from the beginning of the handle range.
*
* @return
* - ESP_OK: Success
* - ESP_GATT_OK: Success
* - ESP_GATT_WRONG_STATE: Bluedroid stack is not enabled
* - ESP_GATT_INVALID_HANDLE: Invalid GATT `start_handle` or `end_handle`
* - ESP_GATT_INVALID_PDU: NULL pointer to `result` or NULL pointer to `count` or the count value is 0
* - ESP_FAIL: Failure due to other reasons
* - ESP_GATT_NOT_FOUND: No characteristic found in the given handle range
* - ESP_GATT_INVALID_OFFSET: `offset` is out of range of the matched characteristics
*/
esp_gatt_status_t esp_ble_gattc_get_all_char(esp_gatt_if_t gattc_if,
uint16_t conn_id,
@@ -568,10 +576,12 @@ esp_gatt_status_t esp_ble_gattc_get_all_char(esp_gatt_if_t gattc_if,
* 2. `char_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_HANDLE: Invalid GATT `char_handle`
* - ESP_GATT_INVALID_PDU: NULL pointer to `result` or NULL pointer to `count` or the count value is 0
* - ESP_FAIL: Failure due to other reasons
* - ESP_GATT_NOT_FOUND: No descriptor found under the given characteristic
* - ESP_GATT_INVALID_OFFSET: `offset` is out of range of the matched descriptors
*/
esp_gatt_status_t esp_ble_gattc_get_all_descr(esp_gatt_if_t gattc_if,
uint16_t conn_id,
@@ -592,13 +602,16 @@ esp_gatt_status_t esp_ble_gattc_get_all_descr(esp_gatt_if_t gattc_if,
*
* @note
* 1. This API does not trigger any event.
* 2. `start_handle` must be greater than 0, and smaller than `end_handle`.
* 2. `start_handle` must not be greater than `end_handle`, and `start_handle` and
* `end_handle` must not both be 0. 0 is allowed for `start_handle` alone and matches
* cached attributes from the beginning of the handle range.
*
* @return
* - ESP_OK: Success
* - ESP_GATT_OK: Success
* - ESP_GATT_WRONG_STATE: Bluedroid stack is not enabled
* - ESP_GATT_INVALID_HANDLE: Invalid GATT `start_handle` or `end_handle`
* - ESP_GATT_INVALID_PDU: NULL pointer to `result` or NULL pointer to `count` or the count value is 0
* - ESP_FAIL: Failure due to other reasons
* - ESP_GATT_NOT_FOUND: No characteristic matching `char_uuid` found in the handle range
*/
esp_gatt_status_t esp_ble_gattc_get_char_by_uuid(esp_gatt_if_t gattc_if,
uint16_t conn_id,
@@ -622,12 +635,16 @@ esp_gatt_status_t esp_ble_gattc_get_char_by_uuid(esp_gatt_if_t gattc_if,
*
* @note
* 1. This API does not trigger any event.
* 2. `start_handle` must be greater than 0, and smaller than `end_handle`.
* 2. `start_handle` must not be greater than `end_handle`, and `start_handle` and
* `end_handle` must not both be 0. 0 is allowed for `start_handle` alone and matches
* cached attributes from the beginning of the handle range.
*
* @return
* - ESP_OK: Success
* - ESP_GATT_OK: Success
* - ESP_GATT_WRONG_STATE: Bluedroid stack is not enabled
* - ESP_GATT_INVALID_HANDLE: Invalid GATT `start_handle` or `end_handle`
* - ESP_GATT_INVALID_PDU: NULL pointer to `result` or NULL pointer to `count` or the count value is 0
* - ESP_FAIL: Failure due to other reasons
* - ESP_GATT_NOT_FOUND: No descriptor matching the given UUIDs found in the handle range
*/
esp_gatt_status_t esp_ble_gattc_get_descr_by_uuid(esp_gatt_if_t gattc_if,
uint16_t conn_id,
@@ -653,10 +670,11 @@ esp_gatt_status_t esp_ble_gattc_get_descr_by_uuid(esp_gatt_if_t gattc_if,
* 2. `char_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_HANDLE: Invalid GATT `char_handle`
* - ESP_GATT_INVALID_PDU: NULL pointer to `result` or NULL pointer to `count` or the count value is 0
* - ESP_FAIL: Failure due to other reasons
* - ESP_GATT_NOT_FOUND: No descriptor matching `descr_uuid` found under `char_handle`
*/
esp_gatt_status_t esp_ble_gattc_get_descr_by_char_handle(esp_gatt_if_t gattc_if,
uint16_t conn_id,
@@ -678,12 +696,16 @@ esp_gatt_status_t esp_ble_gattc_get_descr_by_char_handle(esp_gatt_if_t gattc_if,
*
* @note
* 1. This API does not trigger any event.
* 2. `start_handle` must be greater than 0, and smaller than `end_handle`.
* 2. `start_handle` must not be greater than `end_handle`, and `start_handle` and
* `end_handle` must not both be 0. 0 is allowed for `start_handle` alone and matches
* cached attributes from the beginning of the handle range.
*
* @return
* - ESP_OK: Success
* - ESP_GATT_OK: Success
* - ESP_GATT_WRONG_STATE: Bluedroid stack is not enabled
* - ESP_GATT_INVALID_HANDLE: Invalid GATT `start_handle` or `end_handle`
* - ESP_GATT_INVALID_PDU: NULL pointer to `result` or NULL pointer to `count` or the count value is 0
* - ESP_FAIL: Failure due to other reasons
* - ESP_GATT_NOT_FOUND: No included service matching `incl_uuid` found in the handle range
*/
esp_gatt_status_t esp_ble_gattc_get_include_service(esp_gatt_if_t gattc_if,
uint16_t conn_id,
@@ -707,13 +729,15 @@ esp_gatt_status_t esp_ble_gattc_get_include_service(esp_gatt_if_t gattc_if,
*
* @note
* 1. This API does not trigger any event.
* 2. `start_handle` must be greater than 0, and smaller than `end_handle` if the `type` is not `ESP_GATT_DB_DESCRIPTOR`.
* 2. If the `type` is not `ESP_GATT_DB_DESCRIPTOR`, `start_handle` must not be greater than
* `end_handle`, and `start_handle` and `end_handle` must not both be 0. 0 is allowed for
* `start_handle` alone and matches cached attributes from the beginning of the handle range.
*
* @return
* - ESP_OK: Success
* - ESP_GATT_OK: Success
* - ESP_GATT_WRONG_STATE: Bluedroid stack is not enabled
* - ESP_GATT_INVALID_HANDLE: Invalid GATT `start_handle`, `end_handle`
* - ESP_GATT_INVALID_PDU: NULL pointer to `count`
* - ESP_FAIL: Failure due to other reasons
*/
esp_gatt_status_t esp_ble_gattc_get_attr_count(esp_gatt_if_t gattc_if,
uint16_t conn_id,
@@ -735,13 +759,16 @@ esp_gatt_status_t esp_ble_gattc_get_attr_count(esp_gatt_if_t gattc_if,
*
* @note
* 1. This API does not trigger any event.
* 2. `start_handle` must be greater than 0, and smaller than `end_handle`.
* 2. `start_handle` must not be greater than `end_handle`, and `start_handle` and
* `end_handle` must not both be 0. 0 is allowed for `start_handle` alone and matches
* cached attributes from the beginning of the handle range.
*
* @return
* - ESP_OK: Success
* - ESP_GATT_OK: Success
* - ESP_GATT_WRONG_STATE: Bluedroid stack is not enabled
* - ESP_GATT_INVALID_HANDLE: Invalid GATT `start_handle`, `end_handle`
* - ESP_GATT_INVALID_PDU: NULL pointer to `db` or NULL pointer to `count` or the count value is 0
* - ESP_FAIL: Failure due to other reasons
* - ESP_GATT_NOT_FOUND: No GATT database element found in the given handle range
*
*/
esp_gatt_status_t esp_ble_gattc_get_db(esp_gatt_if_t gattc_if, uint16_t conn_id, uint16_t start_handle, uint16_t end_handle,
@@ -784,7 +811,9 @@ esp_err_t esp_ble_gattc_read_char (esp_gatt_if_t gattc_if,
* @note
* 1. This function triggers `ESP_GATTC_READ_CHAR_EVT`.
* 2. This function should be called only after the connection has been established.
* 3. `start_handle` must be greater than 0, and smaller than `end_handle`.
* 3. `start_handle` must not be greater than `end_handle`, and `start_handle` and
* `end_handle` must not both be 0. 0 is allowed for `start_handle` alone and is
* treated as 1 on air.
*
* @return
* - ESP_OK: Success
@@ -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);
@@ -189,7 +189,7 @@ void bta_gattc_disable(tBTA_GATTC_CB *p_cb)
*******************************************************************************/
void bta_gattc_register(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data)
{
tBTA_GATTC cb_data;
tBTA_GATTC cb_data = {0};
UINT8 i;
tBT_UUID *p_app_uuid = &p_data->api_reg.app_uuid;
tBTA_GATTC_INT_START_IF *p_buf;
@@ -383,7 +383,7 @@ void bta_gattc_process_api_open_cancel (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_
UINT16 event = ((BT_HDR *)p_msg)->event;
tBTA_GATTC_CLCB *p_clcb = NULL;
tBTA_GATTC_RCB *p_clreg;
tBTA_GATTC cb_data;
tBTA_GATTC cb_data = {0};
UNUSED(p_cb);
if (p_msg->api_cancel_conn.is_direct) {
@@ -425,7 +425,7 @@ void bta_gattc_process_api_open_cancel (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_
void bta_gattc_process_enc_cmpl(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_msg)
{
tBTA_GATTC_RCB *p_clreg;
tBTA_GATTC cb_data;
tBTA_GATTC cb_data = {0};
UNUSED(p_cb);
p_clreg = bta_gattc_cl_get_regcb(p_msg->enc_cmpl.client_if);
@@ -451,7 +451,7 @@ void bta_gattc_process_enc_cmpl(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_msg)
*******************************************************************************/
void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
tBTA_GATTC cb_data;
tBTA_GATTC cb_data = {0};
UNUSED(p_data);
memset(&cb_data, 0, sizeof(cb_data));
@@ -513,6 +513,8 @@ void bta_gattc_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
return;
}
memset(&gattc_data, 0, sizeof(gattc_data));
p_tcb = gatt_find_tcb_by_addr(p_data->api_conn.remote_bda, BT_TRANSPORT_LE);
if(p_tcb) {
found_app = gatt_find_specific_app_in_hold_link(p_tcb, p_clcb->p_rcb->client_if);
@@ -584,6 +586,8 @@ void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB *p_clreg
tBTA_GATTC_CLCB *p_clcb;
tBTA_GATTC_DATA gattc_data;
memset(&gattc_data, 0, sizeof(gattc_data));
if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, TRUE, FALSE)) {
/* always call open to hold a connection */
if (!GATT_Connect(p_data->client_if, p_data->remote_bda,
@@ -634,8 +638,7 @@ void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB *p_clreg
void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN *p_data)
{
tBTA_GATTC_RCB *p_clreg;
tBTA_GATTC cb_data;
tBTA_GATTC cb_data = {0};
memset(&cb_data, 0, sizeof(cb_data));
cb_data.cancel_open.status = BTA_GATT_ERROR;
cb_data.cancel_open.client_if = p_data->client_if;
@@ -667,7 +670,7 @@ void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN *p_data)
*******************************************************************************/
void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
tBTA_GATTC cb_data;
tBTA_GATTC cb_data = {0};
UNUSED(p_data);
if ( p_clcb->p_rcb->p_cback ) {
@@ -691,8 +694,7 @@ void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
*******************************************************************************/
void bta_gattc_cancel_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
tBTA_GATTC cb_data;
tBTA_GATTC cb_data = {0};
if (GATT_CancelConnect(p_clcb->p_rcb->client_if, p_data->api_cancel_conn.remote_bda, TRUE)) {
bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CANCEL_OPEN_OK_EVT, p_data);
} else {
@@ -759,12 +761,18 @@ void bta_gattc_conn(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
bta_gattc_register_service_change_notify(p_clcb->bta_conn_id, p_clcb->bda);
} else
#endif
{ /* cache is building */
APPL_TRACE_DEBUG("%s cache not found, start discovery %u", __func__, bta_gattc_cb.auto_disc);
{ /* cache miss or cache load failed */
APPL_TRACE_DEBUG("%s cache not found, auto_disc=%u", __func__, bta_gattc_cb.auto_disc);
if (bta_gattc_cb.auto_disc) {
p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC;
/* cache load failure, start discovery */
bta_gattc_start_discover(p_clcb, NULL);
} else {
/* Auto discovery is disabled: roll the SRCB back to
* SERV_IDLE so it is not stuck in SERV_LOAD. The app is
* expected to drive service discovery explicitly via
* BTA_GATTC_ServiceSearchRequest() once it is ready. */
p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE;
}
}
} else { /* cache is building */
@@ -852,8 +860,7 @@ void bta_gattc_disconncback(tBTA_GATTC_RCB *p_rcb, tBTA_GATTC_DATA *p_data)
*******************************************************************************/
void bta_gattc_close_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
tBTA_GATTC cb_data;
tBTA_GATTC cb_data = {0};
if ( p_clcb->p_rcb->p_cback ) {
memset(&cb_data, 0, sizeof(tBTA_GATTC));
cb_data.close.client_if = p_clcb->p_rcb->client_if;
@@ -883,8 +890,7 @@ void bta_gattc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
}
tBTA_GATTC_CBACK *p_cback = p_clcb->p_rcb->p_cback;
tBTA_GATTC_RCB *p_clreg = p_clcb->p_rcb;
tBTA_GATTC cb_data;
tBTA_GATTC cb_data = {0};
APPL_TRACE_DEBUG("bta_gattc_close conn_id=%d", p_clcb->bta_conn_id);
cb_data.close.client_if = p_clcb->p_rcb->client_if;
@@ -908,9 +914,13 @@ void bta_gattc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
(* p_cback)(BTA_GATTC_CLOSE_EVT, (tBTA_GATTC *)&cb_data);
}
// Please note that BTA_GATTC_CLOSE_EVT will run in the BTC task.
// because bta_gattc_deregister_cmpl did not execute as expected(this is a known issue),
// we will run it again in bta_gattc_clcb_dealloc_by_conn_id.
/*
* Free the CLCB in the BTA task after the close callback has been copied to
* BTC. This keeps the original close-callback semantics while avoiding BTC
* task access to core stack control blocks without locking.
*/
bta_gattc_clcb_dealloc(p_clcb);
if (p_clreg->num_clcb == 0 && p_clreg->dereg_pending) {
bta_gattc_deregister_cmpl(p_clreg);
}
@@ -1078,7 +1088,7 @@ void bta_gattc_start_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
APPL_TRACE_ERROR("discovery on server failed");
bta_gattc_reset_discover_st(p_clcb->p_srcb, p_clcb->status);
//discover service complete, trigger callback
tBTA_GATTC cb_data;
tBTA_GATTC cb_data = {0};
cb_data.dis_cmpl.status = p_clcb->status;
cb_data.dis_cmpl.conn_id = p_clcb->bta_conn_id;
( *p_clcb->p_rcb->p_cback)(BTA_GATTC_DIS_SRVC_CMPL_EVT, &cb_data);
@@ -1380,7 +1390,7 @@ void bta_gattc_confirm(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
void bta_gattc_read_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data)
{
UINT8 event;
tBTA_GATTC cb_data;
tBTA_GATTC cb_data = {0};
tBTA_GATT_UNFMT read_value;
if (p_clcb->p_q_cmd == NULL) {
@@ -1434,8 +1444,21 @@ void bta_gattc_write_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data)
APPL_TRACE_ERROR("%s, p_data->p_cmpl is NULL", __func__);
UINT16 handle = p_clcb->p_q_cmd->api_write.handle;
tBTA_GATTC_EVT cmpl_evt = p_clcb->p_q_cmd->api_write.cmpl_evt;
tBTA_GATTC_CONN *p_conn = bta_gattc_conn_find(p_clcb->bda);
bta_gattc_free_command_data(p_clcb);
bta_gattc_pop_command_to_send(p_clcb);
/* If this completion belongs to the internal service-change CCC write,
* clear the in-progress flag and swallow the event so the application
* does not see a spurious BTA_GATTC_WRITE_DESCR_EVT, and a future
* bta_gattc_register_service_change_notify() can retry. */
if (p_conn &&
p_conn->write_remote_svc_change_ccc_in_progress &&
p_conn->svc_change_descr_handle == handle) {
p_conn->write_remote_svc_change_ccc_in_progress = FALSE;
p_conn->write_remote_svc_change_ccc_done = FALSE;
APPL_TRACE_ERROR("svc chg ccc: p_cmpl NULL");
return;
}
cb_data.write.status = BTA_GATT_ERROR;
cb_data.write.handle = handle;
cb_data.write.conn_id = p_clcb->bta_conn_id;
@@ -1452,7 +1475,7 @@ void bta_gattc_write_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data)
p_clcb->p_q_cmd->api_write.write_type == BTA_GATTC_WRITE_PREPARE) {
// Check if the parameters are valid
// should not happen, but just in case
if (p_clcb->p_q_cmd->api_write.p_value == NULL) {
if (p_clcb->p_q_cmd->api_write.p_value == NULL && p_clcb->p_q_cmd->api_write.len != 0) {
APPL_TRACE_ERROR("%s, p_clcb->p_q_cmd->api_write.p_value is NULL", __func__);
bta_gattc_free_command_data(p_clcb);
bta_gattc_pop_command_to_send(p_clcb);
@@ -1461,10 +1484,21 @@ void bta_gattc_write_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data)
( *p_clcb->p_rcb->p_cback)(BTA_GATTC_PREP_WRITE_EVT, (tBTA_GATTC *)&cb_data);
return;
}
// Should check the value received from the peer device is correct or not.
if (memcmp(p_clcb->p_q_cmd->api_write.p_value, p_data->p_cmpl->att_value.value,
p_data->p_cmpl->att_value.len) != 0) {
cb_data.write.status = BTA_GATT_INVALID_PDU;
/* Rsp value is one ATT chunk (<= MTU-5), not necessarily full api_write.len. */
{
UINT16 rsp_len = p_data->p_cmpl->att_value.len;
UINT16 req_len = p_clcb->p_q_cmd->api_write.len;
tGATT_VALUE *a = &p_data->p_cmpl->att_value;
tBTA_GATTC_API_WRITE *w = &p_clcb->p_q_cmd->api_write;
if (a->handle != w->handle || a->offset != w->offset || rsp_len > req_len ||
(req_len > 0 && rsp_len == 0) ||
(rsp_len > 0 && w->p_value != NULL &&
memcmp(w->p_value, a->value, rsp_len) != 0)) {
APPL_TRACE_ERROR("%s prep_write rsp bad h %u/%u o %u/%u len %u/%u", __func__,
a->handle, w->handle, a->offset, w->offset, rsp_len, req_len);
cb_data.write.status = BTA_GATT_INVALID_PDU;
}
}
event = BTA_GATTC_PREP_WRITE_EVT;
@@ -1475,12 +1509,17 @@ void bta_gattc_write_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data)
bta_gattc_free_command_data(p_clcb);
bta_gattc_pop_command_to_send(p_clcb);
cb_data.write.conn_id = p_clcb->bta_conn_id;
if (p_conn && p_conn->svc_change_descr_handle == cb_data.write.handle) {
if(cb_data.write.status != BTA_GATT_OK) {
if (p_conn &&
p_conn->write_remote_svc_change_ccc_in_progress &&
p_conn->svc_change_descr_handle == cb_data.write.handle) {
p_conn->write_remote_svc_change_ccc_in_progress = FALSE;
if (cb_data.write.status == BTA_GATT_OK) {
p_conn->write_remote_svc_change_ccc_done = TRUE;
} else {
p_conn->write_remote_svc_change_ccc_done = FALSE;
APPL_TRACE_ERROR("service change write ccc failed");
}
return;
return; /* internal CCC write: don't forward to application */
}
/* write complete, callback */
( *p_clcb->p_rcb->p_cback)(event, (tBTA_GATTC *)&cb_data);
@@ -1497,7 +1536,7 @@ void bta_gattc_write_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data)
*******************************************************************************/
void bta_gattc_exec_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data)
{
tBTA_GATTC cb_data;
tBTA_GATTC cb_data = {0};
//free the command data store in the queue.
bta_gattc_free_command_data(p_clcb);
bta_gattc_pop_command_to_send(p_clcb);
@@ -1522,7 +1561,7 @@ void bta_gattc_exec_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data)
*******************************************************************************/
void bta_gattc_cfg_mtu_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data)
{
tBTA_GATTC cb_data;
tBTA_GATTC cb_data = {0};
//free the command data store in the queue.
bta_gattc_free_command_data(p_clcb);
bta_gattc_pop_command_to_send(p_clcb);
@@ -1650,7 +1689,7 @@ void bta_gattc_ignore_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
void bta_gattc_search(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
{
tBTA_GATT_STATUS status = GATT_INTERNAL_ERROR;
tBTA_GATTC cb_data;
tBTA_GATTC cb_data = {0};
APPL_TRACE_DEBUG("bta_gattc_search conn_id=%d", p_clcb->bta_conn_id);
if (p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_cache) {
status = BTA_GATT_OK;
@@ -1782,7 +1821,7 @@ void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB *p_clreg)
{
tBTA_GATTC_CB *p_cb = &bta_gattc_cb;
tBTA_GATTC_IF client_if = p_clreg->client_if;
tBTA_GATTC cb_data;
tBTA_GATTC cb_data = {0};
tBTA_GATTC_CBACK *p_cback = p_clreg->p_cback;
memset(&cb_data, 0, sizeof(tBTA_GATTC));
@@ -1910,7 +1949,7 @@ static void bta_gattc_enc_cmpl_cback(tGATT_IF gattc_if, BD_ADDR bda)
*******************************************************************************/
void bta_gattc_process_api_refresh(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_msg)
{
tBTA_GATTC_SERV *p_srvc_cb = bta_gattc_find_srvr_cache(p_msg->api_refresh.remote_bda);
tBTA_GATTC_SERV *p_srvc_cb;
tBTA_GATTC_CLCB *p_clcb = &bta_gattc_cb.clcb[0];
BOOLEAN found = FALSE;
UINT8 i;
@@ -1918,6 +1957,14 @@ void bta_gattc_process_api_refresh(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_msg)
APPL_TRACE_DEBUG("%s", __func__);
#if (GATTC_CACHE_NVS == TRUE)
if (p_msg->api_refresh.erase_flash) {
bta_gattc_cache_reset(p_msg->api_refresh.remote_bda);
}
#endif
p_srvc_cb = bta_gattc_find_srvr_cache(p_msg->api_refresh.remote_bda);
if (p_srvc_cb != NULL) {
/* try to find a CLCB */
if (p_srvc_cb->connected && p_srvc_cb->num_clcb != 0) {
@@ -2014,11 +2061,17 @@ void bta_gattc_process_api_cache_get_addr_list(tBTA_GATTC_CB *p_cb, tBTA_GATTC_D
*******************************************************************************/
void bta_gattc_process_api_cache_clean(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_msg)
{
tBTA_GATTC_SERV *p_srvc_cb = bta_gattc_find_srvr_cache(p_msg->api_clean.remote_bda);
tBTA_GATTC_SERV *p_srvc_cb;
UNUSED(p_cb);
APPL_TRACE_DEBUG("%s", __func__);
#if (GATTC_CACHE_NVS == TRUE)
bta_gattc_cache_reset(p_msg->api_clean.remote_bda);
#endif
p_srvc_cb = bta_gattc_find_srvr_cache(p_msg->api_clean.remote_bda);
if (p_srvc_cb != NULL && p_srvc_cb->p_srvc_cache != NULL) {
//mark it and delete the cache */
list_free(p_srvc_cb->p_srvc_cache);
@@ -2094,6 +2147,8 @@ BOOLEAN bta_gattc_process_srvc_chg_ind(UINT16 conn_id,
tBTA_GATTC_CONN *p_conn = bta_gattc_conn_find(p_clcb->bda);
if(p_conn) {
p_conn->write_remote_svc_change_ccc_done = FALSE;
p_conn->write_remote_svc_change_ccc_in_progress = FALSE;
p_conn->svc_change_descr_handle = 0;
}
bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
}
@@ -2300,7 +2355,7 @@ static void bta_gattc_cmpl_sendmsg(UINT16 conn_id, tGATTC_OPTYPE op,
********************************************************************************/
static void bta_gattc_cong_cback (UINT16 conn_id, BOOLEAN congested)
{
tBTA_GATTC cb_data;
tBTA_GATTC cb_data = {0};
cb_data.congest.conn_id = conn_id;
cb_data.congest.congested = congested;
btc_gattc_congest_callback(&cb_data);
@@ -2343,6 +2398,8 @@ void bta_gattc_init_clcb_conn(UINT8 cif, BD_ADDR remote_bda)
tBTA_GATTC_DATA gattc_data;
UINT16 conn_id;
memset(&gattc_data, 0, sizeof(gattc_data));
/* should always get the connection ID */
if (GATT_GetConnIdIfConnected(cif, remote_bda, &conn_id, BTA_GATT_TRANSPORT_LE) == FALSE) {
APPL_TRACE_ERROR("bta_gattc_init_clcb_conn ERROR: not a connected device");
@@ -2414,7 +2471,8 @@ tBTA_GATTC_FIND_SERVICE_CB bta_gattc_register_service_change_notify(UINT16 conn_
tBT_UUID gatt_service_change_uuid = {LEN_UUID_16, {GATT_UUID_GATT_SRV_CHGD}};
tBT_UUID gatt_ccc_uuid = {LEN_UUID_16, {GATT_UUID_CHAR_CLIENT_CONFIG}};
tBTA_GATTC_CONN *p_conn = bta_gattc_conn_find_alloc(remote_bda);
if(p_conn && p_conn->write_remote_svc_change_ccc_done) {
if (p_conn && (p_conn->write_remote_svc_change_ccc_done ||
p_conn->write_remote_svc_change_ccc_in_progress)) {
return SERVICE_CHANGE_CCC_WRITTEN_SUCCESS;
}
@@ -2481,17 +2539,26 @@ tBTA_GATTC_FIND_SERVICE_CB bta_gattc_register_service_change_notify(UINT16 conn_
}
if (gatt_ccc_found == TRUE){
if (p_conn) {
/*
* The in-progress flag is required so that bta_gattc_write_cmpl can
* recognize this internal CCC write and avoid forwarding the response
* to the application as a spurious BTA_GATTC_WRITE_DESCR_EVT. If the
* connection tracking slot could not be obtained (e.g. conn_track is
* full), skip the write entirely instead of issuing an untracked one.
*/
if (p_conn == NULL) {
APPL_TRACE_ERROR("%s: no conn_track, skip ccc", __func__);
result = SERVICE_CHANGE_WRITE_CCC_FAILED;
} else {
p_conn->svc_change_descr_handle = p_desc->handle;
p_conn->write_remote_svc_change_ccc_done = TRUE;
p_conn->write_remote_svc_change_ccc_in_progress = TRUE;
result = SERVICE_CHANGE_CCC_WRITTEN_SUCCESS;
uint16_t indicate_value = GATT_CLT_CONFIG_INDICATION;
tBTA_GATT_UNFMT indicate_v;
indicate_v.len = 2;
indicate_v.p_value = (uint8_t *)&indicate_value;
BTA_GATTC_WriteCharDescr (conn_id, p_desc->handle, BTA_GATTC_TYPE_WRITE, &indicate_v, BTA_GATT_AUTH_REQ_NONE);
}
result = SERVICE_CHANGE_CCC_WRITTEN_SUCCESS;
uint16_t indicate_value = GATT_CLT_CONFIG_INDICATION;
tBTA_GATT_UNFMT indicate_v;
indicate_v.len = 2;
indicate_v.p_value = (uint8_t *)&indicate_value;
BTA_GATTC_WriteCharDescr (conn_id, p_desc->handle, BTA_GATTC_TYPE_WRITE, &indicate_v, BTA_GATT_AUTH_REQ_NONE);
}
else if (gatt_service_change_found == TRUE) {
/* Gatt service char found, but service change char ccc not found,
@@ -91,6 +91,7 @@ void BTA_GATTC_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTC_CBACK *p_client_cb)
}
if ((p_buf = (tBTA_GATTC_API_REG *) osi_malloc(sizeof(tBTA_GATTC_API_REG))) != NULL) {
memset(p_buf, 0, sizeof(*p_buf));
p_buf->hdr.event = BTA_GATTC_API_REG_EVT;
if (p_app_uuid != NULL) {
memcpy(&p_buf->app_uuid, p_app_uuid, sizeof(tBT_UUID));
@@ -206,6 +207,7 @@ void BTA_GATTC_CancelOpen(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN i
tBTA_GATTC_API_CANCEL_OPEN *p_buf;
if ((p_buf = (tBTA_GATTC_API_CANCEL_OPEN *) osi_malloc(sizeof(tBTA_GATTC_API_CANCEL_OPEN))) != NULL) {
memset(p_buf, 0, sizeof(tBTA_GATTC_API_CANCEL_OPEN));
p_buf->hdr.event = BTA_GATTC_API_CANCEL_OPEN_EVT;
p_buf->client_if = client_if;
@@ -780,6 +782,7 @@ void BTA_GATTC_PrepareWrite (UINT16 conn_id, UINT16 handle,
p_buf->handle = handle;
p_buf->write_type = BTA_GATTC_WRITE_PREPARE;
p_buf->cmpl_evt = BTA_GATTC_PREP_WRITE_EVT;
p_buf->offset = offset;
p_buf->len = len;
@@ -827,6 +830,7 @@ void BTA_GATTC_PrepareWriteCharDescr (UINT16 conn_id, UINT16 handle,
p_buf->auth_req = auth_req;
p_buf->handle = handle;
p_buf->write_type = BTA_GATTC_WRITE_PREPARE;
p_buf->cmpl_evt = BTA_GATTC_PREP_WRITE_EVT;
p_buf->offset = offset;
if (p_data && p_data->len != 0) {
@@ -1043,12 +1047,6 @@ tBTA_GATT_STATUS BTA_GATTC_DeregisterForNotifications (tBTA_GATTC_IF client_if,
*******************************************************************************/
void BTA_GATTC_Refresh(BD_ADDR remote_bda, bool erase_flash)
{
#if(GATTC_CACHE_NVS == TRUE)
if(erase_flash) {
/* used to reset cache in application */
bta_gattc_cache_reset(remote_bda);
}
#endif
//If the registration callback is NULL, return
if(bta_sys_is_register(BTA_ID_GATTC) == FALSE) {
return;
@@ -1056,8 +1054,10 @@ void BTA_GATTC_Refresh(BD_ADDR remote_bda, bool erase_flash)
tBTA_GATTC_API_CACHE_REFRESH *p_buf;
if ((p_buf = (tBTA_GATTC_API_CACHE_REFRESH *) osi_malloc(sizeof(tBTA_GATTC_API_CACHE_REFRESH))) != NULL) {
memset(p_buf, 0, sizeof(tBTA_GATTC_API_CACHE_REFRESH));
p_buf->hdr.event = BTA_GATTC_API_REFRESH_EVT;
memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
p_buf->erase_flash = erase_flash ? TRUE : FALSE;
bta_sys_sendmsg(p_buf);
}
@@ -1106,11 +1106,6 @@ void BTA_GATTC_CacheGetAddrList(tBTA_GATTC_IF client_if)
*******************************************************************************/
void BTA_GATTC_Clean(BD_ADDR remote_bda)
{
#if(GATTC_CACHE_NVS == TRUE)
/* used to reset cache in application */
bta_gattc_cache_reset(remote_bda);
#endif
tBTA_GATTC_API_CACHE_CLEAN *p_buf;
if ((p_buf = (tBTA_GATTC_API_CACHE_CLEAN *) osi_malloc(sizeof(tBTA_GATTC_API_CACHE_CLEAN))) != NULL) {
File diff suppressed because it is too large Load Diff
@@ -15,9 +15,6 @@
* limitations under the License.
*
******************************************************************************/
#ifdef BT_SUPPORT_NVM
#include <unistd.h>
#endif /* BT_SUPPORT_NVM */
#include <string.h>
#include <stdio.h>
#include "bta/bta_gattc_co.h"
@@ -30,6 +27,8 @@
#include "osi/list.h"
#include "esp_err.h"
#include "osi/allocator.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#if( defined BLE_INCLUDED ) && (BLE_INCLUDED == TRUE)
#if( defined BTA_GATT_INCLUDED ) && (GATTC_INCLUDED == TRUE)
@@ -40,42 +39,6 @@
#define MAX_DEVICE_IN_CACHE 50
#define MAX_ADDR_LIST_CACHE_BUF 2048
#ifdef BT_SUPPORT_NVM
static FILE *sCacheFD = 0;
static void getFilename(char *buffer, BD_ADDR bda)
{
sprintf(buffer, "%s%02x%02x%02x%02x%02x%02x", GATT_CACHE_PREFIX
, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
}
static void cacheClose(void)
{
if (sCacheFD != 0) {
fclose(sCacheFD);
sCacheFD = 0;
}
}
static bool cacheOpen(BD_ADDR bda, bool to_save)
{
char fname[255] = {0};
getFilename(fname, bda);
cacheClose();
sCacheFD = fopen(fname, to_save ? "w" : "r");
return (sCacheFD != 0);
}
static void cacheReset(BD_ADDR bda)
{
char fname[255] = {0};
getFilename(fname, bda);
unlink(fname);
}
#else
static const char *cache_key = "gattc_cache_key";
static const char *cache_addr = "cache_addr_tab";
@@ -98,6 +61,60 @@ typedef struct {
static cache_env_t *cache_env = NULL;
/* Protect |cache_env|; exported callouts re-enter each other (e.g. cacheOpen -> find_addr).
*
* The mutex is created exactly once from bta_gattc_co_cache_addr_init() on the
* BT host startup task before any other callout becomes reachable, so we do
* NOT need any spinlock around the creation. The *Static variant places the
* storage in .bss and avoids any allocation. */
static StaticSemaphore_t s_cache_env_mutex_buf;
static SemaphoreHandle_t s_cache_env_mutex = NULL;
/* Must be called from the BT host startup task (single-threaded context)
* before any other cache_env_* user becomes reachable. Idempotent. */
static void cache_env_mutex_init_once(void)
{
if (s_cache_env_mutex == NULL) {
s_cache_env_mutex = xSemaphoreCreateRecursiveMutexStatic(&s_cache_env_mutex_buf);
}
}
static void cache_env_lock(void)
{
if (s_cache_env_mutex != NULL) {
(void)xSemaphoreTakeRecursive(s_cache_env_mutex, portMAX_DELAY);
}
}
static void cache_env_unlock(void)
{
if (s_cache_env_mutex != NULL) {
xSemaphoreGiveRecursive(s_cache_env_mutex);
}
}
/* Format a per-device GATT cache NVS namespace name into |buffer|.
*
* Output layout: GATT_CACHE_PREFIX (5 chars: "gatt_") + sizeof(hash_key_t)*2
* hex chars (currently 8) + NUL = 14 bytes total.
*
* Contract:
* |buffer| MUST be at least NVS_KEY_NAME_MAX_SIZE (16) bytes, which is also
* the NVS limit for a namespace name. Today's 14-byte output leaves only
* 2 bytes of headroom -- if GATT_CACHE_PREFIX is ever lengthened or
* sizeof(hash_key_t) is ever increased so that
*
* strlen(GATT_CACHE_PREFIX) + 2*sizeof(hash_key_t) + 1 > NVS_KEY_NAME_MAX_SIZE
*
* this sprintf() will silently overflow the caller's stack buffer AND
* produce a namespace name that nvs_open() will reject. In that case
* switch to snprintf(buffer, NVS_KEY_NAME_MAX_SIZE, ...) and propagate
* the truncation as an error to callers.
*
* Callers (keep this list in sync if a new one is added):
* - cacheOpen() [open by current hash]
* - bta_gattc_co_cache_addr_save() [erase old namespace on hash change]
*/
static void getFilename(char *buffer, hash_key_t hash)
{
sprintf(buffer, "%s%02x%02x%02x%02x", GATT_CACHE_PREFIX,
@@ -107,6 +124,9 @@ static void getFilename(char *buffer, hash_key_t hash)
static void cacheClose(BD_ADDR bda)
{
UINT8 index = 0;
if (cache_env == NULL) {
return;
}
if ((index = bta_gattc_co_find_addr_in_cache(bda)) != INVALID_ADDR_NUM) {
if (cache_env->cache_addr[index].is_open) {
nvs_close(cache_env->cache_addr[index].cache_fp);
@@ -117,8 +137,13 @@ static void cacheClose(BD_ADDR bda)
static bool cacheOpen(BD_ADDR bda, bool to_save, UINT8 *index)
{
if (cache_env == NULL) {
return false;
}
UNUSED(to_save);
char fname[255] = {0};
/* NVS namespace name is limited to (NVS_KEY_NAME_MAX_SIZE - 1) characters.
* getFilename() produces GATT_CACHE_PREFIX (5) + 8 hex chars + NUL = 14 bytes. */
char fname[NVS_KEY_NAME_MAX_SIZE] = {0};
UINT8 *assoc_addr = NULL;
esp_err_t status = ESP_FAIL;
hash_key_t hash_key = {0};
@@ -141,8 +166,9 @@ static bool cacheOpen(BD_ADDR bda, bool to_save, UINT8 *index)
static void cacheReset(BD_ADDR bda, BOOLEAN update)
{
char fname[255] = {0};
getFilename(fname, bda);
if (cache_env == NULL) {
return;
}
UINT8 index = 0;
//cache_env->cache_addr
if ((index = bta_gattc_co_find_addr_in_cache(bda)) != INVALID_ADDR_NUM) {
@@ -153,18 +179,21 @@ static void cacheReset(BD_ADDR bda, BOOLEAN update)
nvs_close(cache_env->cache_addr[index].cache_fp);
cache_env->cache_addr[index].is_open = FALSE;
} else {
cacheOpen(bda, false, &index);
if (index == INVALID_ADDR_NUM) {
APPL_TRACE_ERROR("%s INVALID ADDR NUM", __func__);
return;
}
/* The entry exists but is not currently held open in this session;
* try to (re)open it best-effort so we can erase the on-flash blob.
* The recursive cache_env lock is held throughout, so cacheOpen()'s
* internal find_addr_in_cache(bda) cannot disagree with the outer
* find above, i.e. *index will remain valid here. We deliberately
* do NOT bail out on cacheOpen() failure: the entry must still be
* removed from RAM to keep num_addr/cache_addr[] consistent and to
* avoid OOB in callers. */
(void)cacheOpen(bda, false, &index);
if (cache_env->cache_addr[index].is_open) {
nvs_erase_all(cache_env->cache_addr[index].cache_fp);
nvs_close(cache_env->cache_addr[index].cache_fp);
cache_env->cache_addr[index].is_open = FALSE;
} else {
APPL_TRACE_ERROR("%s cacheOpen failed", __func__);
return;
APPL_TRACE_ERROR("%s: cacheOpen fail, evict RAM", __func__);
}
}
if(cache_env->num_addr == 0) {
@@ -180,6 +209,10 @@ static void cacheReset(BD_ADDR bda, BOOLEAN update)
cache_env->cache_addr[index].assoc_addr = NULL;
}
if (cache_env->num_addr > MAX_DEVICE_IN_CACHE) {
APPL_TRACE_WARNING("%s: num_addr %u exceeds max, clamping", __func__, cache_env->num_addr);
cache_env->num_addr = MAX_DEVICE_IN_CACHE;
}
UINT8 num = cache_env->num_addr;
//delete the server_bda in the addr_info list.
for(UINT8 i = index; i < (num - 1); i++) {
@@ -231,7 +264,6 @@ static void cacheReset(BD_ADDR bda, BOOLEAN update)
}
}
#endif /* BT_SUPPORT_NVM */
/*****************************************************************************
** Function Declarations
*****************************************************************************/
@@ -253,13 +285,19 @@ static void cacheReset(BD_ADDR bda, BOOLEAN update)
*******************************************************************************/
tBTA_GATT_STATUS bta_gattc_co_cache_open(BD_ADDR server_bda, BOOLEAN to_save, UINT8 *index)
{
cache_env_lock();
/* open NV cache and send call in */
tBTA_GATT_STATUS status = BTA_GATT_OK;
if (cache_env == NULL) {
cache_env_unlock();
return BTA_GATT_ERROR;
}
if (!cacheOpen(server_bda, to_save, index)) {
status = BTA_GATT_ERROR;
}
APPL_TRACE_DEBUG("%s() - status=%d", __func__, status);
cache_env_unlock();
return status;
}
@@ -280,11 +318,22 @@ tBTA_GATT_STATUS bta_gattc_co_cache_open(BD_ADDR server_bda, BOOLEAN to_save, UI
*******************************************************************************/
tBTA_GATT_STATUS bta_gattc_co_cache_load(tBTA_GATTC_NV_ATTR *attr, UINT8 index)
{
cache_env_lock();
#if (!CONFIG_BT_STACK_NO_LOG)
UINT16 num_attr = 0;
#endif
tBTA_GATT_STATUS status = BTA_GATT_ERROR;
size_t length = 0;
if (cache_env == NULL) {
cache_env_unlock();
return BTA_GATT_ERROR;
}
if (index >= MAX_DEVICE_IN_CACHE) {
cache_env_unlock();
return BTA_GATT_ERROR;
}
// Read the size of memory space required for blob
nvs_get_blob(cache_env->cache_addr[index].cache_fp, cache_key, NULL, &length);
// Read previously saved blob if available
@@ -296,18 +345,28 @@ tBTA_GATT_STATUS bta_gattc_co_cache_load(tBTA_GATTC_NV_ATTR *attr, UINT8 index)
APPL_TRACE_DEBUG("%s() - read=%d, status=%d, err_code = %d",
__func__, num_attr, status, err_code);
cache_env_unlock();
return status;
}
size_t bta_gattc_get_cache_attr_length(UINT8 index)
{
cache_env_lock();
size_t length = 0;
if (index == INVALID_ADDR_NUM) {
if (cache_env == NULL) {
cache_env_unlock();
return 0;
}
if (index == INVALID_ADDR_NUM || index >= MAX_DEVICE_IN_CACHE) {
cache_env_unlock();
return 0;
}
// Read the size of memory space required for blob
nvs_get_blob(cache_env->cache_addr[index].cache_fp, cache_key, NULL, &length);
cache_env_unlock();
return length;
}
@@ -330,6 +389,13 @@ size_t bta_gattc_get_cache_attr_length(UINT8 index)
void bta_gattc_co_cache_save (BD_ADDR server_bda, UINT16 num_attr,
tBTA_GATTC_NV_ATTR *p_attr_list)
{
cache_env_lock();
if (cache_env == NULL) {
cache_env_unlock();
return;
}
tBTA_GATT_STATUS status = BTA_GATT_OK;
hash_key_t hash_key = {0};
UINT8 index = INVALID_ADDR_NUM;
@@ -350,6 +416,7 @@ void bta_gattc_co_cache_save (BD_ADDR server_bda, UINT16 num_attr,
(void) status;
#endif
APPL_TRACE_DEBUG("%s() wrote hash_key = %x%x%x%x, num_attr = %d, status = %d.", __func__, hash_key[0], hash_key[1], hash_key[2], hash_key[3], num_attr, status);
cache_env_unlock();
}
/*******************************************************************************
@@ -367,14 +434,14 @@ void bta_gattc_co_cache_save (BD_ADDR server_bda, UINT16 num_attr,
*******************************************************************************/
void bta_gattc_co_cache_close(BD_ADDR server_bda, UINT16 conn_id)
{
cache_env_lock();
UNUSED(conn_id);
//#ifdef BT_SUPPORT_NVM
cacheClose(server_bda);
//#endif /* BT_SUPPORT_NVM */
/* close NV when server cache is done saving or loading,
does not need to do anything for now on Insight */
BTIF_TRACE_DEBUG("%s()", __FUNCTION__);
cache_env_unlock();
}
/*******************************************************************************
@@ -391,18 +458,22 @@ void bta_gattc_co_cache_close(BD_ADDR server_bda, UINT16 conn_id)
*******************************************************************************/
void bta_gattc_co_cache_reset(BD_ADDR server_bda)
{
cache_env_lock();
cacheReset(server_bda, TRUE);
cache_env_unlock();
}
void bta_gattc_co_cache_addr_init(void)
{
cache_env_mutex_init_once();
cache_env_lock();
nvs_handle_t fp;
esp_err_t err_code;
UINT8 num_addr;
size_t length = MAX_ADDR_LIST_CACHE_BUF;
UINT8 *p_buf = osi_malloc(MAX_ADDR_LIST_CACHE_BUF);
if (p_buf == NULL) {
APPL_TRACE_ERROR("%s malloc failed!", __func__);
cache_env_unlock();
return;
}
@@ -410,6 +481,7 @@ void bta_gattc_co_cache_addr_init(void)
if (cache_env == NULL) {
APPL_TRACE_ERROR("%s malloc failed!", __func__);
osi_free(p_buf);
cache_env_unlock();
return;
}
@@ -420,19 +492,53 @@ void bta_gattc_co_cache_addr_init(void)
cache_env->is_open = TRUE;
// Read previously saved blob if available
if ((err_code = nvs_get_blob(fp, cache_key, p_buf, &length)) != ESP_OK) {
if(err_code != ESP_ERR_NVS_NOT_FOUND) {
if (err_code == ESP_ERR_NVS_NOT_FOUND) {
length = 0;
} else {
APPL_TRACE_ERROR("%s, Line = %d, nvs flash get blob data fail, err_code = 0x%x", __func__, __LINE__, err_code);
osi_free(p_buf);
if (cache_env->is_open) {
nvs_close(cache_env->addr_fp);
cache_env->is_open = FALSE;
}
osi_free(cache_env);
cache_env = NULL;
cache_env_unlock();
return;
}
}
const size_t rec_sz = sizeof(BD_ADDR) + sizeof(hash_key_t);
if (length == 0) {
cache_env->num_addr = 0;
osi_free(p_buf);
cache_env_unlock();
return;
}
num_addr = length / (sizeof(BD_ADDR) + sizeof(hash_key_t));
cache_env->num_addr = num_addr;
if ((length % rec_sz) != 0) {
APPL_TRACE_ERROR("%s: bad blob len %zu", __func__, length);
(void)nvs_erase_key(fp, cache_key);
cache_env->num_addr = 0;
osi_free(p_buf);
if (cache_env->is_open) {
nvs_close(cache_env->addr_fp);
cache_env->is_open = FALSE;
}
osi_free(cache_env);
cache_env = NULL;
cache_env_unlock();
return;
}
size_t n_entries = length / rec_sz;
const BOOLEAN truncated = (n_entries > (size_t)MAX_DEVICE_IN_CACHE) ? TRUE : FALSE;
if (truncated) {
APPL_TRACE_WARNING("%s: trunc %zu->%d", __func__, n_entries, MAX_DEVICE_IN_CACHE);
n_entries = MAX_DEVICE_IN_CACHE;
}
cache_env->num_addr = (UINT8)n_entries;
//read the address from nvs flash to cache address list.
for (UINT8 i = 0; i < num_addr; i++) {
memcpy(cache_env->cache_addr[i].addr, p_buf + i*(sizeof(BD_ADDR) + sizeof(hash_key_t)), sizeof(BD_ADDR));
memcpy(cache_env->cache_addr[i].hash_key,
p_buf + i*(sizeof(BD_ADDR) + sizeof(hash_key_t)) + sizeof(BD_ADDR), sizeof(hash_key_t));
for (UINT8 i = 0; i < cache_env->num_addr; i++) {
memcpy(cache_env->cache_addr[i].addr, p_buf + i * rec_sz, sizeof(BD_ADDR));
memcpy(cache_env->cache_addr[i].hash_key, p_buf + i * rec_sz + sizeof(BD_ADDR), sizeof(hash_key_t));
APPL_TRACE_DEBUG("cache_addr[%x] = %x:%x:%x:%x:%x:%x", i, cache_env->cache_addr[i].addr[0], cache_env->cache_addr[i].addr[1], cache_env->cache_addr[i].addr[2],
cache_env->cache_addr[i].addr[3], cache_env->cache_addr[i].addr[4], cache_env->cache_addr[i].addr[5]);
@@ -440,21 +546,30 @@ void bta_gattc_co_cache_addr_init(void)
cache_env->cache_addr[i].hash_key[2], cache_env->cache_addr[i].hash_key[3]);
bta_gattc_co_cache_new_assoc_list(cache_env->cache_addr[i].addr, i);
}
if (truncated) {
UINT16 out_len = (UINT16)(cache_env->num_addr * rec_sz);
if (nvs_set_blob(fp, cache_key, p_buf, out_len) != ESP_OK) {
APPL_TRACE_WARNING("%s: nvs trunc fail", __func__);
}
}
} else {
APPL_TRACE_ERROR("%s, Line = %d, nvs flash open fail, err_code = %x", __func__, __LINE__, err_code);
osi_free(p_buf);
osi_free(cache_env);
cache_env = NULL;
cache_env_unlock();
return;
}
osi_free(p_buf);
return;
cache_env_unlock();
}
void bta_gattc_co_cache_addr_deinit(void)
{
cache_env_lock();
if(cache_env == NULL) {
cache_env_unlock();
return;
}
@@ -463,112 +578,222 @@ void bta_gattc_co_cache_addr_deinit(void)
if (!cache_env->is_open) {
osi_free(cache_env);
cache_env = NULL;
cache_env_unlock();
return;
}
nvs_close(cache_env->addr_fp);
cache_env->is_open = false;
for(UINT8 i = 0; i< cache_env->num_addr; i++) {
UINT8 num = cache_env->num_addr;
if (num > MAX_DEVICE_IN_CACHE) {
num = MAX_DEVICE_IN_CACHE;
}
for (UINT8 i = 0; i < num; i++) {
cache_addr_info_t *addr_info = &cache_env->cache_addr[i];
if(addr_info) {
if (addr_info->is_open) {
nvs_close(addr_info->cache_fp);
addr_info->is_open = false;
if(addr_info->assoc_addr) {
list_free(addr_info->assoc_addr);
}
}
if (addr_info->assoc_addr != NULL) {
list_free(addr_info->assoc_addr);
addr_info->assoc_addr = NULL;
}
}
osi_free(cache_env);
cache_env = NULL;
cache_env_unlock();
}
BOOLEAN bta_gattc_co_addr_in_cache(BD_ADDR bda)
{
cache_env_lock();
if (cache_env == NULL) {
cache_env_unlock();
return FALSE;
}
UINT8 addr_index = 0;
UINT8 num = cache_env->num_addr;
if (num > MAX_DEVICE_IN_CACHE) {
num = MAX_DEVICE_IN_CACHE;
}
cache_addr_info_t *addr_info = &cache_env->cache_addr[0];
for (addr_index = 0; addr_index < num; addr_index++) {
for (addr_index = 0; addr_index < num; addr_index++, addr_info++) {
if (!memcmp(addr_info->addr, bda, sizeof(BD_ADDR))) {
cache_env_unlock();
return TRUE;
}
}
cache_env_unlock();
return FALSE;
}
UINT8 bta_gattc_co_find_addr_in_cache(BD_ADDR bda)
{
cache_env_lock();
if (cache_env == NULL) {
cache_env_unlock();
return INVALID_ADDR_NUM;
}
UINT8 addr_index = 0;
UINT8 num = cache_env->num_addr;
if (num > MAX_DEVICE_IN_CACHE) {
num = MAX_DEVICE_IN_CACHE;
}
cache_addr_info_t *addr_info = &cache_env->cache_addr[0];
for (addr_index = 0; addr_index < num; addr_index++, addr_info++) {
if (!memcmp(addr_info->addr, bda, sizeof(BD_ADDR))) {
cache_env_unlock();
return addr_index;
}
}
cache_env_unlock();
return INVALID_ADDR_NUM;
}
UINT8 bta_gattc_co_find_hash_in_cache(hash_key_t hash_key)
{
cache_env_lock();
if (cache_env == NULL) {
cache_env_unlock();
return INVALID_ADDR_NUM;
}
UINT8 index = 0;
UINT8 num = cache_env->num_addr;
if (num > MAX_DEVICE_IN_CACHE) {
num = MAX_DEVICE_IN_CACHE;
}
cache_addr_info_t *addr_info = &cache_env->cache_addr[0];
for (index = 0; index < num; index++) {
for (index = 0; index < num; index++, addr_info++) {
if (!memcmp(addr_info->hash_key, hash_key, sizeof(hash_key_t))) {
cache_env_unlock();
return index;
}
}
cache_env_unlock();
return INVALID_ADDR_NUM;
}
UINT8 bta_gattc_co_get_addr_num(void)
{
cache_env_lock();
if (cache_env == NULL) {
cache_env_unlock();
return 0;
}
return cache_env->num_addr;
if (cache_env->num_addr > MAX_DEVICE_IN_CACHE) {
cache_env_unlock();
return MAX_DEVICE_IN_CACHE;
}
UINT8 n = cache_env->num_addr;
cache_env_unlock();
return n;
}
void bta_gattc_co_get_addr_list(BD_ADDR *addr_list)
{
cache_env_lock();
if (cache_env == NULL || addr_list == NULL) {
cache_env_unlock();
return;
}
UINT8 num = cache_env->num_addr;
if (num > MAX_DEVICE_IN_CACHE) {
num = MAX_DEVICE_IN_CACHE;
}
for (UINT8 i = 0; i < num; i++) {
memcpy(addr_list[i], cache_env->cache_addr[i].addr, sizeof(BD_ADDR));
}
cache_env_unlock();
}
void bta_gattc_co_cache_addr_save(BD_ADDR bd_addr, hash_key_t hash_key)
{
cache_env_lock();
if (cache_env == NULL) {
cache_env_unlock();
return;
}
esp_err_t err_code;
UINT8 index = 0;
UINT8 new_index = cache_env->num_addr;
UINT8 *p_buf = osi_malloc(MAX_ADDR_LIST_CACHE_BUF);
if (p_buf == NULL) {
APPL_TRACE_ERROR("%s malloc failed!", __func__);
cache_env_unlock();
return;
}
if (cache_env->num_addr > MAX_DEVICE_IN_CACHE) {
APPL_TRACE_WARNING("%s: num_addr %u exceeds max, clamping", __func__, cache_env->num_addr);
cache_env->num_addr = MAX_DEVICE_IN_CACHE;
}
// check the address list has the same address or not
// for the same address, it's hash key may be change due to service change
if ((index = bta_gattc_co_find_addr_in_cache(bd_addr)) != INVALID_ADDR_NUM) {
APPL_TRACE_DEBUG("%s the bd_addr already in the cache list, index = %x", __func__, index);
/* If the hash key changed (service change on the same peer), the
* per-device NVS namespace is keyed by the OLD hash. Just overwriting
* the in-RAM hash would leave cache_fp/is_open pointing at the old
* namespace, so a subsequent cacheOpen() would short-circuit on
* is_open==TRUE and the new attribute blob would be written into the
* stale namespace. After reboot the addr table maps bd_addr to the
* NEW hash and the load path would miss (and the old namespace is
* orphaned in NVS). Erase the old namespace and clear is_open so
* the next cacheOpen() reopens with the new hash-derived filename. */
if (memcmp(cache_env->cache_addr[index].hash_key, hash_key, sizeof(hash_key_t)) != 0) {
APPL_TRACE_WARNING("%s: hash chg "MACSTR" %02x%02x%02x%02x->%02x%02x%02x%02x, erase NVS",
__func__, MAC2STR(bd_addr),
cache_env->cache_addr[index].hash_key[0], cache_env->cache_addr[index].hash_key[1],
cache_env->cache_addr[index].hash_key[2], cache_env->cache_addr[index].hash_key[3],
hash_key[0], hash_key[1], hash_key[2], hash_key[3]);
if (cache_env->cache_addr[index].is_open) {
(void)nvs_erase_all(cache_env->cache_addr[index].cache_fp);
nvs_close(cache_env->cache_addr[index].cache_fp);
cache_env->cache_addr[index].is_open = FALSE;
} else {
/* Not currently held open in this session; transiently open
* the old namespace just to erase its blob. Best-effort:
* ignore failures so a missing/corrupt old namespace does
* not block writing the new one. */
char fname_old[NVS_KEY_NAME_MAX_SIZE] = {0};
nvs_handle_t old_fp;
getFilename(fname_old, cache_env->cache_addr[index].hash_key);
if (nvs_open(fname_old, NVS_READWRITE, &old_fp) == ESP_OK) {
(void)nvs_erase_all(old_fp);
nvs_close(old_fp);
}
}
}
//if the bd_addr already in the address list, update the hash key in it.
memcpy(cache_env->cache_addr[index].addr, bd_addr, sizeof(BD_ADDR));
memcpy(cache_env->cache_addr[index].hash_key, hash_key, sizeof(hash_key_t));
} else {
if (cache_env->num_addr >= MAX_DEVICE_IN_CACHE) {
while (cache_env->num_addr >= MAX_DEVICE_IN_CACHE) {
APPL_TRACE_WARNING("%s cache list full and remove the oldest addr info", __func__);
UINT8 before = cache_env->num_addr;
cacheReset(cache_env->cache_addr[0].addr, FALSE);
if (cache_env->num_addr >= before) {
APPL_TRACE_ERROR("%s: cache eviction failed", __func__);
osi_free(p_buf);
cache_env_unlock();
return;
}
}
new_index = cache_env->num_addr;
assert(new_index < MAX_DEVICE_IN_CACHE);
if (new_index >= MAX_DEVICE_IN_CACHE) {
APPL_TRACE_ERROR("%s: invalid new_index %u", __func__, new_index);
osi_free(p_buf);
cache_env_unlock();
return;
}
memcpy(cache_env->cache_addr[new_index].addr, bd_addr, sizeof(BD_ADDR));
memcpy(cache_env->cache_addr[new_index].hash_key, hash_key, sizeof(hash_key_t));
cache_env->num_addr++;
@@ -603,22 +828,45 @@ void bta_gattc_co_cache_addr_save(BD_ADDR bd_addr, hash_key_t hash_key)
//free the buffer after used.
osi_free(p_buf);
return;
cache_env_unlock();
}
BOOLEAN bta_gattc_co_cache_new_assoc_list(BD_ADDR src_addr, UINT8 index)
{
cache_env_lock();
if (cache_env == NULL) {
cache_env_unlock();
return FALSE;
}
UNUSED(src_addr);
if (index >= MAX_DEVICE_IN_CACHE) {
cache_env_unlock();
return FALSE;
}
cache_addr_info_t *addr_info = &cache_env->cache_addr[index];
/* Idempotent: if a list already exists at this slot (e.g. caller invoked
* us twice on the same index), free it first so we don't leak the prior
* list_t. The current sole caller is bta_gattc_co_cache_addr_init() which
* runs after a fresh memset, so this path is normally a no-op; the guard
* just keeps the function safe to reuse. */
if (addr_info->assoc_addr != NULL) {
list_free(addr_info->assoc_addr);
addr_info->assoc_addr = NULL;
}
addr_info->assoc_addr = list_new(osi_free_func);
return (addr_info->assoc_addr != NULL ? TRUE : FALSE);
BOOLEAN ok = (addr_info->assoc_addr != NULL ? TRUE : FALSE);
cache_env_unlock();
return ok;
}
BOOLEAN bta_gattc_co_cache_append_assoc_addr(BD_ADDR src_addr, BD_ADDR assoc_addr)
{
cache_env_lock();
UINT8 addr_index = 0;
cache_addr_info_t *addr_info;
UINT8 *p_assoc_buf = osi_malloc(sizeof(BD_ADDR));
if(!p_assoc_buf) {
cache_env_unlock();
return FALSE;
}
memcpy(p_assoc_buf, assoc_addr, sizeof(BD_ADDR));
@@ -630,6 +878,7 @@ BOOLEAN bta_gattc_co_cache_append_assoc_addr(BD_ADDR src_addr, BD_ADDR assoc_add
if (addr_info->assoc_addr == NULL) {
APPL_TRACE_ERROR("assoc_addr list creation failed");
osi_free(p_assoc_buf);
cache_env_unlock();
return FALSE;
}
@@ -638,6 +887,7 @@ BOOLEAN bta_gattc_co_cache_append_assoc_addr(BD_ADDR src_addr, BD_ADDR assoc_add
if (!memcmp(list_node(sn), assoc_addr, sizeof(BD_ADDR))) {
APPL_TRACE_WARNING("Association already exists");
osi_free(p_assoc_buf);
cache_env_unlock();
return TRUE;
}
}
@@ -645,19 +895,23 @@ BOOLEAN bta_gattc_co_cache_append_assoc_addr(BD_ADDR src_addr, BD_ADDR assoc_add
if (!list_append(addr_info->assoc_addr, p_assoc_buf)) {
APPL_TRACE_ERROR("Failed to append to assoc_addr list");
osi_free(p_assoc_buf);
cache_env_unlock();
return FALSE;
}
cache_env_unlock();
return TRUE;
} else {
osi_free(p_assoc_buf);
}
cache_env_unlock();
return FALSE;
}
BOOLEAN bta_gattc_co_cache_remove_assoc_addr(BD_ADDR src_addr, BD_ADDR assoc_addr)
{
cache_env_lock();
UINT8 addr_index = 0;
cache_addr_info_t *addr_info;
if ((addr_index = bta_gattc_co_find_addr_in_cache(src_addr)) != INVALID_ADDR_NUM) {
@@ -667,20 +921,34 @@ BOOLEAN bta_gattc_co_cache_remove_assoc_addr(BD_ADDR src_addr, BD_ADDR assoc_add
sn != list_end(addr_info->assoc_addr); sn = list_next(sn)) {
void *addr = list_node(sn);
if (!memcmp(addr, assoc_addr, sizeof(BD_ADDR))) {
return list_remove(addr_info->assoc_addr, addr);
BOOLEAN removed = list_remove(addr_info->assoc_addr, addr);
cache_env_unlock();
return removed;
}
}
//return list_remove(addr_info->assoc_addr, assoc_addr);
} else {
cache_env_unlock();
return FALSE;
}
}
cache_env_unlock();
return FALSE;
}
UINT8* bta_gattc_co_cache_find_src_addr(BD_ADDR assoc_addr, UINT8 *index)
{
cache_env_lock();
if (index == NULL) {
cache_env_unlock();
return NULL;
}
if (cache_env == NULL) {
*index = INVALID_ADDR_NUM;
cache_env_unlock();
return NULL;
}
UINT8 num = (cache_env->num_addr > MAX_DEVICE_IN_CACHE) ? MAX_DEVICE_IN_CACHE : cache_env->num_addr;
cache_addr_info_t *addr_info = &cache_env->cache_addr[0];
UINT8 *addr_data;
@@ -695,30 +963,37 @@ UINT8* bta_gattc_co_cache_find_src_addr(BD_ADDR assoc_addr, UINT8 *index)
addr_data = (UINT8 *)list_node(node);
if (!memcmp(addr_data, assoc_addr, sizeof(BD_ADDR))) {
*index = i;
return (UINT8 *)addr_info->addr;
UINT8 *ret = (UINT8 *)addr_info->addr;
cache_env_unlock();
return ret;
}
}
addr_info++;
}
*index = INVALID_ADDR_NUM;
cache_env_unlock();
return NULL;
}
BOOLEAN bta_gattc_co_cache_clear_assoc_addr(BD_ADDR src_addr)
{
cache_env_lock();
UINT8 addr_index = 0;
cache_addr_info_t *addr_info;
if ((addr_index = bta_gattc_co_find_addr_in_cache(src_addr)) != INVALID_ADDR_NUM) {
addr_info = &cache_env->cache_addr[addr_index];
if (addr_info->assoc_addr != NULL) {
list_clear(addr_info->assoc_addr);
cache_env_unlock();
return TRUE;
} else {
cache_env_unlock();
return FALSE;
}
return TRUE;
}
cache_env_unlock();
return FALSE;
}
@@ -491,6 +491,12 @@ static char *gattc_evt_code(tBTA_GATTC_INT_EVT evt_code)
return "BTA_GATTC_API_READ_BY_TYPE_EVT";
case BTA_GATTC_API_READ_MULTI_VAR_EVT:
return "BTA_GATTC_API_READ_MULTI_VAR_EVT";
case BTA_GATTC_ENC_CMPL_EVT:
return "BTA_GATTC_ENC_CMPL_EVT";
case BTA_GATTC_API_CACHE_ASSOC_EVT:
return "BTA_GATTC_API_CACHE_ASSOC_EVT";
case BTA_GATTC_API_CACHE_GET_ADDR_LIST_EVT:
return "BTA_GATTC_API_CACHE_GET_ADDR_LIST_EVT";
default:
return "unknown GATTC event code";
}
@@ -541,7 +547,8 @@ uint8_t bta_gattc_cl_rcb_active_count(void)
for (uint8_t i = 0; i < BTA_GATTC_CL_MAX; i ++) {
if (bta_gattc_cb.cl_rcb[i].in_use &&
memcmp(bta_gattc_cb.cl_rcb[i].app_uuid.uu.uuid128, dm_gattc_uuid, 16)) {
(bta_gattc_cb.cl_rcb[i].app_uuid.len != LEN_UUID_128 ||
memcmp(bta_gattc_cb.cl_rcb[i].app_uuid.uu.uuid128, dm_gattc_uuid, LEN_UUID_128))) {
count++;
}
}
@@ -154,9 +154,12 @@ tBTA_GATTC_CLCB *bta_gattc_find_clcb_by_conn_id (UINT16 conn_id)
tBTA_GATTC_CLCB *p_clcb = &bta_gattc_cb.clcb[0];
UINT8 i;
if (conn_id == 0 || conn_id == GATT_INVALID_CONN_ID) {
return NULL;
}
for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++, p_clcb ++) {
if (p_clcb->in_use &&
p_clcb->bta_conn_id == conn_id) {
if (p_clcb->in_use && p_clcb->bta_conn_id == conn_id) {
return p_clcb;
}
}
@@ -342,7 +345,7 @@ tBTA_GATTC_SERV *bta_gattc_find_srvr_cache(BD_ADDR bda)
UINT8 i;
for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_srcb ++) {
if (bdcmp(p_srcb->server_bda, bda) == 0) {
if (p_srcb->in_use && bdcmp(p_srcb->server_bda, bda) == 0) {
return p_srcb;
}
}
@@ -387,7 +390,7 @@ tBTA_GATTC_SERV *bta_gattc_srcb_alloc(BD_ADDR bda)
if (!p_tcb->in_use) {
found = TRUE;
break;
} else if (!p_tcb->connected) {
} else if (!p_tcb->connected && p_tcb->num_clcb == 0) {
p_recycle = p_tcb;
}
}
@@ -417,6 +420,38 @@ tBTA_GATTC_SERV *bta_gattc_srcb_alloc(BD_ADDR bda)
return p_tcb;
}
/******************************************************************************
*
* Fixed-length prefix size of a GATTC API message in the heap buffer passed
* to bta_gattc_enqueue. Must match osi_malloc sizes in bta_gattc_api.c.
* Variable payloads (write value, search UUID) are copied separately.
*
******************************************************************************/
static size_t bta_gattc_enqueue_api_fixed_size(UINT16 event)
{
switch (event) {
case BTA_GATTC_API_READ_EVT:
case BTA_GATTC_API_READ_BY_TYPE_EVT:
return sizeof(tBTA_GATTC_API_READ);
case BTA_GATTC_API_WRITE_EVT:
return sizeof(tBTA_GATTC_API_WRITE);
case BTA_GATTC_API_EXEC_EVT:
return sizeof(tBTA_GATTC_API_EXEC);
case BTA_GATTC_API_CFG_MTU_EVT:
return sizeof(tBTA_GATTC_API_CFG_MTU);
case BTA_GATTC_API_SEARCH_EVT:
return sizeof(tBTA_GATTC_API_SEARCH);
case BTA_GATTC_API_CONFIRM_EVT:
return sizeof(tBTA_GATTC_API_CONFIRM);
case BTA_GATTC_API_READ_MULTI_EVT:
case BTA_GATTC_API_READ_MULTI_VAR_EVT:
return sizeof(tBTA_GATTC_API_READ_MULTI);
default:
APPL_TRACE_ERROR("%s: unexpected event 0x%x", __func__, event);
return 0;
}
}
static BOOLEAN bta_gattc_has_prepare_command_in_queue(tBTA_GATTC_CLCB *p_clcb)
{
assert(p_clcb != NULL);
@@ -485,14 +520,29 @@ BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
if (p_data->hdr.event == BTA_GATTC_API_WRITE_EVT) {
len = p_data->api_write.len;
if ((cmd_data = (tBTA_GATTC_DATA *)osi_malloc(sizeof(tBTA_GATTC_DATA) + len)) != NULL) {
memset(cmd_data, 0, sizeof(tBTA_GATTC_DATA) + len);
memcpy(cmd_data, p_data, sizeof(tBTA_GATTC_DATA));
cmd_data->api_write.p_value = (UINT8 *)(cmd_data + 1);
memcpy(cmd_data->api_write.p_value, p_data->api_write.p_value, len);
if (len > 0) {
if (p_data->api_write.p_value == NULL) {
APPL_TRACE_ERROR("%s(), write len=%u but p_value is NULL", __func__, len);
return FALSE;
}
if ((cmd_data = (tBTA_GATTC_DATA *)osi_malloc(sizeof(tBTA_GATTC_DATA) + len)) != NULL) {
memset(cmd_data, 0, sizeof(tBTA_GATTC_DATA) + len);
memcpy(cmd_data, p_data, sizeof(tBTA_GATTC_API_WRITE));
cmd_data->api_write.p_value = (UINT8 *)(cmd_data + 1);
memcpy(cmd_data->api_write.p_value, p_data->api_write.p_value, len);
} else {
APPL_TRACE_ERROR("%s(), line = %d, alloc fail, no memory.", __func__, __LINE__);
return FALSE;
}
} else {
APPL_TRACE_ERROR("%s(), line = %d, alloc fail, no memory.", __func__, __LINE__);
return FALSE;
/* len == 0: no payload to copy; keep p_value NULL like BTA_GATTC_API_SEARCH_EVT without UUID */
if ((cmd_data = (tBTA_GATTC_DATA *)osi_malloc(sizeof(tBTA_GATTC_DATA))) != NULL) {
memset(cmd_data, 0, sizeof(tBTA_GATTC_DATA));
memcpy(cmd_data, p_data, sizeof(tBTA_GATTC_API_WRITE));
} else {
APPL_TRACE_ERROR("%s(), line = %d, alloc fail, no memory.", __func__, __LINE__);
return FALSE;
}
}
} else if (p_data->hdr.event == BTA_GATTC_API_SEARCH_EVT) {
/*
@@ -547,7 +597,7 @@ BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
if ((cmd_data = (tBTA_GATTC_DATA *)osi_malloc(len)) != NULL) {
memset(cmd_data, 0, len);
/* Copy the structure */
memcpy(cmd_data, p_data, sizeof(tBTA_GATTC_DATA));
memcpy(cmd_data, p_data, sizeof(tBTA_GATTC_API_SEARCH));
/* Update pointer to point to the space after the structure */
cmd_data->api_search.p_srvc_uuid = (tBT_UUID *)(cmd_data + 1);
/* Copy the UUID data */
@@ -561,16 +611,22 @@ BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
/* p_srvc_uuid is NULL, no extra space needed (search all services) */
if ((cmd_data = (tBTA_GATTC_DATA *)osi_malloc(sizeof(tBTA_GATTC_DATA))) != NULL) {
memset(cmd_data, 0, sizeof(tBTA_GATTC_DATA));
memcpy(cmd_data, p_data, sizeof(tBTA_GATTC_DATA));
memcpy(cmd_data, p_data, sizeof(tBTA_GATTC_API_SEARCH));
} else {
APPL_TRACE_ERROR("%s(), line = %d, alloc fail, no memory.", __func__, __LINE__);
return FALSE;
}
}
} else {
size_t copy_sz = bta_gattc_enqueue_api_fixed_size(p_data->hdr.event);
if (copy_sz == 0) {
APPL_TRACE_ERROR("%s(), line = %d, unknown event for queue copy 0x%x.", __func__, __LINE__,
p_data->hdr.event);
return FALSE;
}
if ((cmd_data = (tBTA_GATTC_DATA *)osi_malloc(sizeof(tBTA_GATTC_DATA))) != NULL) {
memset(cmd_data, 0, sizeof(tBTA_GATTC_DATA));
memcpy(cmd_data, p_data, sizeof(tBTA_GATTC_DATA));
memcpy(cmd_data, p_data, copy_sz);
} else {
APPL_TRACE_ERROR("%s(), line = %d, alloc fail, no memory.", __func__, __LINE__);
return FALSE;
@@ -888,7 +944,10 @@ tBTA_GATTC_CONN *bta_gattc_conn_alloc(BD_ADDR remote_bda)
#if BTA_GATT_DEBUG == TRUE
APPL_TRACE_DEBUG("bta_gattc_conn_alloc: found conn_track[%d] available", i_conn);
#endif
p_conn->in_use = TRUE;
p_conn->in_use = TRUE;
p_conn->svc_change_descr_handle = 0;
p_conn->write_remote_svc_change_ccc_in_progress = FALSE;
p_conn->write_remote_svc_change_ccc_done = FALSE;
bdcpy(p_conn->remote_bda, remote_bda);
return p_conn;
}
@@ -956,6 +1015,9 @@ BOOLEAN bta_gattc_conn_dealloc(BD_ADDR remote_bda)
if (p_conn != NULL) {
p_conn->in_use = FALSE;
p_conn->svc_change_descr_handle = 0;
p_conn->write_remote_svc_change_ccc_in_progress = FALSE;
p_conn->write_remote_svc_change_ccc_done = FALSE;
memset(p_conn->remote_bda, 0, BD_ADDR_LEN);
return TRUE;
}
@@ -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);
@@ -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 {
@@ -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;
@@ -211,6 +211,7 @@ typedef struct {
typedef struct {
BT_HDR hdr;
BD_ADDR remote_bda;
BOOLEAN erase_flash;
} tBTA_GATTC_API_CACHE_REFRESH;
typedef struct {
@@ -399,6 +400,8 @@ typedef struct {
BOOLEAN in_use;
BD_ADDR remote_bda;
UINT16 svc_change_descr_handle;
/* Tracks the in-flight internal write to the Service Changed CCC descriptor */
BOOLEAN write_remote_svc_change_ccc_in_progress;
BOOLEAN write_remote_svc_change_ccc_done;
} tBTA_GATTC_CONN;
@@ -558,7 +561,7 @@ extern void bta_gattc_get_db_with_operation(UINT16 conn_id,
extern void bta_gattc_get_gatt_db(UINT16 conn_id, UINT16 start_handle, UINT16 end_handle, btgatt_db_element_t **db, UINT16 *count);
extern tBTA_GATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV *p_srvc_cb);
extern void bta_gattc_rebuild_cache(tBTA_GATTC_SERV *p_srcv, UINT16 num_attr, tBTA_GATTC_NV_ATTR *attr);
extern tBTA_GATT_STATUS bta_gattc_rebuild_cache(tBTA_GATTC_SERV *p_srcv, UINT16 num_attr, tBTA_GATTC_NV_ATTR *attr);
extern void bta_gattc_cache_save(tBTA_GATTC_SERV *p_srvc_cb, UINT16 conn_id);
extern void bta_gattc_reset_discover_st(tBTA_GATTC_SERV *p_srcb, tBTA_GATT_STATUS status);
@@ -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 */
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -90,6 +90,17 @@ void btc_storage_save(void)
}
#if (BLE_INCLUDED == TRUE)
static bool btc_storage_is_all_zeros(const void *buf, size_t len)
{
const uint8_t *p = (const uint8_t *)buf;
for (size_t i = 0; i < len; i++) {
if (p[i] != 0) {
return false;
}
}
return true;
}
static bt_status_t _btc_storage_add_ble_bonding_key(bt_bdaddr_t *remote_bd_addr,
char *key,
uint8_t key_type,
@@ -158,33 +169,48 @@ static bt_status_t _btc_storage_get_ble_bonding_key(bt_bdaddr_t *remote_bd_addr,
{
bdstr_t bdstr;
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
const char* name;
const char *name;
size_t expected_len;
switch (key_type) {
case BTM_LE_KEY_PENC:
name = BTC_BLE_STORAGE_LE_KEY_PENC_STR;
expected_len = sizeof(tBTM_LE_PENC_KEYS);
break;
case BTM_LE_KEY_PID:
name = BTC_BLE_STORAGE_LE_KEY_PID_STR;
expected_len = sizeof(tBTM_LE_PID_KEYS);
break;
case BTM_LE_KEY_PCSRK:
name = BTC_BLE_STORAGE_LE_KEY_PCSRK_STR;
expected_len = sizeof(tBTM_LE_PCSRK_KEYS);
break;
case BTM_LE_KEY_LENC:
name = BTC_BLE_STORAGE_LE_KEY_LENC_STR;
expected_len = sizeof(tBTM_LE_LENC_KEYS);
break;
case BTM_LE_KEY_LCSRK:
name = BTC_BLE_STORAGE_LE_KEY_LCSRK_STR;
expected_len = sizeof(tBTM_LE_LCSRK_KEYS);
break;
case BTM_LE_KEY_LID:
name = BTC_BLE_STORAGE_LE_KEY_LID_STR;
/* LID is a flag-only key; no payload is persisted. */
name = BTC_BLE_STORAGE_LE_KEY_LID_STR;
expected_len = 0;
break;
default:
return BT_STATUS_FAIL;
}
size_t length = key_length;
int ret = btc_config_get_bin(bdstr, name, (uint8_t *)key_value, &length);
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
if (key_length < 0 || (size_t)key_length < expected_len) {
return BT_STATUS_FAIL;
}
size_t length = (size_t)key_length;
bool ret = btc_config_get_bin(bdstr, name, (uint8_t *)key_value, &length);
if (!ret || length != expected_len) {
return BT_STATUS_FAIL;
}
return BT_STATUS_SUCCESS;
}
bt_status_t btc_storage_get_ble_bonding_key(bt_bdaddr_t *remote_bd_addr,
@@ -237,17 +263,22 @@ static bt_status_t _btc_storage_remove_all_ble_keys(const char *name)
void btc_storage_remove_unused_sections(uint8_t *cur_addr, tBTM_LE_PID_KEYS *del_pid_key)
{
bt_bdaddr_t bd_addr;
uint32_t device_type = 0;
if (del_pid_key == NULL) {
return;
}
// Only use valid static address for de-duplication.
if (btc_storage_is_all_zeros(del_pid_key->static_addr, sizeof(del_pid_key->static_addr))) {
return;
}
btc_config_lock();
const btc_config_section_iter_t *iter = btc_config_section_begin();
while (iter != btc_config_section_end()) {
uint32_t device_type = 0;
//store the next iter, if remove section, then will not loss the point
const char *section = btc_config_section_name(iter);
@@ -276,13 +307,19 @@ void btc_storage_remove_unused_sections(uint8_t *cur_addr, tBTM_LE_PID_KEYS *del
char buffer[sizeof(tBTM_LE_KEY_VALUE)] = {0};
if (_btc_storage_get_ble_bonding_key(&bd_addr, BTM_LE_KEY_PID, buffer, sizeof(tBTM_LE_PID_KEYS)) == BT_STATUS_SUCCESS) {
size_t pid_len = sizeof(tBTM_LE_PID_KEYS);
bool pid_ok = btc_config_get_bin(section, BTC_BLE_STORAGE_LE_KEY_PID_STR, (uint8_t *)buffer, &pid_len);
if (pid_ok && pid_len >= sizeof(tBTM_LE_PID_KEYS)) {
tBTM_LE_PID_KEYS *pid_key = (tBTM_LE_PID_KEYS *) buffer;
iter = btc_config_section_next(iter);
if (memcmp(del_pid_key->static_addr, pid_key->static_addr, 6) == 0 && memcmp(cur_addr, bd_addr.address, 6) != 0 && del_pid_key->addr_type == pid_key->addr_type) {
if (del_pid_key->addr_type == pid_key->addr_type &&
!btc_storage_is_all_zeros(pid_key->static_addr, sizeof(pid_key->static_addr)) &&
memcmp(del_pid_key->static_addr, pid_key->static_addr, sizeof(pid_key->static_addr)) == 0 &&
memcmp(cur_addr, bd_addr.address, sizeof(bd_addr.address)) != 0) {
if (device_type == BT_DEVICE_TYPE_DUMO) {
btc_config_set_int(section, BTC_BLE_STORAGE_DEV_TYPE_STR, BT_DEVICE_TYPE_BREDR);
_btc_storage_remove_all_ble_keys(section);
@@ -308,13 +345,13 @@ void btc_storage_delete_duplicate_ble_devices(void)
char temp_buffer[sizeof(tBTM_LE_KEY_VALUE)] = {0};
tBTM_LE_PID_KEYS *pid_key;
tBTM_LE_PID_KEYS *temp_pid_key;
uint32_t device_type = 0;
bt_bdaddr_t temp_bd_addr;
btc_config_lock();
for (const btc_config_section_iter_t *iter = btc_config_section_begin(); iter != btc_config_section_end();
iter = btc_config_section_next(iter)) {
uint32_t device_type = 0;
const char *name = btc_config_section_name(iter);
if (!string_is_bdaddr(name) ||
@@ -324,27 +361,36 @@ void btc_storage_delete_duplicate_ble_devices(void)
}
string_to_bdaddr(name, &bd_addr);
if (_btc_storage_get_ble_bonding_key(&bd_addr, BTM_LE_KEY_PID, buffer, sizeof(tBTM_LE_PID_KEYS)) == BT_STATUS_SUCCESS)
size_t pid_len = sizeof(tBTM_LE_PID_KEYS);
bool pid_ok = btc_config_get_bin(name, BTC_BLE_STORAGE_LE_KEY_PID_STR, (uint8_t *)buffer, &pid_len);
if (pid_ok && pid_len >= sizeof(tBTM_LE_PID_KEYS))
{
pid_key = (tBTM_LE_PID_KEYS *) buffer;
if (btc_storage_is_all_zeros(pid_key->static_addr, sizeof(pid_key->static_addr))) {
continue;
}
const btc_config_section_iter_t *temp_iter = btc_config_section_next(iter);
while (temp_iter != NULL)
{
uint32_t temp_device_type = 0;
const char *temp_name = btc_config_section_name(temp_iter);
if (!string_is_bdaddr(temp_name) || !btc_config_get_int(temp_name, BTC_BLE_STORAGE_DEV_TYPE_STR, (int *)&device_type) ||
((device_type & BT_DEVICE_TYPE_BLE) != BT_DEVICE_TYPE_BLE)) {
if (!string_is_bdaddr(temp_name) || !btc_config_get_int(temp_name, BTC_BLE_STORAGE_DEV_TYPE_STR, (int *)&temp_device_type) ||
((temp_device_type & BT_DEVICE_TYPE_BLE) != BT_DEVICE_TYPE_BLE)) {
temp_iter = btc_config_section_next(temp_iter);
continue;
}
string_to_bdaddr(temp_name, &temp_bd_addr);
if (_btc_storage_get_ble_bonding_key(&temp_bd_addr, BTM_LE_KEY_PID, temp_buffer, sizeof(tBTM_LE_PID_KEYS)) == BT_STATUS_SUCCESS)
size_t temp_pid_len = sizeof(tBTM_LE_PID_KEYS);
bool temp_pid_ok = btc_config_get_bin(temp_name, BTC_BLE_STORAGE_LE_KEY_PID_STR, (uint8_t *)temp_buffer, &temp_pid_len);
if (temp_pid_ok && temp_pid_len >= sizeof(tBTM_LE_PID_KEYS))
{
temp_pid_key = (tBTM_LE_PID_KEYS *) temp_buffer;
if (memcmp(pid_key->static_addr, temp_pid_key->static_addr, 6) == 0 && pid_key->addr_type == temp_pid_key->addr_type) {
const char *temp_name = btc_config_section_name(temp_iter);
if (pid_key->addr_type == temp_pid_key->addr_type &&
!btc_storage_is_all_zeros(temp_pid_key->static_addr, sizeof(temp_pid_key->static_addr)) &&
memcmp(pid_key->static_addr, temp_pid_key->static_addr, sizeof(pid_key->static_addr)) == 0) {
temp_iter = btc_config_section_next(temp_iter);
if (device_type == BT_DEVICE_TYPE_DUMO) {
if (temp_device_type == BT_DEVICE_TYPE_DUMO) {
btc_config_set_int(temp_name, BTC_BLE_STORAGE_DEV_TYPE_STR, BT_DEVICE_TYPE_BREDR);
_btc_storage_remove_all_ble_keys(temp_name);
} else {
@@ -484,9 +530,11 @@ static bt_status_t _btc_storage_get_ble_local_key(uint8_t key_type,
}
size_t length = key_length;
int ret = btc_config_get_bin(BTC_BLE_STORAGE_LOCAL_ADAPTER_STR, name, (uint8_t *)key_value, &length);
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
bool ret = btc_config_get_bin(BTC_BLE_STORAGE_LOCAL_ADAPTER_STR, name, (uint8_t *)key_value, &length);
if (!ret || length != (size_t)key_length) {
return BT_STATUS_FAIL;
}
return BT_STATUS_SUCCESS;
}
bt_status_t btc_storage_get_ble_local_key(uint8_t key_type,
@@ -905,8 +953,8 @@ static void _btc_read_le_key(const uint8_t key_type, const size_t key_len, bt_bd
}
bt_status_t _btc_storage_in_fetch_bonded_ble_device(const char *remote_bd_addr, int add)
{
uint32_t device_type;
int addr_type;
uint32_t device_type = 0;
int addr_type = BLE_ADDR_PUBLIC;
bt_bdaddr_t bd_addr;
BD_ADDR bta_bd_addr;
bool device_added = false;
@@ -1015,11 +1063,11 @@ bt_status_t btc_storage_get_bonded_ble_devices_list(esp_ble_bond_dev_t *bond_dev
int btc_storage_get_num_ble_bond_devices(void)
{
int num_dev = 0;
uint32_t device_type = 0;
btc_config_lock();
for (const btc_config_section_iter_t *iter = btc_config_section_begin(); iter != btc_config_section_end();
iter = btc_config_section_next(iter)) {
uint32_t device_type = 0;
const char *name = btc_config_section_name(iter);
if (!string_is_bdaddr(name) ||
!btc_config_get_int(name, BTC_BLE_STORAGE_DEV_TYPE_STR, (int *)&device_type) ||
@@ -1037,18 +1085,30 @@ int btc_storage_get_num_ble_bond_devices(void)
bt_status_t btc_storage_get_gatt_cl_supp_feat(bt_bdaddr_t *remote_bd_addr, uint8_t *value, int len)
{
bdstr_t bdstr;
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
int ret = btc_config_get_bin(bdstr, BTC_BLE_STORAGE_GATT_CL_SUPP_FEAT_STR, value, (size_t *)&len);
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
bool ret;
size_t length = len;
btc_config_lock();
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr_t));
ret = btc_config_get_bin(bdstr, BTC_BLE_STORAGE_GATT_CL_SUPP_FEAT_STR, value, &length);
btc_config_unlock();
if (!ret || length != (size_t)len) {
return BT_STATUS_FAIL;
}
return BT_STATUS_SUCCESS;
}
bt_status_t btc_storage_set_gatt_cl_supp_feat(bt_bdaddr_t *remote_bd_addr, uint8_t *value, int len)
{
int ret;
bool ret;
bdstr_t bdstr;
btc_config_lock();
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr_t));
ret = btc_config_set_bin(bdstr, BTC_BLE_STORAGE_GATT_CL_SUPP_FEAT_STR, value, (size_t)len);
if (ret) {
_btc_storage_save();
}
btc_config_unlock();
if (ret == false) {
return BT_STATUS_FAIL;
@@ -1060,18 +1120,33 @@ bt_status_t btc_storage_set_gatt_cl_supp_feat(bt_bdaddr_t *remote_bd_addr, uint8
bt_status_t btc_storage_get_gatt_db_hash(bt_bdaddr_t *remote_bd_addr, uint8_t *value, int len)
{
bdstr_t bdstr;
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
int ret = btc_config_get_bin(bdstr, BTC_BLE_STORAGE_GATT_DB_HASH_STR, value, (size_t *)&len);
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
bool ret;
size_t length = len;
btc_config_lock();
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr_t));
ret = btc_config_get_bin(bdstr, BTC_BLE_STORAGE_GATT_DB_HASH_STR, value, &length);
btc_config_unlock();
if (!ret || length != (size_t)len) {
return BT_STATUS_FAIL;
}
return BT_STATUS_SUCCESS;
}
bt_status_t btc_storage_set_gatt_db_hash(bt_bdaddr_t *remote_bd_addr, uint8_t *value, int len)
{
int ret;
bool ret;
bdstr_t bdstr;
btc_config_lock();
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr_t));
ret = btc_config_set_bin(bdstr, BTC_BLE_STORAGE_GATT_DB_HASH_STR, value, (size_t)len);
if (ret) {
_btc_storage_save();
}
btc_config_unlock();
if (ret == false) {
return BT_STATUS_FAIL;
}
@@ -1084,9 +1159,11 @@ bt_status_t btc_storage_remove_gatt_cl_supp_feat(bt_bdaddr_t *remote_bd_addr)
bool ret = true;
bdstr_t bdstr;
btc_config_lock();
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
ret = btc_config_remove(bdstr, BTC_BLE_STORAGE_GATT_CL_SUPP_FEAT_STR);
btc_config_unlock();
if (ret == false) {
return BT_STATUS_FAIL;
}
@@ -1099,9 +1176,11 @@ bt_status_t btc_storage_remove_gatt_db_hash(bt_bdaddr_t *remote_bd_addr)
bool ret = true;
bdstr_t bdstr;
btc_config_lock();
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
ret = btc_config_remove(bdstr, BTC_BLE_STORAGE_GATT_DB_HASH_STR);
btc_config_unlock();
if (ret == false) {
return BT_STATUS_FAIL;
}
@@ -277,6 +277,7 @@ bool btc_config_set_bin(const char *section, const char *key, const uint8_t *val
config_set_string(config, section, key, str, false);
memset(str, 0, length * 2 + 1);
osi_free(str);
return true;
}
@@ -269,7 +269,7 @@ static void btc_dm_ble_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl)
}
#if BLE_SMP_BOND_NVS_FLASH
int addr_type;
int addr_type = BLE_ADDR_PUBLIC;
if (btc_dm_cb.pairing_cb.ble.is_pid_key_rcvd) {
// delete unused section in NVS
@@ -28,7 +28,7 @@ static void btc_ble_cte_callback(tBTM_BLE_CTE_EVENT event,
{
esp_ble_cte_cb_param_t param = {0};
bt_status_t ret;
btc_msg_t msg;
btc_msg_t msg = {0};
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_BLE_CTE;
@@ -42,7 +42,7 @@ static void btc_ble_cte_callback(tBTM_BLE_CTE_EVENT event,
break;
case BTA_BLE_CTE_SET_TRANS_ENABLE_EVT:
msg.act = ESP_BLE_CTE_SET_CONNLESS_TRANS_ENABLE_CMPL_EVT;
param.set_trans_enable_cmpl.status = btc_btm_status_to_esp_status(params->cte_trans_params_cmpl.status);
param.set_trans_enable_cmpl.status = btc_btm_status_to_esp_status(params->cte_trans_en_cmpl.status);
break;
case BTA_BLE_CTE_SET_IQ_SAMP_ENABLE_EVT:
msg.act = ESP_BLE_CTE_SET_CONNLESS_IQ_SAMPLING_ENABLE_CMPL_EVT;
@@ -100,6 +100,7 @@ static void btc_ble_cte_callback(tBTM_BLE_CTE_EVENT event,
case BTA_BLE_CTE_CONN_IQ_REPORT_EVT:
msg.act = ESP_BLE_CTE_CONN_IQ_REPORT_EVT;
param.conn_iq_rpt.conn_handle = params->cte_conn_iq_rpt.conn_handle;
param.conn_iq_rpt.rx_phy = params->cte_conn_iq_rpt.rx_phy;
param.conn_iq_rpt.data_channel_idx = params->cte_conn_iq_rpt.data_channel_idx;
param.conn_iq_rpt.rssi = params->cte_conn_iq_rpt.rssi;
param.conn_iq_rpt.rssi_ant_id = params->cte_conn_iq_rpt.rssi_ant_id;
@@ -163,6 +164,7 @@ void btc_ble_cte_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
dst->cte_trans_params.antenna_ids = NULL;
}
} else {
dst->cte_trans_params.switching_pattern_len = 0;
dst->cte_trans_params.antenna_ids = NULL;
}
break;
@@ -177,6 +179,7 @@ void btc_ble_cte_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act);
}
} else {
dst->cte_iq_sampling_en.switching_pattern_len = 0;
dst->cte_iq_sampling_en.antenna_ids = NULL;
}
break;
@@ -194,6 +197,7 @@ void btc_ble_cte_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act);
}
} else {
dst->cte_recv_params.switching_pattern_len = 0;
dst->cte_recv_params.antenna_ids = NULL;
}
break;
@@ -208,6 +212,7 @@ void btc_ble_cte_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act);
}
} else {
dst->cte_conn_trans_params.switching_pattern_len = 0;
dst->cte_conn_trans_params.antenna_ids = NULL;
}
break;
@@ -490,7 +490,8 @@ static void btc_ble_start_advertising (esp_ble_adv_params_t *ble_adv_params)
tBLE_BD_ADDR peer_addr;
esp_bt_status_t status = ESP_BT_STATUS_SUCCESS;
if (!BLE_ISVALID_PARAM(ble_adv_params->adv_int_min, BTM_BLE_ADV_INT_MIN, BTM_BLE_ADV_INT_MAX) ||
!BLE_ISVALID_PARAM(ble_adv_params->adv_int_max, BTM_BLE_ADV_INT_MIN, BTM_BLE_ADV_INT_MAX)) {
!BLE_ISVALID_PARAM(ble_adv_params->adv_int_max, BTM_BLE_ADV_INT_MIN, BTM_BLE_ADV_INT_MAX) ||
ble_adv_params->adv_int_min > ble_adv_params->adv_int_max) {
status = ESP_BT_STATUS_PARM_INVALID;
BTC_TRACE_ERROR("Invalid advertisting interval parameters.\n");
}
@@ -563,7 +564,8 @@ static void btc_ble_set_scan_params(esp_ble_scan_params_t *scan_params)
BLE_ISVALID_PARAM(scan_params->own_addr_type, BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_RPA_RANDOM) &&
BLE_ISVALID_PARAM(scan_params->scan_filter_policy, BLE_SCAN_FILTER_ALLOW_ALL, BLE_SCAN_FILTER_ALLOW_WLIST_RPA_DIR) &&
BLE_ISVALID_PARAM(scan_params->scan_duplicate, BLE_SCAN_DUPLICATE_DISABLE, BLE_SCAN_DUPLICATE_MAX -1) &&
(scan_params->scan_type == BTM_BLE_SCAN_MODE_ACTI || scan_params->scan_type == BTM_BLE_SCAN_MODE_PASS)) {
(scan_params->scan_type == BTM_BLE_SCAN_MODE_ACTI || scan_params->scan_type == BTM_BLE_SCAN_MODE_PASS) &&
scan_params->scan_window <= scan_params->scan_interval) {
BTA_DmSetBleScanFilterParams(ESP_DEFAULT_GATT_IF, /*client_if*/
scan_params->scan_interval,
scan_params->scan_window,
@@ -936,7 +938,7 @@ static void btc_read_ble_rssi_cmpl_callback(void *p_data)
static void btc_ble_read_channel_map_callback(void *p_data)
{
tBTA_BLE_CH_MAP_RESULTS *result = (tBTA_BLE_CH_MAP_RESULTS *)p_data;
esp_ble_gap_cb_param_t param;
esp_ble_gap_cb_param_t param = {0};
bt_status_t ret;
btc_msg_t msg = {0};
@@ -1229,7 +1231,14 @@ void btc_ble_5_gap_callback(tBTA_DM_BLE_5_GAP_EVENT event,
#if (BLE_50_EXTEND_SCAN_EN == TRUE)
case BTA_DM_BLE_5_GAP_EXT_ADV_REPORT_EVT:
msg.act = ESP_GAP_BLE_EXT_ADV_REPORT_EVT;
memcpy(&param.ext_adv_report.params, &params->ext_adv_report, sizeof(esp_ble_gap_ext_adv_report_t));
memcpy(&param.ext_adv_report.params, &params->ext_adv_report, sizeof(tBTM_BLE_EXT_ADV_REPORT));
/* The source struct ends with a pointer (UINT8 *adv_data) while the destination
* ends with a fixed array (uint8_t adv_data[251]). The memcpy above leaves the
* raw pointer bytes at the start of adv_data[]. Clear it before copying the real
* advertising payload to avoid leaking stale pointer bytes when adv_data is NULL
* or adv_data_len is smaller than sizeof(void *). */
memset(param.ext_adv_report.params.adv_data, 0,
sizeof(param.ext_adv_report.params.adv_data));
if (params->ext_adv_report.adv_data) {
memcpy(param.ext_adv_report.params.adv_data,
params->ext_adv_report.adv_data, params->ext_adv_report.adv_data_len);
@@ -1483,7 +1492,6 @@ void btc_ble_5_gap_callback(tBTA_DM_BLE_5_GAP_EVENT event,
case BTA_BLE_GAP_CS_READ_LOCAL_SUPP_CAPS_EVT:
msg.act = ESP_GAP_BLE_CS_READ_LOCAL_SUPP_CAPS_EVT;
param.cs_read_local_supp_caps.status = btc_btm_status_to_esp_status(params->cs_read_local_supp_caps.status);
param.cs_read_local_supp_caps.conn_handle = params->cs_read_local_supp_caps.conn_handle;
param.cs_read_local_supp_caps.num_config_supported = params->cs_read_local_supp_caps.num_config_supported;
param.cs_read_local_supp_caps.max_consecutive_proc_supported = params->cs_read_local_supp_caps.max_consecutive_proc_supported;
param.cs_read_local_supp_caps.num_ant_supported = params->cs_read_local_supp_caps.num_ant_supported;
@@ -1648,12 +1656,12 @@ void btc_ble_5_gap_callback(tBTA_DM_BLE_5_GAP_EVENT event,
#endif // #if (BLE_50_FEATURE_SUPPORT == TRUE)
#if ((BLE_42_DTM_TEST_EN == TRUE) || (BLE_50_DTM_TEST_EN == TRUE))
void btc_dtm_tx_start_callback(void *p1)
void btc_dtm_tx_start_callback(UINT8 *p1, UINT16 len)
{
UINT8 status;
UINT8 *p;
p = (UINT8*) p1;
if (p1) {
if (p1 && len >= 1) {
STREAM_TO_UINT8(status, p);
BTC_TRACE_DEBUG("DTM TX start, status 0x%x\n", status);
esp_ble_gap_cb_param_t param;
@@ -1675,13 +1683,13 @@ void btc_dtm_tx_start_callback(void *p1)
}
}
void btc_dtm_rx_start_callback(void *p1)
void btc_dtm_rx_start_callback(UINT8 *p1, UINT16 len)
{
UINT8 status;
UINT8 *p;
p = (UINT8*) p1;
if (p1) {
if (p1 && len >= 1) {
STREAM_TO_UINT8(status, p);
BTC_TRACE_DEBUG("DTM RX start, status 0x%x\n", status);
esp_ble_gap_cb_param_t param;
@@ -1705,13 +1713,13 @@ void btc_dtm_rx_start_callback(void *p1)
#endif // #if ((BLE_42_DTM_TEST_EN == TRUE) || (BLE_50_DTM_TEST_EN == TRUE))
#if ((BLE_42_DTM_TEST_EN == TRUE) || (BLE_50_DTM_TEST_EN == TRUE))
void btc_dtm_stop_callback(void *p1)
void btc_dtm_stop_callback(UINT8 *p1, UINT16 len)
{
UINT8 status;
UINT16 num_pkt;
UINT8 *p;
p = (UINT8*) p1;
if (p1) {
if (p1 && len >= 3) {
STREAM_TO_UINT8(status, p);
STREAM_TO_UINT16(num_pkt, p);
BTC_TRACE_DEBUG("DTM stop, status 0x%x num_pkt %d\n", status, num_pkt);
@@ -1876,6 +1884,13 @@ static void btc_ble_vendor_hci_event_callback(UINT8 subevt_code, UINT8 param_len
btc_msg_t msg = {0};
esp_ble_vendor_evt_param_t *evt_param = &param.vendor_hci_evt.param;
bool copy_param = false;
bool parse_ok = true;
if (param_len && params == NULL) {
BTC_TRACE_WARNING("%s vendor evt NULL: sub=0x%02x len=%u",
__func__, subevt_code, param_len);
return;
}
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_GAP_BLE;
@@ -1887,6 +1902,12 @@ static void btc_ble_vendor_hci_event_callback(UINT8 subevt_code, UINT8 param_len
switch (subevt_code) {
case BLE_VENDOR_PDU_RECV_EVT:
param.vendor_hci_evt.subevt_code = ESP_BLE_VENDOR_PDU_RECV_EVT;
if (param_len < (UINT8)(1 + 1 + 1 + BD_ADDR_LEN)) {
BTC_TRACE_WARNING("%s vendor trunc: sub=0x%02x len=%u<%u",
__func__, subevt_code, param_len, (unsigned)(1 + 1 + 1 + BD_ADDR_LEN));
parse_ok = false;
break;
}
STREAM_TO_UINT8(evt_param->pdu_recv.type, params);
STREAM_TO_UINT8(evt_param->pdu_recv.handle, params);
STREAM_TO_UINT8(evt_param->pdu_recv.addr_type, params);
@@ -1894,6 +1915,12 @@ static void btc_ble_vendor_hci_event_callback(UINT8 subevt_code, UINT8 param_len
break;
case BLE_VENDOR_CHMAP_UPDATE_EVT:
param.vendor_hci_evt.subevt_code = ESP_BLE_VENDOR_CHAN_MAP_UPDATE_EVT;
if (param_len < (UINT8)(1 + 2 + ESP_GAP_BLE_CHANNELS_LEN)) {
BTC_TRACE_WARNING("%s vendor trunc: sub=0x%02x len=%u<%u",
__func__, subevt_code, param_len, (unsigned)(1 + 2 + ESP_GAP_BLE_CHANNELS_LEN));
parse_ok = false;
break;
}
STREAM_TO_UINT8(evt_param->chan_map_update.status, params);
STREAM_TO_UINT16(evt_param->chan_map_update.conn_handle, params);
REVERSE_STREAM_TO_ARRAY(evt_param->chan_map_update.ch_map, params, ESP_GAP_BLE_CHANNELS_LEN);
@@ -1907,6 +1934,17 @@ static void btc_ble_vendor_hci_event_callback(UINT8 subevt_code, UINT8 param_len
break;
}
if (!parse_ok) {
/* Malformed/truncated parameters: keep the mapped esp_ble_vendor_evt_t
* already assigned in the switch (do NOT restore the raw HCI subevent
* code, which is outside esp_ble_vendor_evt_t and would break the
* public API contract). Zero the structured fields and suppress the
* internal raw buffer so the callback delivers a deterministic event;
* the truncation has already been logged above. */
memset(evt_param, 0, sizeof(*evt_param));
copy_param = false;
}
if (copy_param) {
param.vendor_hci_evt.param_len = param_len;
param.vendor_hci_evt.param_buf = (param_len) ? params : NULL;
@@ -2140,20 +2178,38 @@ void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
btc_ble_gap_args_t *src = (btc_ble_gap_args_t *)p_src;
btc_ble_gap_args_t *dst = (btc_ble_gap_args_t *) p_dest;
if (src->cfg_adv_data.adv_data.p_manufacturer_data) {
/* btc_transfer_context() does a shallow memcpy first; always null-out
* pointer fields so deep_free() never frees non-owned memory on OOM. */
dst->cfg_adv_data.adv_data.p_manufacturer_data = NULL;
dst->cfg_adv_data.adv_data.p_service_data = NULL;
dst->cfg_adv_data.adv_data.p_service_uuid = NULL;
if (src->cfg_adv_data.adv_data.p_manufacturer_data && src->cfg_adv_data.adv_data.manufacturer_len) {
dst->cfg_adv_data.adv_data.p_manufacturer_data = osi_malloc(src->cfg_adv_data.adv_data.manufacturer_len);
memcpy(dst->cfg_adv_data.adv_data.p_manufacturer_data, src->cfg_adv_data.adv_data.p_manufacturer_data,
src->cfg_adv_data.adv_data.manufacturer_len);
if (dst->cfg_adv_data.adv_data.p_manufacturer_data) {
memcpy(dst->cfg_adv_data.adv_data.p_manufacturer_data, src->cfg_adv_data.adv_data.p_manufacturer_data,
src->cfg_adv_data.adv_data.manufacturer_len);
} else {
BTC_TRACE_WARNING("%s no mem, manu drop %u", __func__, src->cfg_adv_data.adv_data.manufacturer_len);
}
}
if (src->cfg_adv_data.adv_data.p_service_data) {
if (src->cfg_adv_data.adv_data.p_service_data && src->cfg_adv_data.adv_data.service_data_len) {
dst->cfg_adv_data.adv_data.p_service_data = osi_malloc(src->cfg_adv_data.adv_data.service_data_len);
memcpy(dst->cfg_adv_data.adv_data.p_service_data, src->cfg_adv_data.adv_data.p_service_data, src->cfg_adv_data.adv_data.service_data_len);
if (dst->cfg_adv_data.adv_data.p_service_data) {
memcpy(dst->cfg_adv_data.adv_data.p_service_data, src->cfg_adv_data.adv_data.p_service_data, src->cfg_adv_data.adv_data.service_data_len);
} else {
BTC_TRACE_WARNING("%s no mem, svc_data drop %u", __func__, src->cfg_adv_data.adv_data.service_data_len);
}
}
if (src->cfg_adv_data.adv_data.p_service_uuid) {
if (src->cfg_adv_data.adv_data.p_service_uuid && src->cfg_adv_data.adv_data.service_uuid_len) {
dst->cfg_adv_data.adv_data.p_service_uuid = osi_malloc(src->cfg_adv_data.adv_data.service_uuid_len);
memcpy(dst->cfg_adv_data.adv_data.p_service_uuid, src->cfg_adv_data.adv_data.p_service_uuid, src->cfg_adv_data.adv_data.service_uuid_len);
if (dst->cfg_adv_data.adv_data.p_service_uuid) {
memcpy(dst->cfg_adv_data.adv_data.p_service_uuid, src->cfg_adv_data.adv_data.p_service_uuid, src->cfg_adv_data.adv_data.service_uuid_len);
} else {
BTC_TRACE_WARNING("%s no mem, svc_uuid drop %u", __func__, src->cfg_adv_data.adv_data.service_uuid_len);
}
}
break;
}
@@ -2161,10 +2217,13 @@ void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
btc_ble_gap_args_t *src = (btc_ble_gap_args_t *)p_src;
btc_ble_gap_args_t *dst = (btc_ble_gap_args_t *) p_dest;
dst->cfg_adv_data_raw.raw_adv = NULL;
dst->cfg_adv_data_raw.raw_adv_len = 0;
if (src && src->cfg_adv_data_raw.raw_adv && src->cfg_adv_data_raw.raw_adv_len > 0) {
dst->cfg_adv_data_raw.raw_adv = osi_malloc(src->cfg_adv_data_raw.raw_adv_len);
if (dst->cfg_adv_data_raw.raw_adv) {
memcpy(dst->cfg_adv_data_raw.raw_adv, src->cfg_adv_data_raw.raw_adv, src->cfg_adv_data_raw.raw_adv_len);
dst->cfg_adv_data_raw.raw_adv_len = src->cfg_adv_data_raw.raw_adv_len;
}
}
break;
@@ -2173,10 +2232,13 @@ void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
btc_ble_gap_args_t *src = (btc_ble_gap_args_t *)p_src;
btc_ble_gap_args_t *dst = (btc_ble_gap_args_t *) p_dest;
dst->cfg_scan_rsp_data_raw.raw_scan_rsp = NULL;
dst->cfg_scan_rsp_data_raw.raw_scan_rsp_len = 0;
if (src && src->cfg_scan_rsp_data_raw.raw_scan_rsp && src->cfg_scan_rsp_data_raw.raw_scan_rsp_len > 0) {
dst->cfg_scan_rsp_data_raw.raw_scan_rsp = osi_malloc(src->cfg_scan_rsp_data_raw.raw_scan_rsp_len);
if (dst->cfg_scan_rsp_data_raw.raw_scan_rsp) {
memcpy(dst->cfg_scan_rsp_data_raw.raw_scan_rsp, src->cfg_scan_rsp_data_raw.raw_scan_rsp, src->cfg_scan_rsp_data_raw.raw_scan_rsp_len);
dst->cfg_scan_rsp_data_raw.raw_scan_rsp_len = src->cfg_scan_rsp_data_raw.raw_scan_rsp_len;
}
}
break;
@@ -2187,6 +2249,7 @@ void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
btc_ble_gap_args_t *src = (btc_ble_gap_args_t *)p_src;
btc_ble_gap_args_t *dst = (btc_ble_gap_args_t *) p_dest;
uint8_t length = 0;
dst->set_security_param.value = NULL;
if (src->set_security_param.value) {
length = dst->set_security_param.len;
dst->set_security_param.value = osi_malloc(length);
@@ -2194,6 +2257,7 @@ void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
memcpy(dst->set_security_param.value, src->set_security_param.value, length);
} else {
BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act);
dst->set_security_param.len = 0;
}
}
break;
@@ -2202,6 +2266,7 @@ void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
btc_ble_gap_args_t *src = (btc_ble_gap_args_t *)p_src;
btc_ble_gap_args_t *dst = (btc_ble_gap_args_t *) p_dest;
uint8_t length = 0;
dst->oob_req_reply.p_value = NULL;
if (src->oob_req_reply.p_value) {
length = dst->oob_req_reply.len;
dst->oob_req_reply.p_value = osi_malloc(length);
@@ -2209,6 +2274,7 @@ void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
memcpy(dst->oob_req_reply.p_value, src->oob_req_reply.p_value, length);
} else {
BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act);
dst->oob_req_reply.len = 0;
}
}
break;
@@ -2216,6 +2282,8 @@ void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
case BTC_GAP_BLE_SC_OOB_REQ_REPLY_EVT: {
btc_ble_gap_args_t *src = (btc_ble_gap_args_t *)p_src;
btc_ble_gap_args_t *dst = (btc_ble_gap_args_t *)p_dest;
dst->sc_oob_req_reply.p_c = NULL;
dst->sc_oob_req_reply.p_r = NULL;
if (src->sc_oob_req_reply.p_c) {
dst->sc_oob_req_reply.p_c = osi_malloc(BT_OCTET16_LEN);
if (dst->sc_oob_req_reply.p_c) {
@@ -2236,17 +2304,38 @@ void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
}
#if (BLE_50_FEATURE_SUPPORT == TRUE)
#if (BLE_50_EXTEND_ADV_EN == TRUE)
case BTC_GAP_BLE_CFG_EXT_ADV_DATA_RAW:
case BTC_GAP_BLE_CFG_EXT_SCAN_RSP_DATA_RAW: {
case BTC_GAP_BLE_CFG_EXT_ADV_DATA_RAW: {
btc_ble_5_gap_args_t *src = (btc_ble_5_gap_args_t *)p_src;
btc_ble_5_gap_args_t *dst = (btc_ble_5_gap_args_t *)p_dest;
uint16_t length = 0;
dst->ext_adv_cfg_data.data = NULL;
dst->ext_adv_cfg_data.length = 0;
if (src->ext_adv_cfg_data.data) {
length = src->ext_adv_cfg_data.length;
dst->ext_adv_cfg_data.data = osi_malloc(length);
if (dst->ext_adv_cfg_data.data) {
memcpy(dst->ext_adv_cfg_data.data, src->ext_adv_cfg_data.data, length);
dst->ext_adv_cfg_data.length = length;
} else {
BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act);
}
}
break;
}
case BTC_GAP_BLE_CFG_EXT_SCAN_RSP_DATA_RAW: {
btc_ble_5_gap_args_t *src = (btc_ble_5_gap_args_t *)p_src;
btc_ble_5_gap_args_t *dst = (btc_ble_5_gap_args_t *)p_dest;
uint16_t length = 0;
dst->cfg_scan_rsp.data = NULL;
dst->cfg_scan_rsp.length = 0;
if (src->cfg_scan_rsp.data) {
length = src->cfg_scan_rsp.length;
dst->cfg_scan_rsp.data = osi_malloc(length);
if (dst->cfg_scan_rsp.data) {
memcpy(dst->cfg_scan_rsp.data, src->cfg_scan_rsp.data, length);
dst->cfg_scan_rsp.length = length;
} else {
BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act);
}
@@ -2260,17 +2349,17 @@ void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
btc_ble_5_gap_args_t *dst = (btc_ble_5_gap_args_t *)p_dest;
uint16_t length = 0;
dst->periodic_adv_cfg_data.data = NULL;
dst->periodic_adv_cfg_data.len = 0;
if (src->periodic_adv_cfg_data.data) {
length = src->periodic_adv_cfg_data.len;
dst->periodic_adv_cfg_data.data = osi_malloc(length);
if (dst->periodic_adv_cfg_data.data) {
memcpy(dst->periodic_adv_cfg_data.data, src->periodic_adv_cfg_data.data, length);
dst->periodic_adv_cfg_data.len = length;
} else {
BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act);
}
} else {
dst->periodic_adv_cfg_data.data = NULL;
dst->periodic_adv_cfg_data.len = 0;
}
break;
}
@@ -2308,10 +2397,13 @@ void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
case BTC_GAP_BLE_ACT_VENDOR_HCI_CMD_EVT: {
btc_ble_gap_args_t *src = (btc_ble_gap_args_t *)p_src;
btc_ble_gap_args_t *dst = (btc_ble_gap_args_t *)p_dest;
dst->vendor_cmd_send.p_param_buf = NULL;
dst->vendor_cmd_send.param_len = 0;
if (src->vendor_cmd_send.param_len) {
dst->vendor_cmd_send.p_param_buf = osi_malloc(src->vendor_cmd_send.param_len);
if (dst->vendor_cmd_send.p_param_buf) {
memcpy(dst->vendor_cmd_send.p_param_buf, src->vendor_cmd_send.p_param_buf, src->vendor_cmd_send.param_len);
dst->vendor_cmd_send.param_len = src->vendor_cmd_send.param_len;
} else {
BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act);
}
@@ -2398,11 +2490,14 @@ void btc_gap_ble_cb_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
switch (msg->act) {
case ESP_GAP_BLE_VENDOR_CMD_COMPLETE_EVT: {
dst->vendor_cmd_cmpl.p_param_buf = NULL;
dst->vendor_cmd_cmpl.param_len = 0;
if (src->vendor_cmd_cmpl.param_len) {
dst->vendor_cmd_cmpl.p_param_buf = osi_malloc(src->vendor_cmd_cmpl.param_len);
if (dst->vendor_cmd_cmpl.p_param_buf) {
memcpy(dst->vendor_cmd_cmpl.p_param_buf, src->vendor_cmd_cmpl.p_param_buf,
src->vendor_cmd_cmpl.param_len);
dst->vendor_cmd_cmpl.param_len = src->vendor_cmd_cmpl.param_len;
} else {
BTC_TRACE_ERROR("%s, malloc failed\n", __func__);
}
@@ -2410,11 +2505,14 @@ void btc_gap_ble_cb_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
break;
}
case ESP_GAP_BLE_VENDOR_HCI_EVT: {
dst->vendor_hci_evt.param_buf = NULL;
dst->vendor_hci_evt.param_len = 0;
if (src->vendor_hci_evt.param_len) {
dst->vendor_hci_evt.param_buf = osi_malloc(src->vendor_hci_evt.param_len);
if (dst->vendor_hci_evt.param_buf) {
memcpy(dst->vendor_hci_evt.param_buf, src->vendor_hci_evt.param_buf,
src->vendor_hci_evt.param_len);
dst->vendor_hci_evt.param_len = src->vendor_hci_evt.param_len;
} else {
BTC_TRACE_ERROR("%s, malloc failed\n", __func__);
}
@@ -2476,7 +2574,7 @@ void btc_gap_ble_cb_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
}
}
} else {
BTC_TRACE_ERROR("%s, pa_rsp_info, no enough memory.", __func__);
BTC_TRACE_ERROR("%s, step_info, no enough memory.", __func__);
}
}
break;
@@ -2499,7 +2597,7 @@ void btc_gap_ble_cb_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
}
}
} else {
BTC_TRACE_ERROR("%s, pa_rsp_info, no enough memory.", __func__);
BTC_TRACE_ERROR("%s, continue step_info, no enough memory.", __func__);
}
}
break;
@@ -2574,14 +2672,20 @@ void btc_gap_ble_arg_deep_free(btc_msg_t *msg)
}
#if (BLE_50_FEATURE_SUPPORT == TRUE)
#if (BLE_50_EXTEND_ADV_EN == TRUE)
case BTC_GAP_BLE_CFG_EXT_ADV_DATA_RAW:
case BTC_GAP_BLE_CFG_EXT_SCAN_RSP_DATA_RAW: {
case BTC_GAP_BLE_CFG_EXT_ADV_DATA_RAW: {
uint8_t *value = ((btc_ble_5_gap_args_t *)msg->arg)->ext_adv_cfg_data.data;
if (value) {
osi_free(value);
}
break;
}
case BTC_GAP_BLE_CFG_EXT_SCAN_RSP_DATA_RAW: {
uint8_t *value = ((btc_ble_5_gap_args_t *)msg->arg)->cfg_scan_rsp.data;
if (value) {
osi_free(value);
}
break;
}
#endif // #if (BLE_50_EXTEND_ADV_EN == TRUE)
#if (BLE_50_PERIODIC_ADV_EN == TRUE)
case BTC_GAP_BLE_CFG_PERIODIC_ADV_DATA_RAW: {
@@ -3033,9 +3137,9 @@ void btc_gap_ble_call_handler(btc_msg_t *msg)
break;
case BTC_GAP_BLE_CFG_EXT_SCAN_RSP_DATA_RAW:
BTC_TRACE_DEBUG("BTC_GAP_BLE_CFG_EXT_SCAN_RSP_DATA_RAW");
BTA_DmBleGapConfigExtAdvDataRaw(TRUE, arg_5->ext_adv_cfg_data.instance,
arg_5->ext_adv_cfg_data.length,
(const UINT8 *)arg_5->ext_adv_cfg_data.data);
BTA_DmBleGapConfigExtAdvDataRaw(TRUE, arg_5->cfg_scan_rsp.instance,
arg_5->cfg_scan_rsp.length,
(const UINT8 *)arg_5->cfg_scan_rsp.data);
break;
case BTC_GAP_BLE_EXT_ADV_START: {
BTC_TRACE_DEBUG("BTC_GAP_BLE_EXT_ADV_START");
@@ -203,7 +203,7 @@ static void btc_gattc_cback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
static void btc_gattc_app_register(btc_ble_gattc_args_t *arg)
{
tBT_UUID app_uuid;
tBT_UUID app_uuid = {0};
app_uuid.len = 2;
app_uuid.uu.uuid16 = arg->app_reg.app_id;
BTA_GATTC_AppRegister(&app_uuid, btc_gattc_cback);
@@ -991,8 +991,6 @@ void btc_gattc_cb_handler(btc_msg_t *msg)
case BTA_GATTC_CLOSE_EVT: {
tBTA_GATTC_CLOSE *close = &arg->close;
// Free gattc clcb in BTC task to avoid race condition
bta_gattc_clcb_dealloc_by_conn_id(close->conn_id);
gattc_if = close->client_if;
param.close.status = close->status;
param.close.conn_id = BTC_GATT_GET_CONN_ID(close->conn_id);
@@ -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;
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -29,9 +29,10 @@ static void btc_ble_iso_callback(tBTM_BLE_ISO_EVENT event,
{
esp_ble_iso_cb_param_t param = {0};
bt_status_t ret;
btc_msg_t msg;
btc_msg_t msg = {0};
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_ISO_BLE;
msg.act = ESP_BLE_ISO_EVT_MAX;
switch(event) {
#if (BLE_FEAT_ISO_BIG_BROADCASTER_EN == TRUE)
@@ -208,6 +209,11 @@ static void btc_ble_iso_callback(tBTM_BLE_ISO_EVENT event,
break;
}
if (msg.act == ESP_BLE_ISO_EVT_MAX) {
BTC_TRACE_ERROR("%s unk ISO evt %d", __func__, event);
return;
}
ret = btc_transfer_context(&msg, &param,
sizeof(esp_ble_iso_cb_param_t), NULL, NULL);
@@ -341,13 +347,14 @@ void btc_iso_ble_call_handler(btc_msg_t *msg)
(uint8_t *)&set_cig_params->cis_params[0]);
break;
}
case BTC_ISO_ACT_SET_CIG_PARAMS_TEST:
case BTC_ISO_ACT_SET_CIG_PARAMS_TEST: {
struct set_cig_params_test_arg *set_cig_params_test = (struct set_cig_params_test_arg *)arg;
BTA_DmBleIsoSetCigParamsTest(set_cig_params_test->cig_id, set_cig_params_test->sdu_int_c_to_p, set_cig_params_test->sdu_int_p_to_c,
set_cig_params_test->ft_c_to_p, set_cig_params_test->ft_p_to_c, set_cig_params_test->iso_interval,
set_cig_params_test->worse_case_SCA, set_cig_params_test->packing, set_cig_params_test->framing,
set_cig_params_test->cis_cnt, (uint8_t *)&set_cig_params_test->cis_params_test[0]);
break;
}
case BTC_ISO_ACT_CREATE_CIS: {
struct creat_cis_arg * create_cis = (struct creat_cis_arg *)arg;
BTA_DmBleIsoCreateCis(create_cis->cis_count, (uint8_t *)&create_cis->cis_hdls[0]);
@@ -17,6 +17,22 @@
* under the License.
*/
/*
* ============================================================================
* WARNING
* ============================================================================
* NOTE: The code in this file is for INTERNAL TEMPORARY TESTING ONLY.
*
* - DO NOT use it in any product code or user application.
* - It is not part of the public/stable API and provides NO compatibility
* guarantees of any kind (behavior, ABI, function signatures, side effects).
* - It may be changed, refactored, or REMOVED at any time without notice.
*
* This file will be deleted in a future release. Any external dependency on
* the symbols defined here is unsupported and will break.
* ============================================================================
*/
#include <string.h>
#include <assert.h>
#include "hci/ble_hci_iso.h"
@@ -2279,7 +2279,7 @@ void btm_acl_pkt_types_changed(UINT8 status, UINT16 handle, UINT16 pkt_types)
tBTM_STATUS BTM_ReadChannelMap(BD_ADDR remote_bda)
{
tACL_CONN *p;
tBTM_BLE_CH_MAP_RESULTS result;
tBTM_BLE_CH_MAP_RESULTS result = {0};
tBTM_BLE_LEGACY_GAP_CB_PARAMS cb_params;
UINT8 status;
@@ -2322,7 +2322,7 @@ void BTM_BleGetWhiteListSize(uint16_t *length)
{
tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
if (p_cb->white_list_avail_size == 0) {
BTM_TRACE_WARNING("%s Whitelist full.", __func__);
BTM_TRACE_WARNING("%s Whitelist size is 0.", __func__);
}
*length = p_cb->white_list_avail_size;
return;
@@ -2356,7 +2356,7 @@ void BTM_BleGetPeriodicAdvListSize(uint8_t *size)
*******************************************************************************/
void btm_read_channel_map_complete(UINT8 *p)
{
tBTM_BLE_CH_MAP_RESULTS results;
tBTM_BLE_CH_MAP_RESULTS results = {0};
UINT16 handle;
tACL_CONN *p_acl_cb = NULL;
@@ -736,7 +736,7 @@ BOOLEAN BTM_ReadConnectedTransportAddress(BD_ADDR remote_bda, tBT_TRANSPORT tran
** p_cmd_cmpl_cback - Command Complete callback
**
*******************************************************************************/
void BTM_BleReceiverTest(UINT8 rx_freq, tBTM_CMPL_CB *p_cmd_cmpl_cback)
void BTM_BleReceiverTest(UINT8 rx_freq, tBTM_DTM_CMD_CMPL_CBACK *p_cmd_cmpl_cback)
{
btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
@@ -758,7 +758,7 @@ void BTM_BleReceiverTest(UINT8 rx_freq, tBTM_CMPL_CB *p_cmd_cmpl_cback)
**
*******************************************************************************/
void BTM_BleTransmitterTest(UINT8 tx_freq, UINT8 test_data_len,
UINT8 packet_payload, tBTM_CMPL_CB *p_cmd_cmpl_cback)
UINT8 packet_payload, tBTM_DTM_CMD_CMPL_CBACK *p_cmd_cmpl_cback)
{
btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
if (btsnd_hcic_ble_transmitter_test(tx_freq, test_data_len, packet_payload) == FALSE) {
@@ -776,7 +776,7 @@ void BTM_BleTransmitterTest(UINT8 tx_freq, UINT8 test_data_len,
** Parameter p_cmd_cmpl_cback - Command complete callback
**
*******************************************************************************/
void BTM_BleTestEnd(tBTM_CMPL_CB *p_cmd_cmpl_cback)
void BTM_BleTestEnd(tBTM_DTM_CMD_CMPL_CBACK *p_cmd_cmpl_cback)
{
btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
@@ -788,14 +788,14 @@ void BTM_BleTestEnd(tBTM_CMPL_CB *p_cmd_cmpl_cback)
/*******************************************************************************
** Internal Functions
*******************************************************************************/
void btm_ble_test_command_complete(UINT8 *p)
void btm_ble_test_command_complete(UINT8 *p, UINT16 len)
{
tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_le_test_cmd_cmpl_cb;
tBTM_DTM_CMD_CMPL_CBACK *p_cb = btm_cb.devcb.p_le_test_cmd_cmpl_cb;
btm_cb.devcb.p_le_test_cmd_cmpl_cb = NULL;
if (p_cb) {
(*p_cb)(p);
(*p_cb)(p, len);
}
}
#endif // #if ((BLE_42_DTM_TEST_EN == TRUE) || (BLE_50_DTM_TEST_EN == TRUE))
@@ -813,7 +813,7 @@ void btm_ble_test_command_complete(UINT8 *p)
** p_cmd_cmpl_cback - Command Complete callback
**
*******************************************************************************/
void BTM_BleEnhancedReceiverTest(UINT8 rx_freq, UINT8 phy, UINT8 modulation_index, tBTM_CMPL_CB *p_cmd_cmpl_cback)
void BTM_BleEnhancedReceiverTest(UINT8 rx_freq, UINT8 phy, UINT8 modulation_index, tBTM_DTM_CMD_CMPL_CBACK *p_cmd_cmpl_cback)
{
btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
@@ -836,7 +836,7 @@ void BTM_BleEnhancedReceiverTest(UINT8 rx_freq, UINT8 phy, UINT8 modulation_inde
**
*******************************************************************************/
void BTM_BleEnhancedTransmitterTest(UINT8 tx_freq, UINT8 test_data_len,
UINT8 packet_payload, UINT8 phy, tBTM_CMPL_CB *p_cmd_cmpl_cback)
UINT8 packet_payload, UINT8 phy, tBTM_DTM_CMD_CMPL_CBACK *p_cmd_cmpl_cback)
{
btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
if (btsnd_hcic_ble_enhand_tx_test(tx_freq, test_data_len, packet_payload, phy) == FALSE) {
@@ -334,13 +334,13 @@ tBTM_STATUS BTM_BleConfigExtendedAdvDataRaw(BOOLEAN is_scan_rsp, UINT8 instance,
}
}
if (!is_scan_rsp) {
if ((err = btsnd_hcic_ble_set_ext_adv_data(instance, operation, 0, send_data_len, &data[data_offset])) != HCI_SUCCESS) {
if ((err = btsnd_hcic_ble_set_ext_adv_data(instance, operation, 0, send_data_len, (data == NULL) ? NULL : &data[data_offset])) != HCI_SUCCESS) {
BTM_TRACE_ERROR("LE EA SetAdvData: cmd err=0x%x", err);
status = BTM_HCI_ERROR | err;
break;
}
} else {
if ((err = btsnd_hcic_ble_set_ext_adv_scan_rsp_data(instance, operation, 0, send_data_len, &data[data_offset])) != HCI_SUCCESS) {
if ((err = btsnd_hcic_ble_set_ext_adv_scan_rsp_data(instance, operation, 0, send_data_len, (data == NULL) ? NULL : &data[data_offset])) != HCI_SUCCESS) {
BTM_TRACE_ERROR("LE EA SetScanRspData: cmd err=0x%x", err);
status = BTM_HCI_ERROR | err;
break;
@@ -1900,7 +1900,6 @@ void btm_ble_cs_read_local_supp_caps_cmpl_evt(uint8_t *p)
goto _error;
}
STREAM_TO_UINT16(cb_params.cs_read_local_supp_caps.conn_handle, p);
STREAM_TO_UINT8(cb_params.cs_read_local_supp_caps.num_config_supported, p);
STREAM_TO_UINT16(cb_params.cs_read_local_supp_caps.max_consecutive_proc_supported, p);
STREAM_TO_UINT8(cb_params.cs_read_local_supp_caps.num_ant_supported, p);
@@ -2011,6 +2010,7 @@ void btm_ble_cs_read_remote_fae_table_cmd_status(UINT8 status)
tBTM_BLE_CS_READ_REMOTE_FAE_TAB_CMPL_EVT cs_read_remote_fae_tab = {0};
if (status != HCI_SUCCESS) {
cs_read_remote_fae_tab.status = (status | BTM_HCI_ERROR);
cs_read_remote_fae_tab.conn_handle = 0xFFFF;
BTM_ExtBleCallbackTrigger(BTM_BLE_GAP_CS_READ_REMOTE_FAE_TABLE_CMPL_EVT, (tBTM_BLE_5_GAP_CB_PARAMS *)&cs_read_remote_fae_tab);
}
}
@@ -1180,6 +1180,9 @@ void btm_ble_resolving_list_cleanup(void)
{
tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
p_q->q_next = 0;
p_q->q_pending = 0;
if (p_q->resolve_q_random_pseudo) {
osi_free(p_q->resolve_q_random_pseudo);
p_q->resolve_q_random_pseudo = NULL;
@@ -120,13 +120,11 @@ void btm_dev_init (void)
*******************************************************************************/
static void btm_db_reset (void)
{
tBTM_CMPL_CB *p_cb;
tBTM_STATUS status = BTM_DEV_RESET;
btm_inq_db_reset();
#if (CLASSIC_BT_INCLUDED == TRUE)
if (btm_cb.devcb.p_rln_cmpl_cb) {
tBTM_CMPL_CB *p_cb;
p_cb = btm_cb.devcb.p_rln_cmpl_cb;
btm_cb.devcb.p_rln_cmpl_cb = NULL;
@@ -137,12 +135,14 @@ static void btm_db_reset (void)
#endif // (CLASSIC_BT_INCLUDED == TRUE)
if (btm_cb.devcb.p_rssi_cmpl_cb) {
p_cb = btm_cb.devcb.p_rssi_cmpl_cb;
btm_cb.devcb.p_rssi_cmpl_cb = NULL;
tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_rssi_cmpl_cb;
tBTM_RSSI_RESULTS results = {0};
if (p_cb) {
(*p_cb)((tBTM_RSSI_RESULTS *) &status);
}
results.status = BTM_DEV_RESET;
btm_cb.devcb.p_rssi_cmpl_cb = NULL;
btu_stop_timer(&btm_cb.devcb.rssi_timer);
(*p_cb)(&results);
}
}
@@ -444,7 +444,7 @@ void btm_ble_increment_sign_ctr(BD_ADDR bd_addr, BOOLEAN is_local );
BOOLEAN btm_get_local_div (BD_ADDR bd_addr, UINT16 *p_div);
BOOLEAN btm_ble_get_enc_key_type(BD_ADDR bd_addr, UINT8 *p_key_types);
void btm_ble_test_command_complete(UINT8 *p);
void btm_ble_test_command_complete(UINT8 *p, UINT16 len);
void btm_ble_rand_enc_complete (UINT8 *p, UINT16 op_code, tBTM_RAND_ENC_CB *p_enc_cplt_cback);
void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY_VALUE *p_keys, BOOLEAN pass_to_application);
@@ -291,8 +291,8 @@ DEV_CLASS dev_class; /* Local device class
TIMER_LIST_ENT ble_channels_timer;
tBTM_CMPL_CB *p_le_test_cmd_cmpl_cb; /* Callback function to be called when
LE test mode command has been sent successfully */
tBTM_DTM_CMD_CMPL_CBACK *p_le_test_cmd_cmpl_cb; /* Callback function to be called when
LE test mode command has been sent successfully */
BD_ADDR read_tx_pwr_addr; /* read TX power target address */
@@ -50,7 +50,7 @@
#include "stack/btu.h"
extern void btm_process_cancel_complete(UINT8 status, UINT8 mode);
extern void btm_ble_test_command_complete(UINT8 *p);
extern void btm_ble_test_command_complete(UINT8 *p, UINT16 len);
#if (BT_BLE_FEAT_CHANNEL_SOUNDING == TRUE)
// BLE Channel Sounding parameter validation macros per BLE spec
@@ -1331,11 +1331,17 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l
btm_ble_create_ll_conn_complete(*p);
break;
#if ((BLE_42_DTM_TEST_EN == TRUE) || (BLE_50_DTM_TEST_EN == TRUE))
case HCI_BLE_TRANSMITTER_TEST:
case HCI_BLE_RECEIVER_TEST:
case HCI_BLE_TEST_END:
/* Forward raw parameters + length; upper layers validate before parsing. */
btm_ble_test_command_complete(p, evt_len);
break;
#else
case HCI_BLE_TRANSMITTER_TEST:
case HCI_BLE_RECEIVER_TEST:
#if ((BLE_42_DTM_TEST_EN == TRUE) || (BLE_50_DTM_TEST_EN == TRUE))
case HCI_BLE_TEST_END:
btm_ble_test_command_complete(p);
break;
#endif // #if ((BLE_42_DTM_TEST_EN == TRUE) || (BLE_50_DTM_TEST_EN == TRUE))
case HCI_BLE_CREATE_CONN_CANCEL:
@@ -1397,7 +1403,7 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l
#if (BLE_50_DTM_TEST_EN == TRUE)
case HCI_BLE_ENH_RX_TEST:
case HCI_BLE_ENH_TX_TEST:
btm_ble_test_command_complete(p);
btm_ble_test_command_complete(p, evt_len);
break;
#endif // #if (BLE_50_DTM_TEST_EN == TRUE)
@@ -390,6 +390,18 @@ tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP)
if (p_tcb->att_lcid == L2CAP_ATT_CID) {
/* L2CA_SendFixedChnlData() silently drops (osi_free) the buffer when the
* ATT fixed channel is already in cong_sent state, yet still returns
* L2CAP_DW_CONGESTED. Without distinguishing this from the post-enqueue
* congestion case, the upper layer would treat a dropped PDU as "sent"
* and wait for a response that never arrives. Detect the drop path
* up-front, release the buffer here and surface it as GATT_BUSY so that
* callers go through their failure path instead. */
if (L2CA_CheckIsCongest(L2CAP_ATT_CID, p_tcb->peer_bda)) {
GATT_TRACE_WARNING("ATT fixed channel already congested, drop PDU");
osi_free(p_toL2CAP);
return GATT_BUSY;
}
l2cap_ret = L2CA_SendFixedChnlData (L2CAP_ATT_CID, p_tcb->peer_bda, p_toL2CAP);
} else {
#if (CLASSIC_BT_INCLUDED == TRUE)
@@ -403,6 +415,8 @@ tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP)
GATT_TRACE_DEBUG("ATT failed to pass msg to L2CAP");
return GATT_INTERNAL_ERROR;
} else if (l2cap_ret == L2CAP_DW_CONGESTED) {
/* Buffer was enqueued by L2CAP before congestion was reported;
* L2CAP retains ownership of it. */
GATT_TRACE_DEBUG("ATT congested, message accepted");
return GATT_CONGESTED;
}
@@ -1750,9 +1750,22 @@ tGATT_STATUS GATTS_HandleMultiValueNotification (UINT16 conn_id, tGATT_HLV *tupl
return GATT_ILLEGAL_PARAMETER;
}
{
UINT32 new_len = (UINT32)notif.len + 4U + (UINT32)p_hlv->length;
if (new_len > (UINT32)GATT_MAX_ATTR_LEN) {
GATT_TRACE_ERROR("%s: len %u>MAX_ATTR_LEN", __func__, (unsigned)new_len);
return GATT_ILLEGAL_PARAMETER;
}
}
UINT16_TO_STREAM(p, p_hlv->handle); //handle
UINT16_TO_STREAM(p, p_hlv->length); //length
memcpy (p, p_hlv->value, p_hlv->length); //value
if (p_hlv->length > 0) {
if (p_hlv->value == NULL) {
return GATT_ILLEGAL_PARAMETER;
}
memcpy (p, p_hlv->value, p_hlv->length); //value
}
GATT_TRACE_DEBUG("%s handle %x, length %u", __func__, p_hlv->handle, p_hlv->length);
p += p_hlv->length;
notif.len += 4 + p_hlv->length;
@@ -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;
@@ -1124,10 +1124,14 @@ BOOLEAN gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb)
if (att_ret == GATT_SUCCESS || att_ret == GATT_CONGESTED) {
sent = TRUE;
p_cmd->to_send = FALSE;
if(p_cmd->p_cmd) {
osi_free(p_cmd->p_cmd);
p_cmd->p_cmd = NULL;
}
/* On GATT_SUCCESS / GATT_CONGESTED, L2CAP has taken ownership of
* p_cmd->p_cmd (it was either accepted normally, or enqueued just
* before the channel turned congested). The "already congested"
* drop path inside L2CA_SendFixedChnlData() is filtered out earlier
* by attp_send_msg_to_l2cap() and returned as GATT_BUSY, which
* falls into the error branch below. So we must not free the
* buffer here. */
p_cmd->p_cmd = NULL;
/* dequeue the request if is write command or sign write */
if (p_cmd->op_code != GATT_CMD_WRITE && p_cmd->op_code != GATT_SIGN_CMD_WRITE) {
@@ -1145,13 +1149,22 @@ BOOLEAN gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb)
gatt_end_operation(p_clcb, att_ret, NULL);
}
} else {
GATT_TRACE_ERROR("gatt_cl_send_next_cmd_inq: L2CAP sent error");
GATT_TRACE_ERROR("gatt_cl_send_next_cmd_inq: L2CAP sent error, status=%d", att_ret);
/* attp_send_msg_to_l2cap() already freed p_cmd->p_cmd on failure */
p_cmd->p_cmd = NULL;
memset(p_cmd, 0, sizeof(tGATT_CMD_Q));
p_tcb->pending_cl_req ++;
p_tcb->pending_cl_req %= GATT_CL_MAX_LCB;
p_cmd->to_send = FALSE;
/* Dequeue the failing command so pending_cl_req is advanced and the
* associated p_clcb can be retrieved. */
p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
/* Notify the upper layer about the failure. Without this the
* response timer is never armed (non-write ops) and the write
* completion callback is never fired, leaving the application
* stuck waiting for a callback that will never come. The p_clcb
* would also leak. */
if (p_clcb != NULL) {
gatt_end_operation(p_clcb, att_ret, NULL);
}
}
}
@@ -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);
}
}
}
@@ -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)
}
/*******************************************************************************
@@ -3059,7 +3059,8 @@ UINT8 btsnd_hcic_ble_set_periodic_adv_subevt_data(UINT8 adv_handle, UINT8 num_su
{
BT_HDR *p;
UINT8 *pp;
uint8_t param_len = 0;
unsigned total_len;
UINT8 param_len;
HCI_TRACE_DEBUG("hci set PA subevent data, adv_handle %d num_subevents_with_data %d", adv_handle, num_subevents_with_data);
@@ -3067,10 +3068,19 @@ UINT8 btsnd_hcic_ble_set_periodic_adv_subevt_data(UINT8 adv_handle, UINT8 num_su
HCI_TRACE_ERROR("%s error\n", __func__);
return HCI_ERR_ILLEGAL_PARAMETER_FMT;
}
param_len += HCIC_PARAM_SIZE_SET_PA_SUBEVT_DATA_PARAMS_LEN;
total_len = HCIC_PARAM_SIZE_SET_PA_SUBEVT_DATA_PARAMS_LEN;
for (UINT8 i = 0; i < num_subevents_with_data; i++)
{
if (subevent_params[i].subevent_data_len > sizeof(subevent_params[i].data)) {
HCI_TRACE_ERROR("%s sub_data_len %u>%u", __func__,
(unsigned)subevent_params[i].subevent_data_len,
(unsigned)sizeof(subevent_params[i].data));
return HCI_ERR_ILLEGAL_PARAMETER_FMT;
}
unsigned add_len = 4u + (unsigned)subevent_params[i].subevent_data_len;
HCI_TRACE_DEBUG("subevent_params: subevent %d response_slot_start %d response_slot_count %d subevent_data_len %d",
subevent_params[i].subevent, subevent_params[i].response_slot_start, subevent_params[i].response_slot_count,
subevent_params[i].subevent_data_len);
@@ -3079,9 +3089,17 @@ UINT8 btsnd_hcic_ble_set_periodic_adv_subevt_data(UINT8 adv_handle, UINT8 num_su
esp_log_buffer_hex_internal("data", subevent_params[i].data, subevent_params[i].subevent_data_len, ESP_LOG_DEBUG);
}
param_len += (4 + subevent_params[i].subevent_data_len);
/* Avoid unsigned wrap when add_len > HCI_COMMAND_SIZE. */
if (total_len > (unsigned)HCI_COMMAND_SIZE ||
add_len > (unsigned)HCI_COMMAND_SIZE - total_len) {
HCI_TRACE_ERROR("%s total>HCI_CMD_SZ", __func__);
return HCI_ERR_ILLEGAL_PARAMETER_FMT;
}
total_len += add_len;
}
param_len = (UINT8)total_len;
HCIC_BLE_CMD_CREATED_U8(p, pp, param_len);
pp = (UINT8 *)(p + 1);
@@ -3113,6 +3131,11 @@ UINT8 btsnd_hcic_ble_set_periodic_adv_rsp_data(UINT16 sync_handle, UINT16 req_ev
HCI_TRACE_DEBUG("hci set PA rsp data, sync_handle %d req_evt %d req_subevt %d rsp_subevt %d rsp_slot %d rsp_data_len %d",
sync_handle, req_evt, req_subevt, rsp_subevt, rsp_slot, rsp_data_len);
if (rsp_data_len > HCIC_PA_RSP_DATA_PAYLOAD_MAX) {
HCI_TRACE_ERROR("%s rsp_len %u>%u", __func__, rsp_data_len, HCIC_PA_RSP_DATA_PAYLOAD_MAX);
return HCI_ERR_ILLEGAL_PARAMETER_FMT;
}
HCIC_BLE_CMD_CREATED_U8(p, pp, HCIC_PARAM_SIZE_SET_PA_RESPONSE_DATA_PARAMS_LEN + rsp_data_len);
pp = (UINT8 *)(p + 1);
@@ -3141,6 +3164,12 @@ UINT8 btsnd_hcic_ble_set_periodic_sync_subevt(UINT16 sync_handle, UINT16 periodi
HCI_TRACE_DEBUG("hci set PA sync subevent, sync_handle %d periodic_adv_properties %d num_subevents_to_sync %d",
sync_handle, periodic_adv_properties, num_subevents_to_sync);
if (num_subevents_to_sync > HCIC_PA_SYNC_SUBEVT_NUM_MAX) {
HCI_TRACE_ERROR("%s n_sync %u>%u", __func__, num_subevents_to_sync, HCIC_PA_SYNC_SUBEVT_NUM_MAX);
return HCI_ERR_ILLEGAL_PARAMETER_FMT;
}
for (UINT8 i = 0; i < num_subevents_to_sync; i++)
{
HCI_TRACE_DEBUG("subevt[%d] = %d", i, subevt[i]);
@@ -173,7 +173,14 @@ typedef void (tBTM_VSC_CMPL_CB) (tBTM_VSC_CMPL *p1);
*/
// typedef UINT8 (tBTM_FILTER_CB) (BD_ADDR bd_addr, DEV_CLASS dc);
typedef void (tBTM_DTM_CMD_CMPL_CBACK) (void *p1);
/*
* DTM (Direct Test Mode) command complete callback.
*
* The controller returns a variable-length parameter block depending on the
* specific LE test command. Propagate the parameter length so upper layers can
* validate before parsing and avoid OOB reads on malformed/truncated responses.
*/
typedef void (tBTM_DTM_CMD_CMPL_CBACK) (UINT8 *p, UINT16 len);
typedef void (tBTM_SET_RAND_ADDR_CBACK) (UINT8 status);
@@ -1528,7 +1528,6 @@ typedef struct {
typedef struct {
UINT8 status;
UINT16 conn_handle;
UINT8 num_config_supported;
UINT16 max_consecutive_proc_supported;
UINT8 num_ant_supported;
@@ -2726,7 +2725,7 @@ void BTM_BleClearWhitelist(void);
** p_cmd_cmpl_cback - Command Complete callback
**
*******************************************************************************/
void BTM_BleReceiverTest(UINT8 rx_freq, tBTM_CMPL_CB *p_cmd_cmpl_cback);
void BTM_BleReceiverTest(UINT8 rx_freq, tBTM_DTM_CMD_CMPL_CBACK *p_cmd_cmpl_cback);
/*******************************************************************************
@@ -2742,7 +2741,7 @@ void BTM_BleReceiverTest(UINT8 rx_freq, tBTM_CMPL_CB *p_cmd_cmpl_cback);
**
*******************************************************************************/
void BTM_BleTransmitterTest(UINT8 tx_freq, UINT8 test_data_len,
UINT8 packet_payload, tBTM_CMPL_CB *p_cmd_cmpl_cback);
UINT8 packet_payload, tBTM_DTM_CMD_CMPL_CBACK *p_cmd_cmpl_cback);
/*******************************************************************************
**
@@ -2753,7 +2752,7 @@ void BTM_BleTransmitterTest(UINT8 tx_freq, UINT8 test_data_len,
** Parameter p_cmd_cmpl_cback - Command complete callback
**
*******************************************************************************/
void BTM_BleTestEnd(tBTM_CMPL_CB *p_cmd_cmpl_cback);
void BTM_BleTestEnd(tBTM_DTM_CMD_CMPL_CBACK *p_cmd_cmpl_cback);
/*******************************************************************************
**
@@ -3087,9 +3086,9 @@ tBTM_STATUS BTM_BleEnableMonitorAdv(UINT8 enable);
#endif // #if (BLE_50_FEATURE_SUPPORT == TRUE)
#if (BLE_50_DTM_TEST_EN == TRUE)
void BTM_BleEnhancedReceiverTest(UINT8 rx_freq, UINT8 phy, UINT8 modulation_index, tBTM_CMPL_CB *p_cmd_cmpl_cback);
void BTM_BleEnhancedReceiverTest(UINT8 rx_freq, UINT8 phy, UINT8 modulation_index, tBTM_DTM_CMD_CMPL_CBACK *p_cmd_cmpl_cback);
void BTM_BleEnhancedTransmitterTest(UINT8 tx_freq, UINT8 test_data_len, UINT8 packet_payload, UINT8 phy, tBTM_CMPL_CB *p_cmd_cmpl_cback);
void BTM_BleEnhancedTransmitterTest(UINT8 tx_freq, UINT8 test_data_len, UINT8 packet_payload, UINT8 phy, tBTM_DTM_CMD_CMPL_CBACK *p_cmd_cmpl_cback);
#endif // #if (BLE_50_DTM_TEST_EN == TRUE)
#if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE)
@@ -1285,6 +1285,11 @@ typedef struct {
#define HCIC_PARAM_SIZE_SET_PA_RESPONSE_DATA_PARAMS_LEN 8
#define HCIC_PARAM_SIZE_SET_PA_SYNC_SUBEVT_PARAMS_LEN 5
/** Max rsp_data octets in LE Set Periodic Advertising Response Data (HCI command param total ≤ HCI_COMMAND_SIZE). */
#define HCIC_PA_RSP_DATA_PAYLOAD_MAX (HCI_COMMAND_SIZE - HCIC_PARAM_SIZE_SET_PA_RESPONSE_DATA_PARAMS_LEN)
/** Max Num_Subevents_To_Sync in LE Set Periodic Advertising Sync Subevents (BT Core Spec §7.8.127: 0x01–0x80). */
#define HCIC_PA_SYNC_SUBEVT_NUM_MAX 128
#define HCIC_PARAM_SIZE_SET_PERIODIC_ADV_PARAMS_V2 12
UINT8 btsnd_hcic_ble_set_periodic_adv_params_v2(UINT8 adv_handle, UINT16 interval_min, UINT16 interval_max,
UINT16 propertics, UINT8 num_subevents, UINT8 subevent_interval,