Merge branch 'fix/fix_blufi_memory_copy_len_error' into 'master'

fix(ble): Fix blufi fragment reassembly bounds and buffer overflows

See merge request espressif/esp-idf!47090
This commit is contained in:
Island
2026-04-27 15:38:23 +08:00
20 changed files with 676 additions and 188 deletions

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -51,15 +51,17 @@ int btc_profile_cb_set(btc_pid_t profile_id, void *cb)
void *btc_profile_cb_get(btc_pid_t profile_id)
{
#if BTC_DYNAMIC_MEMORY == TRUE
void *p = btc_profile_cb_tab;
void **p = btc_profile_cb_tab;
if (p == NULL) {
return NULL;
}
#else
void **p = btc_profile_cb_tab;
#endif
if (profile_id < 0 || profile_id >= BTC_PID_NUM) {
return NULL;
}
return btc_profile_cb_tab[profile_id];
return p[profile_id];
}

View File

@@ -292,6 +292,8 @@ static void btc_thread_handler(void *arg)
btc_msg_t *msg = (btc_msg_t *)arg;
BTC_TRACE_DEBUG("%s msg %u %u %u %p\n", __func__, msg->sig, msg->pid, msg->act, msg->arg);
/* msg->pid is validated at btc_transfer_context() entry; any message that
* reaches this handler is guaranteed to carry a valid pid. */
switch (msg->sig) {
case BTC_SIG_API_CALL:
profile_tab[msg->pid].btc_call(msg);
@@ -331,7 +333,12 @@ bt_status_t btc_transfer_context(btc_msg_t *msg, void *arg, int arg_len, btc_arg
btc_msg_t* lmsg;
bt_status_t ret;
// arg XOR arg_len
if ((msg == NULL) || ((arg == NULL) == !(arg_len == 0))) {
if ((msg == NULL) || ((arg == NULL) == !(arg_len == 0)) ||
(msg->pid >= BTC_PID_NUM)) {
/* Reject invalid pid here, before any deep_copy runs, so the caller's
* arg is not yet duplicated into lmsg and there is nothing to free.
* This keeps the trust boundary at the single public entry point and
* makes the downstream handler unable to encounter an invalid pid. */
BTC_TRACE_WARNING("%s Invalid parameters\n", __func__);
return BT_STATUS_PARM_INVALID;
}
@@ -564,22 +571,31 @@ bt_status_t btc_init(void)
void btc_deinit(void)
{
osi_thread_t *thread = btc_thread;
if (!thread) {
if (!btc_thread) {
return;
}
osi_thread_free(thread);
btc_thread = NULL;
/* Reverse order of btc_init():
* 1) BLE GAP deinit must run BEFORE btc_deinit_mem(), otherwise under
* BTC_DYNAMIC_MEMORY the gl_bta_adv_data macro expands to
* *(NULL) and btc_cleanup_adv_data() early-returns, leaking the
* inner adv-data fields (p_manu / p_proprietary / p_services...).
* 2) BT classic GAP deinit follows.
* 3) Then release the dynamic-memory pool.
* 4) Finally tear down the BTC worker thread.
*/
#if (BLE_INCLUDED == TRUE)
btc_gap_ble_deinit();
#endif ///BLE_INCLUDED == TRUE
#if BTC_GAP_BT_INCLUDED
btc_gap_bt_deinit();
#endif
#if BTC_DYNAMIC_MEMORY
btc_deinit_mem();
#endif
#if (BLE_INCLUDED == TRUE)
btc_gap_ble_deinit();
#endif ///BLE_INCLUDED == TRUE
osi_thread_free(btc_thread);
btc_thread = NULL;
}
int get_btc_work_queue_size(void)

View File

@@ -160,6 +160,9 @@ static bool blufi_rx_enqueue(const uint8_t *data, uint16_t len)
static uint8_t server_if;
static uint16_t conn_id;
/* Forward declaration used by the GATTS event handler. */
esp_err_t esp_blufi_close(esp_gatt_if_t gatts_if, uint16_t conn_id);
static uint8_t blufi_service_uuid128[32] = {
/* LSB <--------------------------------------------------------------------------------> MSB */
//first uuid, 16bit, [12],[13] is the value
@@ -274,6 +277,10 @@ void esp_blufi_gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_pa
BLUFI_TRACE_DEBUG("GAP_EVT, event %d", event);
switch (event) {
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
if (param->adv_data_cmpl.status != ESP_BT_STATUS_SUCCESS) {
BTC_TRACE_ERROR("Advertising data set failed, status %x", param->adv_data_cmpl.status);
break;
}
esp_ble_gap_start_advertising(&blufi_adv_params);
break;
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
@@ -303,8 +310,15 @@ void esp_blufi_gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_pa
case ESP_GAP_BLE_NC_REQ_EVT:
/* The app will receive this evt when the IO has DisplayYesNO capability and the peer device IO also has DisplayYesNo capability.
show the passkey number to the user to confirm it with the number displayed by peer device. */
esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, true);
BLUFI_TRACE_WARNING("Numeric Comparison request, passkey %" PRIu32, param->ble_security.key_notif.passkey);
/*
* Security note:
* Auto-accepting Numeric Comparison would bypass the user confirmation step and
* effectively weaken MITM protection. Reject by default; applications that want
* MITM protection must implement explicit user confirmation logic.
*/
esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, false);
BLUFI_TRACE_WARNING("Numeric Comparison request rejected by default, passkey %" PRIu32,
param->ble_security.key_notif.passkey);
break;
case ESP_GAP_BLE_SEC_REQ_EVT:
/* send the positive(true) security response to the peer device to accept the security request.
@@ -414,7 +428,7 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
break;
}
case BTA_GATTS_READ_EVT:
memset(&rsp, 0, sizeof(tBTA_GATTS_API_RSP));
memset(&rsp, 0, sizeof(rsp));
rsp.attr_value.handle = p_data->req_data.p_data->read_req.handle;
rsp.attr_value.len = 1;
rsp.attr_value.value[0] = 0x00;
@@ -441,7 +455,9 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
status = GATT_INVALID_OFFSET;
break;
}
blufi_env.prepare_buf = osi_malloc(BLUFI_PREPARE_BUF_MAX_SIZE);
/* Use calloc so any unwritten gaps are deterministic (0) if peer sends
* out-of-order/overlapping fragments and later executes the write. */
blufi_env.prepare_buf = osi_calloc(BLUFI_PREPARE_BUF_MAX_SIZE);
blufi_env.prepare_len = 0;
if (blufi_env.prepare_buf == NULL) {
BLUFI_TRACE_ERROR("Blufi prep no mem\n");
@@ -474,7 +490,14 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
memcpy(blufi_env.prepare_buf + p_data->req_data.p_data->write_req.offset,
p_data->req_data.p_data->write_req.value,
p_data->req_data.p_data->write_req.len);
blufi_env.prepare_len += p_data->req_data.p_data->write_req.len;
/* Maintain the maximum written extent rather than summing lengths.
* Summation breaks on retransmissions/overlaps and can exceed the actual
* written range, causing parsing of unwritten bytes. */
const uint16_t end =
(uint16_t)(p_data->req_data.p_data->write_req.offset + p_data->req_data.p_data->write_req.len);
if (end > blufi_env.prepare_len) {
blufi_env.prepare_len = end;
}
return;
} else {
@@ -548,7 +571,11 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
blufi_env.handle_char_p2e = p_data->add_result.attr_id;
BTA_GATTS_AddCharacteristic(blufi_env.handle_srvc, &blufi_char_uuid_e2p,
#if CONFIG_BT_BLUFI_BLE_SMP_ENABLE
(GATT_PERM_READ_ENC_MITM),
#else
(GATT_PERM_READ),
#endif
(GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY),
NULL, NULL);
break;
@@ -556,7 +583,11 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
blufi_env.handle_char_e2p = p_data->add_result.attr_id;
BTA_GATTS_AddCharDescriptor (blufi_env.handle_srvc,
#if CONFIG_BT_BLUFI_BLE_SMP_ENABLE
(GATT_PERM_READ_ENC_MITM | GATT_PERM_WRITE_ENC_MITM),
#else
(GATT_PERM_READ | GATT_PERM_WRITE),
#endif
&blufi_descr_uuid_e2p,
NULL, NULL);
break;
@@ -585,6 +616,13 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
btc_msg_t msg;
esp_blufi_cb_param_t param;
if (blufi_env.is_connected) {
BLUFI_TRACE_WARNING("BLUFI already connected; rejecting new connection from "BT_BD_ADDR_STR", connect_id=%d",
BT_BD_ADDR_HEX(p_data->conn.remote_bda), p_data->conn.conn_id);
(void)esp_blufi_close(p_data->conn.server_if, BTC_GATT_GET_CONN_ID(p_data->conn.conn_id));
break;
}
//set the connection flag to true
BLUFI_TRACE_API("\ndevice is connected "BT_BD_ADDR_STR", server_if=%d,reason=0x%x,connect_id=%d\n",
BT_BD_ADDR_HEX(p_data->conn.remote_bda), p_data->conn.server_if,
@@ -609,6 +647,18 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
btc_msg_t msg;
esp_blufi_cb_param_t param;
/* Ignore disconnects that do not belong to the active BLUFI connection.
* Even though we reject concurrent connections, the stack may still
* deliver disconnect events for transient/previous connections; blindly
* resetting the global env would corrupt the active session. */
if (!blufi_env.is_connected || blufi_env.conn_id != p_data->conn.conn_id) {
BLUFI_TRACE_WARNING("Ignoring BLUFI disconnect for non-active conn_id=%d (active=%d, is_connected=%d) from "
BT_BD_ADDR_STR,
p_data->conn.conn_id, blufi_env.conn_id, blufi_env.is_connected,
BT_BD_ADDR_HEX(p_data->conn.remote_bda));
break;
}
blufi_env.is_connected = false;
//set the connection flag to true
BLUFI_TRACE_API("\ndevice is disconnected "BT_BD_ADDR_STR", server_if=%d,reason=0x%x,connect_id=%d\n",
@@ -626,6 +676,12 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
blufi_env.aggr_buf = NULL;
}
if (blufi_env.prepare_buf) {
osi_free(blufi_env.prepare_buf);
blufi_env.prepare_buf = NULL;
blufi_env.prepare_len = 0;
}
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_BLUFI;
msg.act = ESP_BLUFI_EVENT_BLE_DISCONNECT;
@@ -660,6 +716,18 @@ void esp_blufi_deinit(void)
#if !SOC_MPI_SUPPORTED
blufi_rx_worker_stop();
#endif
if (blufi_env.prepare_buf) {
osi_free(blufi_env.prepare_buf);
blufi_env.prepare_buf = NULL;
blufi_env.prepare_len = 0;
}
if (blufi_env.aggr_buf) {
osi_free(blufi_env.aggr_buf);
blufi_env.aggr_buf = NULL;
}
blufi_env.offset = 0;
blufi_env.total_len = 0;
BTA_GATTS_StopService(blufi_env.handle_srvc);
BTA_GATTS_DeleteService(blufi_env.handle_srvc);
/* register the BLUFI profile to the BTA_GATTS module*/
@@ -720,6 +788,8 @@ esp_err_t esp_blufi_close(esp_gatt_if_t gatts_if, uint16_t conn_id)
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
btc_msg_t msg;
btc_ble_gatts_args_t arg;
memset(&msg, 0, sizeof(msg));
memset(&arg, 0, sizeof(arg));
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GATTS;
msg.act = BTC_GATTS_ACT_CLOSE;

View File

@@ -5,10 +5,10 @@
*/
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "osi/allocator.h"
@@ -34,6 +34,22 @@ tBLUFI_ENV *blufi_env_ptr;
// static functions declare
static void btc_blufi_send_ack(uint8_t seq);
static inline void btc_blufi_env_free_buffers(void)
{
if (blufi_env.aggr_buf) {
osi_free(blufi_env.aggr_buf);
blufi_env.aggr_buf = NULL;
}
blufi_env.total_len = 0;
blufi_env.offset = 0;
if (blufi_env.prepare_buf) {
osi_free(blufi_env.prepare_buf);
blufi_env.prepare_buf = NULL;
}
blufi_env.prepare_len = 0;
}
inline void btc_blufi_cb_to_app(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param)
{
esp_blufi_event_cb_t btc_blufi_cb = (esp_blufi_event_cb_t)btc_profile_cb_get(BTC_PID_BLUFI);
@@ -52,6 +68,7 @@ static uint8_t btc_blufi_profile_init(void)
return ESP_BLUFI_ERROR;
}
btc_blufi_env_free_buffers();
memset(&blufi_env, 0x0, sizeof(blufi_env));
blufi_env.cbs = store_p; /* if set callback prior, restore the point */
blufi_env.frag_size = BLUFI_FRAG_DATA_DEFAULT_LEN;
@@ -138,6 +155,7 @@ void btc_blufi_recv_handler(uint8_t *data, int len)
blufi_env.aggr_buf = NULL; \
} \
blufi_env.offset = 0; \
blufi_env.total_len = 0; \
} while (0)
// first step, decrypt
@@ -170,11 +188,14 @@ void btc_blufi_recv_handler(uint8_t *data, int len)
}
if (BLUFI_FC_IS_FRAG(hdr->fc)) {
if(hdr->data_len<2) {
BTC_TRACE_ERROR("%s: Invalid fragment data length: %d", __func__, hdr->data_len);
btc_blufi_report_error(ESP_BLUFI_DATA_FORMAT_ERROR);
return;
if (hdr->data_len < 2) {
BTC_TRACE_ERROR("%s: Invalid fragment data length: %d", __func__, hdr->data_len);
BLUFI_RESET_AGGR_BUF();
btc_blufi_report_error(ESP_BLUFI_DATA_FORMAT_ERROR);
return;
}
uint16_t frag_payload = (uint16_t)(hdr->data_len - 2);
if (blufi_env.offset == 0) {
/*
blufi_env.aggr_buf should be NULL if blufi_env.offset is 0.
@@ -183,17 +204,16 @@ void btc_blufi_recv_handler(uint8_t *data, int len)
*/
if (blufi_env.aggr_buf) {
BTC_TRACE_ERROR("%s msg error, blufi_env.aggr_buf is not freed\n", __func__);
osi_free(blufi_env.aggr_buf);
blufi_env.aggr_buf = NULL;
BLUFI_RESET_AGGR_BUF();
btc_blufi_report_error(ESP_BLUFI_MSG_STATE_ERROR);
return;
}
if (hdr->data_len < 2) {
BTC_TRACE_ERROR("%s frag header too short: data_len=%d\n", __func__, hdr->data_len);
blufi_env.total_len = hdr->data[0] | (((uint16_t) hdr->data[1]) << 8);
if (blufi_env.total_len == 0) {
BTC_TRACE_ERROR("%s zero total_len\n", __func__);
btc_blufi_report_error(ESP_BLUFI_DATA_FORMAT_ERROR);
return;
}
blufi_env.total_len = hdr->data[0] | (((uint16_t) hdr->data[1]) << 8);
blufi_env.aggr_buf = osi_malloc(blufi_env.total_len);
if (blufi_env.aggr_buf == NULL) {
BTC_TRACE_ERROR("%s no mem, len %d\n", __func__, blufi_env.total_len);
@@ -201,15 +221,15 @@ void btc_blufi_recv_handler(uint8_t *data, int len)
return;
}
}
if (blufi_env.offset + hdr->data_len - 2 <= blufi_env.total_len){
memcpy(blufi_env.aggr_buf + blufi_env.offset, hdr->data + 2, hdr->data_len - 2);
blufi_env.offset += (hdr->data_len - 2);
} else {
BTC_TRACE_ERROR("%s payload is longer than packet length, len %d \n", __func__, blufi_env.total_len);
if ((uint32_t)blufi_env.offset + frag_payload > blufi_env.total_len) {
BTC_TRACE_ERROR("%s payload is longer than packet length, len %d\n", __func__, blufi_env.total_len);
BLUFI_RESET_AGGR_BUF();
btc_blufi_report_error(ESP_BLUFI_DATA_FORMAT_ERROR);
return;
}
memcpy(blufi_env.aggr_buf + blufi_env.offset, hdr->data + 2, frag_payload);
blufi_env.offset += frag_payload;
} else {
if (blufi_env.offset > 0) { /* if previous pkt is frag */
@@ -255,6 +275,16 @@ void btc_blufi_send_encap(uint8_t type, uint8_t *data, int total_data_len)
return;
}
if (total_data_len <= 0 || data == NULL) {
BTC_TRACE_ERROR("%s invalid data or length %d\n", __func__, total_data_len);
return;
}
if (total_data_len > UINT16_MAX) {
BTC_TRACE_ERROR("%s total_data_len too large %d\n", __func__, total_data_len);
btc_blufi_report_error(ESP_BLUFI_DATA_FORMAT_ERROR);
return;
}
while (remain_len > 0) {
if (remain_len > blufi_env.frag_size) {
hdr = osi_malloc(sizeof(struct blufi_hdr) + 2 + blufi_env.frag_size + 2);
@@ -264,8 +294,8 @@ void btc_blufi_send_encap(uint8_t type, uint8_t *data, int total_data_len)
}
hdr->fc = 0x0;
hdr->data_len = blufi_env.frag_size + 2;
hdr->data[0] = remain_len & 0xff;
hdr->data[1] = (remain_len >> 8) & 0xff;
hdr->data[0] = (uint8_t)(remain_len & 0xff);
hdr->data[1] = (uint8_t)((remain_len >> 8) & 0xff);
memcpy(hdr->data + 2, &data[total_data_len - remain_len], blufi_env.frag_size); //copy first, easy for check sum
hdr->fc |= BLUFI_FC_FRAG;
} else {
@@ -325,15 +355,99 @@ void btc_blufi_send_encap(uint8_t type, uint8_t *data, int total_data_len)
}
}
/* IEEE 802.11 SSID / passphrase upper bounds for BLUFI encoding */
#define BLUFI_WIFI_SSID_MAX 32
#define BLUFI_WIFI_PASS_MAX 64
#define BLUFI_WIFI_CONN_REP_MAX 512
static size_t blufi_extra_field_len(int len, size_t max_len)
{
if (len <= 0) {
return 0;
}
return (size_t)len > max_len ? max_len : (size_t)len;
}
static bool btc_blufi_wifi_conn_report_add(size_t *acc, size_t add)
{
if (*acc > SIZE_MAX - add) {
return false;
}
*acc += add;
return *acc <= BLUFI_WIFI_CONN_REP_MAX;
}
static size_t btc_blufi_wifi_conn_report_need(esp_blufi_extra_info_t *info)
{
size_t n = 3;
if (info == NULL) {
return n;
}
if (info->sta_bssid_set && !btc_blufi_wifi_conn_report_add(&n, 8)) {
return 0;
}
if (info->sta_ssid) {
size_t sl = blufi_extra_field_len(info->sta_ssid_len, BLUFI_WIFI_SSID_MAX);
if (!btc_blufi_wifi_conn_report_add(&n, 2 + sl)) {
return 0;
}
}
if (info->sta_passwd) {
size_t pl = blufi_extra_field_len(info->sta_passwd_len, BLUFI_WIFI_PASS_MAX);
if (!btc_blufi_wifi_conn_report_add(&n, 2 + pl)) {
return 0;
}
}
if (info->softap_ssid) {
size_t sl = blufi_extra_field_len(info->softap_ssid_len, BLUFI_WIFI_SSID_MAX);
if (!btc_blufi_wifi_conn_report_add(&n, 2 + sl)) {
return 0;
}
}
if (info->softap_passwd) {
size_t pl = blufi_extra_field_len(info->softap_passwd_len, BLUFI_WIFI_PASS_MAX);
if (!btc_blufi_wifi_conn_report_add(&n, 2 + pl)) {
return 0;
}
}
if (info->softap_authmode_set && !btc_blufi_wifi_conn_report_add(&n, 3)) {
return 0;
}
if (info->softap_max_conn_num_set && !btc_blufi_wifi_conn_report_add(&n, 3)) {
return 0;
}
if (info->softap_channel_set && !btc_blufi_wifi_conn_report_add(&n, 3)) {
return 0;
}
if (info->sta_max_conn_retry_set && !btc_blufi_wifi_conn_report_add(&n, 3)) {
return 0;
}
if (info->sta_conn_end_reason_set && !btc_blufi_wifi_conn_report_add(&n, 3)) {
return 0;
}
if (info->sta_conn_rssi_set && !btc_blufi_wifi_conn_report_add(&n, 3)) {
return 0;
}
return n;
}
static void btc_blufi_wifi_conn_report(uint8_t opmode, uint8_t sta_conn_state, uint8_t softap_conn_num, esp_blufi_extra_info_t *info, int info_len)
{
uint8_t type;
uint8_t *data;
int data_len;
uint8_t *p;
size_t buf_len;
data_len = info_len + 3;
p = data = osi_malloc(data_len);
(void)info_len;
buf_len = btc_blufi_wifi_conn_report_need(info);
if (buf_len == 0 || buf_len > BLUFI_WIFI_CONN_REP_MAX) {
BTC_TRACE_ERROR("%s invalid buffer size %u\n", __func__, (unsigned)buf_len);
return;
}
p = data = osi_malloc(buf_len);
if (data == NULL) {
BTC_TRACE_ERROR("%s no mem\n", __func__);
return;
@@ -352,28 +466,32 @@ static void btc_blufi_wifi_conn_report(uint8_t opmode, uint8_t sta_conn_state, u
p += 6;
}
if (info->sta_ssid) {
size_t sl = blufi_extra_field_len(info->sta_ssid_len, BLUFI_WIFI_SSID_MAX);
*p++ = BLUFI_TYPE_DATA_SUBTYPE_STA_SSID;
*p++ = info->sta_ssid_len;
memcpy(p, info->sta_ssid, info->sta_ssid_len);
p += info->sta_ssid_len;
*p++ = (uint8_t)sl;
memcpy(p, info->sta_ssid, sl);
p += sl;
}
if (info->sta_passwd) {
size_t pl = blufi_extra_field_len(info->sta_passwd_len, BLUFI_WIFI_PASS_MAX);
*p++ = BLUFI_TYPE_DATA_SUBTYPE_STA_PASSWD;
*p++ = info->sta_passwd_len;
memcpy(p, info->sta_passwd, info->sta_passwd_len);
p += info->sta_passwd_len;
*p++ = (uint8_t)pl;
memcpy(p, info->sta_passwd, pl);
p += pl;
}
if (info->softap_ssid) {
size_t sl = blufi_extra_field_len(info->softap_ssid_len, BLUFI_WIFI_SSID_MAX);
*p++ = BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_SSID;
*p++ = info->softap_ssid_len;
memcpy(p, info->softap_ssid, info->softap_ssid_len);
p += info->softap_ssid_len;
*p++ = (uint8_t)sl;
memcpy(p, info->softap_ssid, sl);
p += sl;
}
if (info->softap_passwd) {
size_t pl = blufi_extra_field_len(info->softap_passwd_len, BLUFI_WIFI_PASS_MAX);
*p++ = BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_PASSWD;
*p++ = info->softap_passwd_len;
memcpy(p, info->softap_passwd, info->softap_passwd_len);
p += info->softap_passwd_len;
*p++ = (uint8_t)pl;
memcpy(p, info->softap_passwd, pl);
p += pl;
}
if (info->softap_authmode_set) {
*p++ = BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_AUTH_MODE;
@@ -403,14 +521,16 @@ static void btc_blufi_wifi_conn_report(uint8_t opmode, uint8_t sta_conn_state, u
if (info->sta_conn_rssi_set) {
*p++ = BLUFI_TYPE_DATA_SUBTYPE_STA_CONN_RSSI;
*p++ = 1;
*p++ = info->sta_conn_rssi;
*p++ = (uint8_t)info->sta_conn_rssi;
}
}
if (p - data > data_len) {
BTC_TRACE_ERROR("%s len error %d %d\n", __func__, (int)(p - data), data_len);
if ((size_t)(p - data) != buf_len) {
BTC_TRACE_ERROR("%s len mismatch %d %u\n", __func__, (int)(p - data), (unsigned)buf_len);
osi_free(data);
return;
}
btc_blufi_send_encap(type, data, data_len);
btc_blufi_send_encap(type, data, (int)buf_len);
osi_free(data);
}
@@ -420,30 +540,48 @@ void btc_blufi_send_wifi_list(uint16_t apCount, esp_blufi_ap_record_t *list)
uint8_t *data;
int data_len;
uint8_t *p;
// malloc size: (len + RSSI + ssid buffer) * apCount;
uint32_t malloc_size = (1 + 1 + sizeof(list->ssid)) * apCount;
uint32_t entry_sz;
uint32_t malloc_size;
if (list == NULL || apCount == 0) {
return;
}
entry_sz = 1u + 1u + (uint32_t)sizeof(list[0].ssid);
/* The encoded WiFi list is later wrapped by btc_blufi_send_encap(),
* which rejects total_data_len > UINT16_MAX (single BLUFI frame limit).
* Cap apCount against that real ceiling here instead of the previous
* (uint16_t)(UINT32_MAX / entry_sz) check, which the narrowing cast
* silently truncated to 18439 entries (~645 KB) and let the buffer
* be allocated only to be discarded later by send_encap.
* The apCount value returned by WiFi is very small in practice, but
* we still want to fail fast and avoid a pointless large allocation. */
if ((uint32_t)apCount > (UINT16_MAX / entry_sz)) {
BTC_TRACE_ERROR("%s apCount %u exceeds BLUFI single-frame limit\n",
__func__, (unsigned)apCount);
return;
}
malloc_size = (uint32_t)apCount * entry_sz;
p = data = osi_malloc(malloc_size);
if (data == NULL) {
BTC_TRACE_ERROR("malloc error\n");
return;
}
type = BLUFI_BUILD_TYPE(BLUFI_TYPE_DATA, BLUFI_TYPE_DATA_SUBTYPE_WIFI_LIST);
for (int i = 0; i < apCount; ++i)
{
uint32_t len = strlen((const char *)list[i].ssid);
data_len = (p - data);
//current_len + ssid + rssi + total_len_value
if((data_len + len + 1 + 1) > malloc_size) {
for (int i = 0; i < apCount; ++i) {
size_t len = strnlen((const char *)list[i].ssid, sizeof(list[i].ssid));
data_len = (int)(p - data);
if ((uint32_t)data_len + len + 1u + 1u > malloc_size) {
BTC_TRACE_ERROR("%s len error", __func__);
osi_free(data);
return;
}
*p++ = len + 1; // length of ssid + rssi
*p++ = list[i].rssi;
*p++ = (uint8_t)(len + 1); /* length of ssid + rssi */
*p++ = (uint8_t)list[i].rssi;
memcpy(p, list[i].ssid, len);
p = p + len;
p += len;
}
data_len = (p - data);
data_len = (int)(p - data);
btc_blufi_send_encap(type, data, data_len);
osi_free(data);
}
@@ -506,76 +644,97 @@ void btc_blufi_cb_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
switch (msg->act) {
case ESP_BLUFI_EVENT_RECV_STA_SSID:
dst->sta_ssid.ssid = NULL;
dst->sta_ssid.ssid = osi_malloc(src->sta_ssid.ssid_len);
if (dst->sta_ssid.ssid == NULL) {
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
break;
}
memcpy(dst->sta_ssid.ssid, src->sta_ssid.ssid, src->sta_ssid.ssid_len);
break;
case ESP_BLUFI_EVENT_RECV_STA_PASSWD:
dst->sta_passwd.passwd = NULL;
dst->sta_passwd.passwd = osi_malloc(src->sta_passwd.passwd_len);
if (dst->sta_passwd.passwd == NULL) {
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
break;
}
memcpy(dst->sta_passwd.passwd, src->sta_passwd.passwd, src->sta_passwd.passwd_len);
break;
case ESP_BLUFI_EVENT_RECV_SOFTAP_SSID:
dst->softap_ssid.ssid = NULL;
dst->softap_ssid.ssid = osi_malloc(src->softap_ssid.ssid_len);
if (dst->softap_ssid.ssid == NULL) {
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
break;
}
memcpy(dst->softap_ssid.ssid, src->softap_ssid.ssid, src->softap_ssid.ssid_len);
break;
case ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD:
dst->softap_passwd.passwd = NULL;
dst->softap_passwd.passwd = osi_malloc(src->softap_passwd.passwd_len);
if (dst->softap_passwd.passwd == NULL) {
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
break;
}
memcpy(dst->softap_passwd.passwd, src->softap_passwd.passwd, src->softap_passwd.passwd_len);
break;
case ESP_BLUFI_EVENT_RECV_USERNAME:
dst->username.name = NULL;
dst->username.name = osi_malloc(src->username.name_len);
if (dst->username.name == NULL) {
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
break;
}
memcpy(dst->username.name, src->username.name, src->username.name_len);
break;
case ESP_BLUFI_EVENT_RECV_CA_CERT:
dst->ca.cert = NULL;
dst->ca.cert = osi_malloc(src->ca.cert_len);
if (dst->ca.cert == NULL) {
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
break;
}
memcpy(dst->ca.cert, src->ca.cert, src->ca.cert_len);
break;
case ESP_BLUFI_EVENT_RECV_CLIENT_CERT:
dst->client_cert.cert = NULL;
dst->client_cert.cert = osi_malloc(src->client_cert.cert_len);
if (dst->client_cert.cert == NULL) {
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
break;
}
memcpy(dst->client_cert.cert, src->client_cert.cert, src->client_cert.cert_len);
break;
case ESP_BLUFI_EVENT_RECV_SERVER_CERT:
dst->server_cert.cert = NULL;
dst->server_cert.cert = osi_malloc(src->server_cert.cert_len);
if (dst->server_cert.cert == NULL) {
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
break;
}
memcpy(dst->server_cert.cert, src->server_cert.cert, src->server_cert.cert_len);
break;
case ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY:
dst->client_pkey.pkey = NULL;
dst->client_pkey.pkey = osi_malloc(src->client_pkey.pkey_len);
if (dst->client_pkey.pkey == NULL) {
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
break;
}
memcpy(dst->client_pkey.pkey, src->client_pkey.pkey, src->client_pkey.pkey_len);
break;
case ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY:
dst->server_pkey.pkey = NULL;
dst->server_pkey.pkey = osi_malloc(src->server_pkey.pkey_len);
if (dst->server_pkey.pkey == NULL) {
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
break;
}
memcpy(dst->server_pkey.pkey, src->server_pkey.pkey, src->server_pkey.pkey_len);
break;
case ESP_BLUFI_EVENT_RECV_CUSTOM_DATA:
dst->custom_data.data = NULL;
dst->custom_data.data = osi_malloc(src->custom_data.data_len);
if (dst->custom_data.data == NULL) {
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
@@ -831,8 +990,8 @@ void btc_blufi_call_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
}
case BTC_BLUFI_ACT_SEND_WIFI_LIST:{
esp_blufi_ap_record_t *list = src->wifi_list.list;
src->wifi_list.list = NULL;
if (list == NULL || src->wifi_list.apCount <= 0) {
dst->wifi_list.list = NULL;
if (list == NULL || src->wifi_list.apCount == 0) {
break;
}
dst->wifi_list.list = (esp_blufi_ap_record_t *)osi_malloc(sizeof(esp_blufi_ap_record_t) * src->wifi_list.apCount);

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -13,6 +13,7 @@
#include "btc_blufi_prf.h"
#include "btc/btc_task.h"
#include "btc/btc_manage.h"
#include "osi/allocator.h"
#include "blufi_int.h"
@@ -27,6 +28,14 @@ void btc_blufi_protocol_handler(uint8_t type, uint8_t *data, int len)
int output_len = 0;
bool need_free = false;
#define BLUFI_REQUIRE_LEN_AT_LEAST(_n) \
if (len < (_n)) { \
BTC_TRACE_ERROR("%s pkt %02x len too short: %d\n", \
__func__, type, len); \
btc_blufi_report_error(ESP_BLUFI_DATA_FORMAT_ERROR); \
break; \
}
switch (BLUFI_GET_TYPE(type)) {
case BLUFI_TYPE_CTRL:
switch (BLUFI_GET_SUBTYPE(type)) {
@@ -34,9 +43,11 @@ void btc_blufi_protocol_handler(uint8_t type, uint8_t *data, int len)
/* TODO: check sequence */
break;
case BLUFI_TYPE_CTRL_SUBTYPE_SET_SEC_MODE:
BLUFI_REQUIRE_LEN_AT_LEAST(1);
blufi_env.sec_mode = data[0];
break;
case BLUFI_TYPE_CTRL_SUBTYPE_SET_WIFI_OPMODE:
BLUFI_REQUIRE_LEN_AT_LEAST(1);
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_BLUFI;
msg.act = ESP_BLUFI_EVENT_SET_WIFI_OPMODE;
@@ -109,11 +120,16 @@ void btc_blufi_protocol_handler(uint8_t type, uint8_t *data, int len)
btc_blufi_send_encap(BLUFI_BUILD_TYPE(BLUFI_TYPE_DATA, BLUFI_TYPE_DATA_SUBTYPE_NEG),
output_data, output_len);
}
if (need_free && output_data) {
osi_free(output_data);
output_data = NULL;
}
break;
case BLUFI_TYPE_DATA_SUBTYPE_STA_BSSID:
if (len < 6) {
BTC_TRACE_ERROR("%s STA_BSSID data too short: %d\n", __func__, len);
return;
btc_blufi_report_error(ESP_BLUFI_DATA_FORMAT_ERROR);
break;
}
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_BLUFI;
@@ -159,6 +175,7 @@ void btc_blufi_protocol_handler(uint8_t type, uint8_t *data, int len)
btc_transfer_context(&msg, &param, sizeof(esp_blufi_cb_param_t), btc_blufi_cb_deep_copy, btc_blufi_cb_deep_free);
break;
case BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_MAX_CONN_NUM:
BLUFI_REQUIRE_LEN_AT_LEAST(1);
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_BLUFI;
msg.act = ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM;
@@ -167,6 +184,7 @@ void btc_blufi_protocol_handler(uint8_t type, uint8_t *data, int len)
btc_transfer_context(&msg, &param, sizeof(esp_blufi_cb_param_t), NULL, NULL);
break;
case BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_AUTH_MODE:
BLUFI_REQUIRE_LEN_AT_LEAST(1);
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_BLUFI;
msg.act = ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE;
@@ -175,6 +193,7 @@ void btc_blufi_protocol_handler(uint8_t type, uint8_t *data, int len)
btc_transfer_context(&msg, &param, sizeof(esp_blufi_cb_param_t), NULL, NULL);
break;
case BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_CHANNEL:
BLUFI_REQUIRE_LEN_AT_LEAST(1);
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_BLUFI;
msg.act = ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL;
@@ -252,6 +271,8 @@ void btc_blufi_protocol_handler(uint8_t type, uint8_t *data, int len)
default:
break;
}
#undef BLUFI_REQUIRE_LEN_AT_LEAST
}
#endif ///BLUFI_INCLUDED == TRUE

View File

@@ -18,6 +18,7 @@
#ifdef CONFIG_BT_BLUEDROID_ENABLED
#include "esp_gap_ble_api.h"
#include "esp_gatt_defs.h"
#endif
#ifdef __cplusplus
@@ -61,7 +62,7 @@ void esp_blufi_btc_deinit(void);
* - other : failed
*
*/
esp_err_t esp_blufi_close(uint8_t gatts_if, uint16_t conn_id);
esp_err_t esp_blufi_close(esp_gatt_if_t gatts_if, uint16_t conn_id);
void esp_blufi_gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
#endif

View File

@@ -30,7 +30,7 @@ extern "C" {
#define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]
#define GATT_UUID_CHAR_CLIENT_CONFIG 0x2902 /* Client Characteristic Configuration */
//define the blufi serivce uuid
//define the blufi service uuid
#define BLUFI_SERVICE_UUID 0xFFFF
//define the blufi Char uuid (PHONE to ESP32)
#define BLUFI_CHAR_P2E_UUID 0xFF01
@@ -98,6 +98,7 @@ void btc_blufi_cb_handler(btc_msg_t *msg);
void btc_blufi_call_handler(btc_msg_t *msg);
void btc_blufi_set_callbacks(esp_blufi_callbacks_t *callbacks);
void btc_blufi_report_error(esp_blufi_error_state_t state);
void btc_blufi_recv_handler(uint8_t *data, int len);
void btc_blufi_send_notify(uint8_t *pkt, int pkt_len);
void btc_blufi_call_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -13,9 +13,14 @@
#include "esp_timer.h"
#if (BT_HCI_LOG_INCLUDED == TRUE)
static const char *const TAG = "bt_hci_log";
#define BT_HCI_LOG_PRINT_TAG (1)
#define BT_HCI_LOG_DATA_BUF_SIZE (1024 * HCI_LOG_DATA_BUFFER_SIZE)
#define BT_HCI_LOG_ADV_BUF_SIZE (1024 * HCI_LOG_ADV_BUFFER_SIZE)
/* Max payload per HCI log line; larger inputs are dropped (not logged). */
#define BT_HCI_LOG_RECORD_PAYLOAD_MAX (2048U)
typedef struct {
osi_mutex_t mutex_lock;
@@ -64,8 +69,14 @@ esp_err_t bt_hci_log_init(void)
g_bt_hci_log_adv_ctl.buf_size = BT_HCI_LOG_ADV_BUF_SIZE;
g_bt_hci_log_adv_ctl.p_hci_log_buffer = g_bt_hci_log_adv_buffer;
osi_mutex_new((osi_mutex_t *)&g_bt_hci_log_data_ctl.mutex_lock);
osi_mutex_new((osi_mutex_t *)&g_bt_hci_log_adv_ctl.mutex_lock);
if (osi_mutex_new((osi_mutex_t *)&g_bt_hci_log_data_ctl.mutex_lock) != 0) {
bt_hci_log_deinit();
return ESP_FAIL;
}
if (osi_mutex_new((osi_mutex_t *)&g_bt_hci_log_adv_ctl.mutex_lock) != 0) {
bt_hci_log_deinit();
return ESP_FAIL;
}
return ESP_OK;
}
@@ -191,9 +202,16 @@ void bt_hci_log_record_string(bt_hci_log_t *p_hci_log_ctl, char *string)
g_hci_log_buffer = p_hci_log_ctl->p_hci_log_buffer;
while (*string != '\0') {
g_hci_log_buffer[p_hci_log_ctl->log_record_in] = *string;
++string;
if (string == NULL) {
return;
}
/* Avoid unbounded memory scan if string is not NUL-terminated. */
const size_t max_len = 256;
size_t len = strnlen(string, max_len);
for (size_t i = 0; i < len; i++) {
g_hci_log_buffer[p_hci_log_ctl->log_record_in] = (uint8_t)string[i];
if (++p_hci_log_ctl->log_record_in >= p_hci_log_ctl->buf_size) {
p_hci_log_ctl->log_record_in = 0;
@@ -211,6 +229,7 @@ esp_err_t IRAM_ATTR bt_hci_log_record_data(bt_hci_log_t *p_hci_log_ctl, char *st
uint8_t *g_hci_log_buffer;
int64_t ts;
uint8_t *temp_buf;
uint16_t record_len;
if (!p_hci_log_ctl->p_hci_log_buffer) {
return ESP_FAIL;
@@ -221,21 +240,34 @@ esp_err_t IRAM_ATTR bt_hci_log_record_data(bt_hci_log_t *p_hci_log_ctl, char *st
if (!g_hci_log_buffer) {
return ESP_FAIL;
}
if (p_hci_log_ctl->mutex_lock == NULL) {
return ESP_FAIL;
}
if ((data_len == 0) || (data == NULL)) {
return ESP_ERR_INVALID_ARG;
}
ts = esp_timer_get_time();
temp_buf = (uint8_t *)malloc(data_len + 8);
if (data_len > BT_HCI_LOG_RECORD_PAYLOAD_MAX) {
ESP_LOGW(TAG, "HCI log record dropped: data_len=%u (max %u)",
(unsigned)data_len, (unsigned)BT_HCI_LOG_RECORD_PAYLOAD_MAX);
return ESP_FAIL;
}
record_len = (uint16_t)((uint32_t)data_len + 8U);
temp_buf = (uint8_t *)malloc((size_t)record_len);
if (!temp_buf) {
return ESP_ERR_NO_MEM;
}
memset(temp_buf, 0x0, data_len + 8);
memset(temp_buf, 0x0, (size_t)record_len);
memcpy(temp_buf, &ts, 8);
memcpy(temp_buf + 8, data, data_len);
data_len += 8;
mutex_lock = p_hci_log_ctl->mutex_lock;
osi_mutex_lock(&mutex_lock, OSI_MUTEX_MAX_TIMEOUT);
@@ -267,7 +299,7 @@ esp_err_t IRAM_ATTR bt_hci_log_record_data(bt_hci_log_t *p_hci_log_ctl, char *st
bt_hci_log_record_string(p_hci_log_ctl, str);
}
bt_hci_log_record_hex(p_hci_log_ctl, temp_buf, data_len);
bt_hci_log_record_hex(p_hci_log_ctl, temp_buf, record_len);
g_hci_log_buffer[p_hci_log_ctl->log_record_in] = '\n';
@@ -296,6 +328,9 @@ void bt_hci_log_data_show(bt_hci_log_t *p_hci_log_ctl)
if (!p_hci_log_ctl->p_hci_log_buffer) {
return;
}
if (p_hci_log_ctl->mutex_lock == NULL) {
return;
}
osi_mutex_t mutex_lock = p_hci_log_ctl->mutex_lock;

View File

@@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <assert.h>
#if !defined(ESP_ASSUME_NONNULL)
#if defined(CONFIG_COMPILER_OPTIMIZATION_DEBUG) || defined(CONFIG_BT_NIMBLE_DEBUG) || !defined(NDEBUG)
/* Debug: fail fast if upstream contract is broken */
#define ESP_ASSUME_NONNULL(p) do { assert((p) != NULL); } while (0)
#else
/* Release: contract only (no extra code size) */
#define ESP_ASSUME_NONNULL(p) do { (void)(p); } while (0)
#endif
#endif

View File

@@ -323,9 +323,20 @@ bool osi_alarm_is_active(osi_alarm_t *alarm)
{
assert(alarm != NULL);
if (alarm->alarm_hdl != NULL) {
return esp_timer_is_active(alarm->alarm_hdl);
assert(alarm_mutex != NULL);
bool active = false;
osi_mutex_lock(&alarm_mutex, OSI_MUTEX_MAX_TIMEOUT);
if (alarm_state != ALARM_STATE_OPEN) {
active = false;
goto end;
}
return false;
if (alarm->alarm_hdl != NULL) {
active = esp_timer_is_active(alarm->alarm_hdl);
}
end:
osi_mutex_unlock(&alarm_mutex);
return active;
}

View File

@@ -16,6 +16,7 @@
#include <string.h>
#include "bt_common.h"
#include "esp_assume.h"
#include "osi/allocator.h"
#include "osi/config.h"
#include "osi/list.h"
@@ -40,7 +41,7 @@ struct config_t {
// Empty definition; this type is aliased to list_node_t.
struct config_section_iter_t {};
static void config_parse(nvs_handle_t fp, config_t *config);
static bool config_parse(nvs_handle_t fp, config_t *config);
static section_t *section_new(const char *name);
static void section_free(void *ptr);
@@ -94,8 +95,12 @@ config_t *config_new(const char *filename)
return NULL;
}
config_parse(fp, config);
bool ok = config_parse(fp, config);
nvs_close(fp);
if (!ok) {
config_free(config);
return NULL;
}
return config;
}
@@ -136,7 +141,7 @@ bool config_has_key_in_section(config_t *config, const char *key, char *key_valu
entry_t *entry = list_node(node);
OSI_TRACE_DEBUG("entry->key = %s, entry->value = %s", entry->key, entry->value);
if (!strcmp(entry->key, key) && !strcmp(entry->value, key_value)) {
OSI_TRACE_DEBUG("%s, the irk aready in the flash.", __func__);
OSI_TRACE_DEBUG("%s, the irk already in the flash.", __func__);
return true;
}
}
@@ -221,6 +226,10 @@ void config_set_string(config_t *config, const char *section, const char *key, c
section_t *sec = section_find(config, section);
if (!sec) {
sec = section_new(section);
if (sec == NULL) {
OSI_TRACE_ERROR("%s unable to allocate section\n", __func__);
return;
}
if (insert_back) {
list_append(config->sections, sec);
} else {
@@ -231,13 +240,22 @@ void config_set_string(config_t *config, const char *section, const char *key, c
for (const list_node_t *node = list_begin(sec->entries); node != list_end(sec->entries); node = list_next(node)) {
entry_t *entry = list_node(node);
if (!strcmp(entry->key, key)) {
char *new_value = osi_strdup(value);
if (new_value == NULL) {
OSI_TRACE_ERROR("%s unable to allocate entry value\n", __func__);
return;
}
osi_free(entry->value);
entry->value = osi_strdup(value);
entry->value = new_value;
return;
}
}
entry_t *entry = entry_new(key, value);
if (entry == NULL) {
OSI_TRACE_ERROR("%s unable to allocate entry\n", __func__);
return;
}
list_append(sec->entries, entry);
}
@@ -327,32 +345,57 @@ const char *config_section_name(const config_section_node_t *node)
return section->name;
}
static int get_config_size(const config_t *config)
static bool get_config_size(const config_t *config, size_t *out_size)
{
assert(config != NULL);
assert(out_size != NULL);
int w_len = 0, total_size = 0;
size_t total_size = 0;
for (const list_node_t *node = list_begin(config->sections); node != list_end(config->sections); node = list_next(node)) {
const section_t *section = (const section_t *)list_node(node);
w_len = strlen(section->name) + strlen("[]\n");// format "[section->name]\n"
/* CONTRACT / PRECONDITION:
* - section->name is guaranteed non-NULL.
* - Upstream guard: section_new() stores osi_strdup(name) from config_set_string().
*/
ESP_ASSUME_NONNULL(section->name);
size_t w_len = strlen(section->name) + strlen("[]\n"); // format "[section->name]\n"
if (total_size > SIZE_MAX - w_len) {
return false;
}
total_size += w_len;
for (const list_node_t *enode = list_begin(section->entries); enode != list_end(section->entries); enode = list_next(enode)) {
const entry_t *entry = (const entry_t *)list_node(enode);
w_len = strlen(entry->key) + strlen(entry->value) + strlen(" = \n");// format "entry->key = entry->value\n"
/* CONTRACT / PRECONDITION:
* - entry->key/value are guaranteed non-NULL.
* - Upstream guard: entry_new() stores osi_strdup(key/value) from config_set_string().
*/
ESP_ASSUME_NONNULL(entry->key);
ESP_ASSUME_NONNULL(entry->value);
w_len = strlen(entry->key) + strlen(entry->value) + strlen(" = \n"); // format "entry->key = entry->value\n"
if (total_size > SIZE_MAX - w_len) {
return false;
}
total_size += w_len;
}
// Only add a separating newline if there are more sections.
if (list_next(node) != list_end(config->sections)) {
total_size ++; //'\n'
if (total_size == SIZE_MAX) {
return false;
}
total_size++; // '\n'
} else {
break;
}
}
total_size ++; //'\0'
return total_size;
if (total_size == SIZE_MAX) {
return false;
}
total_size++; // '\0'
*out_size = total_size;
return true;
}
static int get_config_size_from_flash(nvs_handle_t fp)
@@ -364,7 +407,7 @@ static int get_config_size_from_flash(nvs_handle_t fp)
char *keyname = osi_calloc(keyname_bufsz);
if (!keyname){
OSI_TRACE_ERROR("%s, malloc error\n", __func__);
return 0;
return -1;
}
size_t length = CONFIG_FILE_DEFAULE_LENGTH;
size_t total_length = 0;
@@ -378,7 +421,7 @@ static int get_config_size_from_flash(nvs_handle_t fp)
if (err != ESP_OK) {
OSI_TRACE_ERROR("%s, error %d\n", __func__, err);
osi_free(keyname);
return 0;
return -2;
}
total_length += length;
while (length == CONFIG_FILE_MAX_SIZE) {
@@ -392,7 +435,7 @@ static int get_config_size_from_flash(nvs_handle_t fp)
if (err != ESP_OK) {
OSI_TRACE_ERROR("%s, error %d\n", __func__, err);
osi_free(keyname);
return 0;
return -3;
}
total_length += length;
}
@@ -409,12 +452,21 @@ bool config_save(const config_t *config, const char *filename)
esp_err_t err;
int err_code = 0;
nvs_handle_t fp;
char *line = osi_calloc(1024);
char *buf = NULL;
bool nvs_opened = false;
const size_t keyname_bufsz = sizeof(CONFIG_KEY) + 5 + 1; // including log10(sizeof(i))
char *keyname = osi_calloc(keyname_bufsz);
int config_size = get_config_size(config);
char *buf = osi_calloc(config_size);
if (!line || !buf || !keyname) {
if (!keyname) {
err_code |= 0x01;
goto error;
}
size_t config_size = 0;
if (!get_config_size(config, &config_size) || config_size == 0) {
err_code |= 0x01;
goto error;
}
buf = osi_calloc(config_size);
if (!buf) {
err_code |= 0x01;
goto error;
}
@@ -428,63 +480,67 @@ bool config_save(const config_t *config, const char *filename)
err_code |= 0x02;
goto error;
}
nvs_opened = true;
int w_cnt, w_cnt_total = 0;
int w_cnt;
size_t w_cnt_total = 0;
for (const list_node_t *node = list_begin(config->sections); node != list_end(config->sections); node = list_next(node)) {
const section_t *section = (const section_t *)list_node(node);
w_cnt = snprintf(line, 1024, "[%s]\n", section->name);
if(w_cnt < 0) {
OSI_TRACE_ERROR("snprintf error w_cnt %d.",w_cnt);
err_code |= 0x10;
goto error;
}
if(w_cnt_total + w_cnt > config_size) {
OSI_TRACE_ERROR("%s, memcpy size (w_cnt + w_cnt_total = %d) is larger than buffer size (config_size = %d).", __func__, (w_cnt + w_cnt_total), config_size);
size_t remaining = (w_cnt_total < config_size) ? (config_size - w_cnt_total) : 0;
if (remaining == 0) {
err_code |= 0x20;
goto error;
}
OSI_TRACE_DEBUG("section name: %s, w_cnt + w_cnt_total = %d\n", section->name, w_cnt + w_cnt_total);
memcpy(buf + w_cnt_total, line, w_cnt);
w_cnt_total += w_cnt;
w_cnt = snprintf(buf + w_cnt_total, remaining, "[%s]\n", section->name);
if (w_cnt < 0 || (size_t)w_cnt >= remaining) {
err_code |= 0x20;
goto error;
}
OSI_TRACE_DEBUG("section name: %s, w_cnt + w_cnt_total = %d\n", section->name, (int)(w_cnt + w_cnt_total));
w_cnt_total += (size_t)w_cnt;
for (const list_node_t *enode = list_begin(section->entries); enode != list_end(section->entries); enode = list_next(enode)) {
const entry_t *entry = (const entry_t *)list_node(enode);
OSI_TRACE_DEBUG("(key, val): (%s, %s)\n", entry->key, entry->value);
w_cnt = snprintf(line, 1024, "%s = %s\n", entry->key, entry->value);
if(w_cnt < 0) {
OSI_TRACE_ERROR("snprintf error w_cnt %d.",w_cnt);
err_code |= 0x10;
goto error;
}
if(w_cnt_total + w_cnt > config_size) {
OSI_TRACE_ERROR("%s, memcpy size (w_cnt + w_cnt_total = %d) is larger than buffer size.(config_size = %d)", __func__, (w_cnt + w_cnt_total), config_size);
remaining = (w_cnt_total < config_size) ? (config_size - w_cnt_total) : 0;
if (remaining == 0) {
err_code |= 0x20;
goto error;
}
OSI_TRACE_DEBUG("%s, w_cnt + w_cnt_total = %d", __func__, w_cnt + w_cnt_total);
memcpy(buf + w_cnt_total, line, w_cnt);
w_cnt_total += w_cnt;
w_cnt = snprintf(buf + w_cnt_total, remaining, "%s = %s\n", entry->key, entry->value);
if (w_cnt < 0 || (size_t)w_cnt >= remaining) {
err_code |= 0x20;
goto error;
}
OSI_TRACE_DEBUG("%s, w_cnt + w_cnt_total = %d", __func__, (int)(w_cnt + w_cnt_total));
w_cnt_total += (size_t)w_cnt;
}
// Only add a separating newline if there are more sections.
if (list_next(node) != list_end(config->sections)) {
buf[w_cnt_total] = '\n';
w_cnt_total += 1;
if (w_cnt_total + 1 >= config_size) {
err_code |= 0x20;
goto error;
}
buf[w_cnt_total++] = '\n';
} else {
break;
}
}
if (w_cnt_total >= config_size) {
err_code |= 0x20;
goto error;
}
buf[w_cnt_total] = '\0';
if (w_cnt_total < CONFIG_FILE_MAX_SIZE) {
snprintf(keyname, keyname_bufsz, "%s%d", CONFIG_KEY, 0);
err = nvs_set_blob(fp, keyname, buf, w_cnt_total);
if (err != ESP_OK) {
nvs_close(fp);
err_code |= 0x04;
goto error;
}
}else {
int count = (w_cnt_total / CONFIG_FILE_MAX_SIZE);
int count = (int)(w_cnt_total / CONFIG_FILE_MAX_SIZE);
assert(count <= 0xFF);
for (uint8_t i = 0; i <= count; i++)
{
@@ -497,7 +553,6 @@ bool config_save(const config_t *config, const char *filename)
OSI_TRACE_DEBUG("save keyname = %s, i = %d, %d\n", keyname, i, CONFIG_FILE_MAX_SIZE);
}
if (err != ESP_OK) {
nvs_close(fp);
err_code |= 0x04;
goto error;
}
@@ -506,24 +561,23 @@ bool config_save(const config_t *config, const char *filename)
err = nvs_commit(fp);
if (err != ESP_OK) {
nvs_close(fp);
err_code |= 0x08;
goto error;
}
nvs_close(fp);
osi_free(line);
nvs_opened = false;
osi_free(buf);
osi_free(keyname);
return true;
error:
if (nvs_opened) {
nvs_close(fp);
}
if (buf) {
osi_free(buf);
}
if (line) {
osi_free(line);
}
if (keyname) {
osi_free(keyname);
}
@@ -552,7 +606,7 @@ static char *trim(char *str)
return str;
}
static void config_parse(nvs_handle_t fp, config_t *config)
static bool config_parse(nvs_handle_t fp, config_t *config)
{
assert(fp != 0);
assert(config != NULL);
@@ -570,9 +624,14 @@ static void config_parse(nvs_handle_t fp, config_t *config)
int buf_size = get_config_size_from_flash(fp);
char *buf = NULL;
if(buf_size == 0) { //First use nvs
if (buf_size < 0) {
err_code |= 0x04;
goto error;
}
if(buf_size == 0) { //First use nvs
goto ok;
}
buf = osi_calloc(buf_size);
if (!line || !section || !buf || !keyname) {
err_code |= 0x01;
@@ -581,7 +640,7 @@ static void config_parse(nvs_handle_t fp, config_t *config)
snprintf(keyname, keyname_bufsz, "%s%d", CONFIG_KEY, 0);
err = nvs_get_blob(fp, keyname, buf, &length);
if (err == ESP_ERR_NVS_NOT_FOUND) {
goto error;
goto ok;
}
if (err != ESP_OK) {
err_code |= 0x02;
@@ -644,6 +703,21 @@ static void config_parse(nvs_handle_t fp, config_t *config)
}
}
ok:
if (buf) {
osi_free(buf);
}
if (line) {
osi_free(line);
}
if (section) {
osi_free(section);
}
if (keyname) {
osi_free(keyname);
}
return true;
error:
if (buf) {
osi_free(buf);
@@ -660,6 +734,7 @@ error:
if (err_code) {
OSI_TRACE_ERROR("%s returned with err code: %d\n", __func__, err_code);
}
return false;
}
static section_t *section_new(const char *name)
@@ -671,6 +746,10 @@ static section_t *section_new(const char *name)
section->name = osi_strdup(name);
section->entries = list_new(entry_free);
if (section->name == NULL || section->entries == NULL) {
section_free(section);
return NULL;
}
return section;
}
@@ -707,6 +786,10 @@ static entry_t *entry_new(const char *key, const char *value)
entry->key = osi_strdup(key);
entry->value = osi_strdup(value);
if (entry->key == NULL || entry->value == NULL) {
entry_free(entry);
return NULL;
}
return entry;
}

View File

@@ -22,6 +22,7 @@
#include "osi/osi.h"
#include "osi/mutex.h"
#include "osi/semaphore.h"
#include "esp_assume.h"
typedef struct fixed_queue_t {
@@ -43,6 +44,12 @@ fixed_queue_t *fixed_queue_new(size_t capacity)
}
osi_mutex_new(&ret->lock);
/* CONTRACT / PRECONDITION:
* - ret->lock is guaranteed non-NULL after successful osi_mutex_new().
* - Rationale: treat mutex allocation failure as fatal in debug builds;
* release builds do not add extra code size.
*/
ESP_ASSUME_NONNULL(ret->lock);
ret->capacity = capacity;
ret->list = list_new(NULL);

View File

@@ -138,26 +138,37 @@ bool hash_map_set(hash_map_t *hash_map, const void *key, void *data)
}
list_t *hash_bucket_list = hash_map->bucket[hash_key].list;
hash_map_entry_t *hash_map_entry = find_bucket_entry_(hash_bucket_list, key);
/* Allocate the new entry FIRST, before touching any existing entry.
* This preserves the atomicity of hash_map_set: on failure the map
* stays exactly as it was, and the caller's previously-stored
* key/data remain valid. */
hash_map_entry_t *new_entry = osi_calloc(sizeof(hash_map_entry_t));
if (new_entry == NULL) {
return false;
}
new_entry->key = key;
new_entry->data = data;
new_entry->hash_map = hash_map;
if (hash_map_entry) {
// Calls hash_map callback to delete the hash_map_entry.
bool rc = list_remove(hash_bucket_list, hash_map_entry);
hash_map_entry_t *old_entry = find_bucket_entry_(hash_bucket_list, key);
if (!list_append(hash_bucket_list, new_entry)) {
osi_free(new_entry);
return false;
}
/* Only after the new entry has been successfully inserted do we
* destroy the old one (which frees the previous key/data via
* bucket_free_). For a brand-new key, bump hash_size instead. */
if (old_entry) {
bool rc = list_remove(hash_bucket_list, old_entry);
assert(rc == true);
(void)rc;
} else {
hash_map->hash_size++;
}
hash_map_entry = osi_calloc(sizeof(hash_map_entry_t));
if (hash_map_entry == NULL) {
return false;
}
hash_map_entry->key = key;
hash_map_entry->data = data;
hash_map_entry->hash_map = hash_map;
return list_append(hash_bucket_list, hash_map_entry);
return true;
}
bool hash_map_erase(hash_map_t *hash_map, const void *key)

View File

@@ -181,8 +181,9 @@ bool list_remove(list_t *list, void *data)
}
if (list->head->data == data) {
const bool was_tail = (list->tail == list->head);
list_node_t *next = list_free_node(list, list->head);
if (list->tail == list->head) {
if (was_tail) {
list->tail = next;
}
list->head = next;
@@ -191,8 +192,9 @@ bool list_remove(list_t *list, void *data)
for (list_node_t *prev = list->head, *node = list->head->next; node; prev = node, node = node->next)
if (node->data == data) {
const bool was_tail = (list->tail == node);
prev->next = list_free_node(list, node);
if (list->tail == node) {
if (was_tail) {
list->tail = prev;
}
return true;
@@ -211,8 +213,9 @@ bool list_delete(list_t *list, void *data)
}
if (list->head->data == data) {
const bool was_tail = (list->tail == list->head);
list_node_t *next = list_delete_node(list, list->head);
if (list->tail == list->head) {
if (was_tail) {
list->tail = next;
}
list->head = next;
@@ -221,8 +224,9 @@ bool list_delete(list_t *list, void *data)
for (list_node_t *prev = list->head, *node = list->head->next; node; prev = node, node = node->next)
if (node->data == data) {
const bool was_tail = (list->tail == node);
prev->next = list_delete_node(list, node);
if (list->tail == node) {
if (was_tail) {
list->tail = prev;
}
return true;

View File

@@ -16,6 +16,8 @@
*
******************************************************************************/
#include <assert.h>
#include "osi/mutex.h"
@@ -90,15 +92,21 @@ int osi_mutex_global_init(void)
void osi_mutex_global_deinit(void)
{
if (gl_mutex == NULL) {
return;
}
vSemaphoreDelete(gl_mutex);
gl_mutex = NULL;
}
void osi_mutex_global_lock(void)
{
assert(gl_mutex != NULL);
xSemaphoreTakeRecursive(gl_mutex, portMAX_DELAY);
}
void osi_mutex_global_unlock(void)
{
assert(gl_mutex != NULL);
xSemaphoreGiveRecursive(gl_mutex);
}

View File

@@ -68,7 +68,9 @@ bool hci_host_check_send_available(void)
void hci_host_send_packet(uint8_t *data, uint16_t len)
{
#if (BT_HCI_LOG_INCLUDED == TRUE)
bt_hci_log_record_hci_data(data[0], &data[1], len - 1);
if (data != NULL && len > 1) {
bt_hci_log_record_hci_data(data[0], &data[1], (uint16_t)(len - 1));
}
#endif
#if CONFIG_BT_BLE_LOG_SPI_OUT_HCI_ENABLED
ble_log_spi_out_hci_write(BLE_LOG_SPI_OUT_SOURCE_HCI_DOWNSTREAM, data, len);

View File

@@ -224,7 +224,9 @@ esp_err_t esp_bluedroid_init_with_cfg(esp_bluedroid_config_t *cfg)
}
#if (BT_HCI_LOG_INCLUDED == TRUE)
bt_hci_log_init();
if (bt_hci_log_init() != ESP_OK) {
LOG_WARN("HCI log facility unavailable, continuing without HCI log\n");
}
#endif // (BT_HCI_LOG_INCLUDED == TRUE)
s_bt_host_state = ESP_BLUEDROID_STATUS_INITIALIZED;

View File

@@ -92,7 +92,7 @@ bool btc_config_init(void)
config = config_new(CONFIG_FILE_PATH);
if (!config) {
BTC_TRACE_WARNING("%s unable to load config file; starting unconfigured.\n", __func__);
BTC_TRACE_WARNING("%s unable to load/parse config; starting unconfigured without overwriting NVS.\n", __func__);
config = config_new_empty();
if (!config) {
BTC_TRACE_ERROR("%s unable to allocate a config object.\n", __func__);
@@ -345,14 +345,17 @@ int btc_config_clear(void)
{
assert(config != NULL);
config_free(config);
btc_config_lock();
config_free(config);
config = config_new_empty();
if (config == NULL) {
return false;
btc_config_unlock();
return -1;
}
int ret = config_save(config, CONFIG_FILE_PATH);
return ret;
bool ret = config_save(config, CONFIG_FILE_PATH);
btc_config_unlock();
return ret ? 0 : -1;
}
void btc_config_lock(void)

View File

@@ -593,7 +593,7 @@ static void btc_gap_ble_adv_pkt_handler(void *arg)
}
}
if (pkt_queue_length(p_env->adv_rpt_queue) != 0) {
if (p_env->adv_rpt_ready && pkt_queue_length(p_env->adv_rpt_queue) != 0) {
osi_thread_post_event(p_env->adv_rpt_ready, OSI_THREAD_MAX_TIMEOUT);
}
}
@@ -628,7 +628,9 @@ static void btc_process_adv_rpt_pkt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_
} while (0);
pkt_queue_enqueue(p_env->adv_rpt_queue, linked_pkt);
osi_thread_post_event(p_env->adv_rpt_ready, OSI_THREAD_MAX_TIMEOUT);
if (p_env->adv_rpt_ready) {
osi_thread_post_event(p_env->adv_rpt_ready, OSI_THREAD_MAX_TIMEOUT);
}
}
static void btc_search_callback(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data)
@@ -3412,15 +3414,34 @@ void btc_gap_ble_deinit(void)
#if (BLE_42_SCAN_EN == TRUE)
btc_gap_ble_env_t *p_env = &btc_gap_ble_env;
osi_event_delete(p_env->adv_rpt_ready);
struct osi_event *adv_evt = p_env->adv_rpt_ready;
p_env->adv_rpt_ready = NULL;
if (adv_evt) {
osi_event_delete(adv_evt);
}
pkt_queue_destroy(p_env->adv_rpt_queue, NULL);
p_env->adv_rpt_queue = NULL;
if (p_env->adv_rpt_queue) {
pkt_queue_destroy(p_env->adv_rpt_queue, NULL);
p_env->adv_rpt_queue = NULL;
}
#endif // #if (BLE_42_SCAN_EN == TRUE)
#if (BLE_42_ADV_EN == TRUE)
/* Under BTC_DYNAMIC_MEMORY, gl_bta_adv_data is a macro that dereferences
* gl_bta_adv_data_ptr. Guard against the case where the pointer is NULL
* (e.g. btc_init_mem() failed midway, or btc_deinit() is invoked twice)
* to avoid &(*NULL) UB before reaching btc_cleanup_adv_data()'s NULL
* check. */
#if (BTC_DYNAMIC_MEMORY == TRUE)
if (gl_bta_adv_data_ptr) {
btc_cleanup_adv_data(&gl_bta_adv_data);
}
if (gl_bta_scan_rsp_data_ptr) {
btc_cleanup_adv_data(&gl_bta_scan_rsp_data);
}
#else
btc_cleanup_adv_data(&gl_bta_adv_data);
btc_cleanup_adv_data(&gl_bta_scan_rsp_data);
#endif // #if (BTC_DYNAMIC_MEMORY == TRUE)
#endif // #if (BLE_42_ADV_EN == TRUE)
#endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)
}

View File

@@ -461,11 +461,10 @@ void btu_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_sec)
return;
}
}
osi_mutex_unlock(&btu_general_alarm_lock);
alarm = hash_map_get(btu_general_alarm_hash_map, p_tle);
if (alarm == NULL) {
HCI_TRACE_ERROR("%s Unable to create alarm", __func__);
osi_mutex_unlock(&btu_general_alarm_lock);
return;
}
osi_alarm_cancel(alarm);
@@ -475,6 +474,7 @@ void btu_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_sec)
p_tle->ticks = timeout_sec;
p_tle->in_use = TRUE;
osi_alarm_set(alarm, (period_ms_t)((period_ms_t)timeout_sec * 1000));
osi_mutex_unlock(&btu_general_alarm_lock);
}
@@ -491,18 +491,21 @@ void btu_stop_timer(TIMER_LIST_ENT *p_tle)
{
assert(p_tle != NULL);
osi_mutex_lock(&btu_general_alarm_lock, OSI_MUTEX_MAX_TIMEOUT);
if (p_tle->in_use == FALSE) {
osi_mutex_unlock(&btu_general_alarm_lock);
return;
}
p_tle->in_use = FALSE;
// Get the alarm for the timer list entry.
osi_alarm_t *alarm = hash_map_get(btu_general_alarm_hash_map, p_tle);
if (alarm == NULL) {
HCI_TRACE_WARNING("%s Unable to find expected alarm in hashmap", __func__);
p_tle->in_use = FALSE;
osi_mutex_unlock(&btu_general_alarm_lock);
return;
}
osi_alarm_cancel(alarm);
p_tle->in_use = FALSE;
osi_mutex_unlock(&btu_general_alarm_lock);
}
/*******************************************************************************
@@ -518,16 +521,18 @@ void btu_free_timer(TIMER_LIST_ENT *p_tle)
{
assert(p_tle != NULL);
p_tle->in_use = FALSE;
// Get the alarm for the timer list entry.
osi_mutex_lock(&btu_general_alarm_lock, OSI_MUTEX_MAX_TIMEOUT);
osi_alarm_t *alarm = hash_map_get(btu_general_alarm_hash_map, p_tle);
if (alarm == NULL) {
HCI_TRACE_DEBUG("%s Unable to find expected alarm in hashmap", __func__);
p_tle->in_use = FALSE;
osi_mutex_unlock(&btu_general_alarm_lock);
return;
}
osi_alarm_cancel(alarm);
hash_map_erase(btu_general_alarm_hash_map, p_tle);
p_tle->in_use = FALSE;
osi_mutex_unlock(&btu_general_alarm_lock);
}
#if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0)
@@ -586,11 +591,10 @@ void btu_start_quick_timer(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_ti
return;
}
}
osi_mutex_unlock(&btu_l2cap_alarm_lock);
alarm = hash_map_get(btu_l2cap_alarm_hash_map, p_tle);
if (alarm == NULL) {
HCI_TRACE_ERROR("%s Unable to create alarm", __func__);
osi_mutex_unlock(&btu_l2cap_alarm_lock);
return;
}
osi_alarm_cancel(alarm);
@@ -600,6 +604,7 @@ void btu_start_quick_timer(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_ti
p_tle->in_use = TRUE;
// The quick timer ticks are 100ms long.
osi_alarm_set(alarm, (period_ms_t)(timeout_ticks * 100));
osi_mutex_unlock(&btu_l2cap_alarm_lock);
}
/*******************************************************************************
@@ -615,34 +620,39 @@ void btu_stop_quick_timer(TIMER_LIST_ENT *p_tle)
{
assert(p_tle != NULL);
osi_mutex_lock(&btu_l2cap_alarm_lock, OSI_MUTEX_MAX_TIMEOUT);
if (p_tle->in_use == FALSE) {
osi_mutex_unlock(&btu_l2cap_alarm_lock);
return;
}
p_tle->in_use = FALSE;
// Get the alarm for the timer list entry.
osi_alarm_t *alarm = hash_map_get(btu_l2cap_alarm_hash_map, p_tle);
if (alarm == NULL) {
HCI_TRACE_WARNING("%s Unable to find expected alarm in hashmap", __func__);
p_tle->in_use = FALSE;
osi_mutex_unlock(&btu_l2cap_alarm_lock);
return;
}
osi_alarm_cancel(alarm);
p_tle->in_use = FALSE;
osi_mutex_unlock(&btu_l2cap_alarm_lock);
}
void btu_free_quick_timer(TIMER_LIST_ENT *p_tle)
{
assert(p_tle != NULL);
p_tle->in_use = FALSE;
// Get the alarm for the timer list entry.
osi_mutex_lock(&btu_l2cap_alarm_lock, OSI_MUTEX_MAX_TIMEOUT);
osi_alarm_t *alarm = hash_map_get(btu_l2cap_alarm_hash_map, p_tle);
if (alarm == NULL) {
HCI_TRACE_DEBUG("%s Unable to find expected alarm in hashmap", __func__);
p_tle->in_use = FALSE;
osi_mutex_unlock(&btu_l2cap_alarm_lock);
return;
}
osi_alarm_cancel(alarm);
hash_map_erase(btu_l2cap_alarm_hash_map, p_tle);
p_tle->in_use = FALSE;
osi_mutex_unlock(&btu_l2cap_alarm_lock);
}
#endif /* defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0) */
@@ -682,11 +692,10 @@ void btu_start_timer_oneshot(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_
return;
}
}
osi_mutex_unlock(&btu_oneshot_alarm_lock);
alarm = hash_map_get(btu_oneshot_alarm_hash_map, p_tle);
if (alarm == NULL) {
HCI_TRACE_ERROR("%s Unable to create alarm", __func__);
osi_mutex_unlock(&btu_oneshot_alarm_lock);
return;
}
osi_alarm_cancel(alarm);
@@ -696,24 +705,28 @@ void btu_start_timer_oneshot(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_
// NOTE: This value is in seconds but stored in a ticks field.
p_tle->ticks = timeout_sec;
osi_alarm_set(alarm, (period_ms_t)(timeout_sec * 1000));
osi_mutex_unlock(&btu_oneshot_alarm_lock);
}
void btu_stop_timer_oneshot(TIMER_LIST_ENT *p_tle)
{
assert(p_tle != NULL);
osi_mutex_lock(&btu_oneshot_alarm_lock, OSI_MUTEX_MAX_TIMEOUT);
if (p_tle->in_use == FALSE) {
osi_mutex_unlock(&btu_oneshot_alarm_lock);
return;
}
p_tle->in_use = FALSE;
// Get the alarm for the timer list entry.
osi_alarm_t *alarm = hash_map_get(btu_oneshot_alarm_hash_map, p_tle);
if (alarm == NULL) {
HCI_TRACE_WARNING("%s Unable to find expected alarm in hashmap", __func__);
p_tle->in_use = FALSE;
osi_mutex_unlock(&btu_oneshot_alarm_lock);
return;
}
osi_alarm_cancel(alarm);
p_tle->in_use = FALSE;
osi_mutex_unlock(&btu_oneshot_alarm_lock);
}
#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)