Merge branch 'fix/fix_blufi_memory_copy_len_error_v5.3' into 'release/v5.3'

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

See merge request espressif/esp-idf!48265
This commit is contained in:
Island
2026-05-12 19:27:45 +08:00
28 changed files with 1005 additions and 201 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

@@ -286,6 +286,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);
@@ -325,7 +327,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;
}
@@ -558,22 +565,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

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -32,11 +32,15 @@
#include "esp_bt_device.h"
#include "esp_err.h"
#include "esp_blufi.h"
#include <esp_gap_ble_api.h>
#if (BLUFI_INCLUDED == TRUE)
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
@@ -70,12 +74,166 @@ static esp_ble_adv_params_t blufi_adv_params = {
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};
#ifdef CONFIG_BT_BLUFI_BLE_SMP_ENABLE
static char *esp_auth_req_to_str(esp_ble_auth_req_t auth_req)
{
char *auth_str = NULL;
switch(auth_req) {
case ESP_LE_AUTH_NO_BOND:
auth_str = "ESP_LE_AUTH_NO_BOND";
break;
case ESP_LE_AUTH_BOND:
auth_str = "ESP_LE_AUTH_BOND";
break;
case ESP_LE_AUTH_REQ_MITM:
auth_str = "ESP_LE_AUTH_REQ_MITM";
break;
case ESP_LE_AUTH_REQ_BOND_MITM:
auth_str = "ESP_LE_AUTH_REQ_BOND_MITM";
break;
case ESP_LE_AUTH_REQ_SC_ONLY:
auth_str = "ESP_LE_AUTH_REQ_SC_ONLY";
break;
case ESP_LE_AUTH_REQ_SC_BOND:
auth_str = "ESP_LE_AUTH_REQ_SC_BOND";
break;
case ESP_LE_AUTH_REQ_SC_MITM:
auth_str = "ESP_LE_AUTH_REQ_SC_MITM";
break;
case ESP_LE_AUTH_REQ_SC_MITM_BOND:
auth_str = "ESP_LE_AUTH_REQ_SC_MITM_BOND";
break;
default:
auth_str = "INVALID BLE AUTH REQ";
break;
}
return auth_str;
}
static char *esp_key_type_to_str(esp_ble_key_type_t key_type)
{
char *key_str = NULL;
switch(key_type) {
case ESP_LE_KEY_NONE:
key_str = "ESP_LE_KEY_NONE";
break;
case ESP_LE_KEY_PENC:
key_str = "ESP_LE_KEY_PENC";
break;
case ESP_LE_KEY_PID:
key_str = "ESP_LE_KEY_PID";
break;
case ESP_LE_KEY_PCSRK:
key_str = "ESP_LE_KEY_PCSRK";
break;
case ESP_LE_KEY_PLK:
key_str = "ESP_LE_KEY_PLK";
break;
case ESP_LE_KEY_LLK:
key_str = "ESP_LE_KEY_LLK";
break;
case ESP_LE_KEY_LENC:
key_str = "ESP_LE_KEY_LENC";
break;
case ESP_LE_KEY_LID:
key_str = "ESP_LE_KEY_LID";
break;
case ESP_LE_KEY_LCSRK:
key_str = "ESP_LE_KEY_LCSRK";
break;
default:
key_str = "INVALID BLE KEY TYPE";
break;
}
return key_str;
}
#endif
void esp_blufi_gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
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:
//advertising start complete event to indicate advertising start successfully or failed
if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
BTC_TRACE_ERROR("Advertising start failed, status %x", param->adv_start_cmpl.status);
break;
}
BLUFI_TRACE_API("Advertising start successfully");
break;
#ifdef CONFIG_BT_BLUFI_BLE_SMP_ENABLE
case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */
BLUFI_TRACE_API("Passkey request");
break;
case ESP_GAP_BLE_OOB_REQ_EVT: {
BLUFI_TRACE_API("OOB request");
uint8_t tk[16] = {1}; //If you paired with OOB, both devices need to use the same tk
esp_ble_oob_req_reply(param->ble_security.ble_req.bd_addr, tk, sizeof(tk));
break;
}
case ESP_GAP_BLE_LOCAL_IR_EVT: /* BLE local IR event */
BLUFI_TRACE_API("Local identity root");
break;
case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */
BLUFI_TRACE_API("Local encryption root");
break;
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. */
/*
* 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.
If not accept the security request, should send the security response with negative(false) accept value*/
esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
break;
case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: ///the app will receive this evt when the IO has Output capability and the peer device IO has Input capability.
///show the passkey number to the user to input it in the peer device.
BLUFI_TRACE_WARNING("Passkey notify, passkey %06" PRIu32, param->ble_security.key_notif.passkey);
break;
case ESP_GAP_BLE_KEY_EVT:
//shows the ble key info share with peer device to the user.
BLUFI_TRACE_API("Key exchanged, key_type %s", esp_key_type_to_str(param->ble_security.ble_key.key_type));
break;
case ESP_GAP_BLE_AUTH_CMPL_EVT: {
esp_bd_addr_t bd_addr;
memcpy(bd_addr, param->ble_security.auth_cmpl.bd_addr, sizeof(esp_bd_addr_t));
BLUFI_TRACE_API("Authentication complete, addr_type %u, addr "ESP_BD_ADDR_STR"",
param->ble_security.auth_cmpl.addr_type, ESP_BD_ADDR_HEX(bd_addr));
if(!param->ble_security.auth_cmpl.success) {
BLUFI_TRACE_WARNING("Pairing failed, reason 0x%x",param->ble_security.auth_cmpl.fail_reason);
} else {
BLUFI_TRACE_WARNING("Pairing successfully, auth_mode %s",esp_auth_req_to_str(param->ble_security.auth_cmpl.auth_mode));
}
break;
}
case ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT: {
BLUFI_TRACE_DEBUG("Bond device remove, status %d, device "ESP_BD_ADDR_STR"",
param->remove_bond_dev_cmpl.status, ESP_BD_ADDR_HEX(param->remove_bond_dev_cmpl.bd_addr));
break;
}
case ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT:
if (param->local_privacy_cmpl.status != ESP_BT_STATUS_SUCCESS){
BLUFI_TRACE_WARNING("Local privacy config failed, status %x", param->local_privacy_cmpl.status);
}
break;
#endif // CONFIG_BT_BLUFI_BLE_SMP_ENABLE
default:
break;
}
@@ -149,7 +307,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;
@@ -176,7 +334,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");
@@ -209,7 +369,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 {
@@ -251,10 +418,16 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
break;
case BTA_GATTS_CREATE_EVT:
blufi_env.handle_srvc = p_data->create.service_id;
#if CONFIG_BT_BLUFI_BLE_SMP_ENABLE
BLUFI_TRACE_WARNING("BLE SMP support in BLUFI is ENABLED!");
#endif // CONFIG_BT_BLUFI_BLE_SMP_ENABLE
//add the first blufi characteristic --> write characteristic
BTA_GATTS_AddCharacteristic(blufi_env.handle_srvc, &blufi_char_uuid_p2e,
(GATT_PERM_WRITE),
#if CONFIG_BT_BLUFI_BLE_SMP_ENABLE
GATT_PERM_WRITE_ENC_MITM,
#else
GATT_PERM_WRITE,
#endif
(GATT_CHAR_PROP_BIT_WRITE),
NULL, NULL);
break;
@@ -264,7 +437,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;
@@ -272,7 +449,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;
@@ -301,6 +482,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,
@@ -325,6 +513,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",
@@ -342,6 +542,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;
@@ -373,6 +579,18 @@ void esp_blufi_send_notify(void *arg)
void esp_blufi_deinit(void)
{
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*/
@@ -398,6 +616,16 @@ void esp_blufi_adv_stop(void)
esp_ble_gap_stop_advertising();
}
esp_err_t esp_blufi_start_security_request(esp_blufi_bd_addr_t remote_bda)
{
#ifdef CONFIG_BT_BLUFI_BLE_SMP_ENABLE
return esp_ble_set_encryption(remote_bda, ESP_BLE_SEC_ENCRYPT_MITM);
#else
return ESP_ERR_INVALID_STATE;
#endif // CONFIG_BT_BLUFI_BLE_SMP_ENABLE
}
void esp_blufi_send_encap(void *arg)
{
struct blufi_hdr *hdr = (struct blufi_hdr *)arg;
@@ -423,6 +651,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

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -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
@@ -90,6 +91,22 @@ void esp_blufi_adv_start_with_name(const char *name);
void esp_blufi_send_encap(void *arg);
/*
* @brief Initiate BLE security request with the connected peer device.
*
* This function triggers the BLE Security Manager Protocol (SMP) procedure
* to establish a secure, encrypted connection with the specified remote device.
* It should be called after a BLE connection is established.
*
* @param[in] remote_bda Bluetooth device address of the connected peer.
*
* @return
* - ESP_OK: Security request initiated successfully
* - ESP_FAIL: Security request failed
* - ESP_ERR_INVALID_STATE: BluFi BLE SMP is not enabled
*/
esp_err_t esp_blufi_start_security_request(esp_blufi_bd_addr_t remote_bda);
#ifdef CONFIG_BT_NIMBLE_ENABLED
/**
* @brief Handle gap event for BluFi.

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

@@ -222,6 +222,16 @@ config BT_BLE_BLUFI_ENABLE
help
This option can be close when the app does not require blufi function.
config BT_BLUFI_BLE_SMP_ENABLE
bool "Enable BLE SMP support for BluFi"
depends on BT_BLE_BLUFI_ENABLE && BT_BLE_SMP_ENABLE
default n
help
Enable BLE Security Manager Protocol (SMP) for BluFi.
When enabled, BluFi will support BLE pairing and encryption
before Wi-Fi provisioning, providing a more secure provisioning process.
This feature is only supported with the Bluedroid host.
config BT_GATT_MAX_SR_PROFILES
int "Max GATT Server Profiles"
depends on BT_GATTS_ENABLE && BT_BLUEDROID_ENABLED

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

@@ -208,7 +208,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)

View File

@@ -12,6 +12,16 @@ Fragmenting, data encryption, and checksum verification in the BluFi layer are t
You can customize symmetric encryption, asymmetric encryption, and checksum support customization. Here we use the DH algorithm for key negotiation, 128-AES algorithm for data encryption, and CRC16 algorithm for checksum verification.
.. note::
**BluFi is currently in maintenance mode, and no new features are planned.**
For new projects or when adding Wi-Fi provisioning, we recommend using the network_provisioning component
(`network_provisioning <https://github.com/espressif/idf-extra-components/tree/master/network_provisioning>`_)
for a modern, secure, and actively maintained solution.
The BluFi Flow
----------------
@@ -481,15 +491,36 @@ The data to be encrypted and decrypted must be in the same length. The IV8 is an
This function is used to compute CheckSum and return a value of CheckSum. BluFi uses the returned value to compare the CheckSum of the frame.
5. Implementing Stronger Security
5. BLE SMP Encryption for Blufi
The default encryption/decryption logic in this example is intended for demonstration purposes only.
Before Wi-Fi provisioning, you can use BLE SMP pairing to establish a secure connection, making the provisioning process safer.
If you require a higher level of security, it is recommended to implement your own encryption, decryption, authentication, and checksum algorithms by customizing the security callbacks in the BluFi framework.
This feature can be enabled or disabled via the configuration option:
.. code-block:: c
esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks)
CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE
If this option is enabled, the ESP32 device will issue a pairing request once it is connected. Only after a successful pairing can the device proceed with provisioning.
Currently, BLE SMP pairing is supported **only on the Bluedroid host**.
6. Implementing Stronger Security
The default encryption and decryption logic in this example is intended for demonstration purposes only.
If you require a higher level of security, you may consider one of the following approaches:
1. **Custom Security Callbacks** Implement your own encryption, decryption, authentication, and checksum algorithms by customizing the security callbacks in the Blufi framework:
.. code-block:: c
esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks);
2. **Network Provisioning Component (recommended)** Alternatively, you can use the network_provisioning component for a secure, ready-to-use provisioning solution:
`network_provisioning <https://github.com/espressif/idf-extra-components/tree/master/network_provisioning>`_
GATT Related Instructions
----------------------------

View File

@@ -12,6 +12,16 @@ BluFi 流程的关键部分包括数据的分片、加密以及校验和验证
用户可按需自定义用于对称加密、非对称加密以及校验的算法。此处,我们采用 DH 算法进行密钥协商128-AES 算法用于数据加密CRC16 算法用于校验和验证。
.. note::
**BluFi 目前处于维护模式,不再规划新功能。**
对于新项目或新增 Wi-Fi 配网的场景,建议使用 network_provisioning 组件
(`network_provisioning <https://github.com/espressif/idf-extra-components/tree/master/network_provisioning>`_)
来实现现代化、安全且有持续维护的解决方案。
BluFi 流程
-----------
@@ -481,15 +491,36 @@ BluFi 会在调用完 Negotiate_data_handler 后,发送 Negotiate_data_handler
该函数用来进行校验返回值为校验的值。BluFi 会使用该函数返回值与帧的校验值进行比较。
5. 实现更强的安全性
5. BLE SMP Encryption for Blufi
本示例中默认的加密/解密逻辑仅用于演示目的
在 Wi-Fi 配网之前,可以使用 BLE SMP 配对建立安全连接,使配网过程更安全
如果需要更高等级的安全性,建议通过自定义 BluFi 框架中的安全回调函数,实现您自己的加密、解密、认证以及校验算法。
此功能可通过配置选项启用或禁用:
.. code-block:: c
esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks)
CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE
如果启用该选项ESP32 设备在连接成功后会发起配对请求。仅在配对成功后,设备才可继续进行 Wi-Fi 配网。
目前 BLE SMP 配对 **仅支持 Bluedroid 主机**
6. 实现更强的安全性
示例中的默认加密/解密逻辑仅用于演示目的。
如果需要更高等级的安全性,可以考虑以下方法:
1. **自定义安全回调** 通过自定义 BluFi 框架中的安全回调函数,实现自己的加密、解密、认证以及校验算法:
.. code-block:: c
esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks);
2. **Network Provisioning 组件(推荐使用)** 或者可以使用 ESP-IDF 提供的 network_provisioning 组件,实现安全、可直接使用的配网解决方案:
`network_provisioning <https://github.com/espressif/idf-extra-components/tree/master/network_provisioning>`_
GATT 相关说明

View File

@@ -695,7 +695,7 @@ void app_main(void)
/* set the security iocap & auth_req & key size & init key response key parameters to the stack*/
esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND; //bonding with peer device after authentication
esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT; //set the IO capability to No output No input
esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT; //set the IO capability to DisplayOnly
uint8_t key_size = 16; //the key size should be 7~16 bytes
uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;

View File

@@ -82,3 +82,9 @@ I (1198) BLUFI_EXAMPLE: BLUFI init finish
## Troubleshooting
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
## Note
BluFi is currently in maintenance mode, and no new features are planned.
For new projects or when adding network_provisioning, we recommend using the [network_provisioning](https://github.com/espressif/idf-extra-components/tree/master/network_provisioning).

View File

@@ -33,4 +33,23 @@ menu "Example Configuration"
bool "WAPI PSK"
endchoice
config EXAMPLE_BLUFI_BLE_SMP_ENABLE
bool "Enable BLE SMP support in BLUFI"
depends on BT_BLUEDROID_ENABLED
select BT_BLUFI_BLE_SMP_ENABLE
select BT_BLE_SMP_ENABLE
default n
help
Enable BLE Security Manager Protocol (SMP) for BLUFI.
Currently, this feature is only supported with the Bluedroid host.
If enabled:
- BLUFI will configure SMP security parameters such as
IO capabilities, authentication mode, and key size.
- After a BLE connection is established, BLUFI will
proactively initiate a security request.
- Only after the BLE pairing is successfully completed,
BLUFI can proceed with Wi-Fi provisioning.
- If the user rejects pairing or inputs an incorrect passkey,
BLUFI will not start Wi-Fi provisioning.
endmenu

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -319,6 +319,14 @@ static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_para
ble_is_connected = true;
esp_blufi_adv_stop();
blufi_security_init();
#ifdef CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE
// Try to initiate BLE security request after connection established.
BLUFI_INFO("Try to initiate BLE security request\n");
esp_err_t ret = esp_blufi_start_security_request(param->connect.remote_bda);
if (ret != ESP_OK) {
BLUFI_ERROR("Failed to start security request: %s\n", esp_err_to_name(ret));
}
#endif // CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE
break;
case ESP_BLUFI_EVENT_BLE_DISCONNECT:
BLUFI_INFO("BLUFI ble disconnect\n");

View File

@@ -16,6 +16,7 @@
#ifdef CONFIG_BT_BLUEDROID_ENABLED
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "esp_gap_ble_api.h"
#endif
#ifdef CONFIG_BT_NIMBLE_ENABLED
@@ -56,6 +57,37 @@ esp_err_t esp_blufi_host_init(void)
}
#ifdef CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE
void esp_blufi_set_ble_security_params(void)
{
/* set the security iocap & auth_req & key size & init key response key parameters to the stack*/
esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM; // Secure Connections with MITM protection (no bonding)
esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT; // IO capability: DisplayOnly
uint8_t key_size = 16; //the key size should be 7~16 bytes
uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
//set static passkey
uint32_t passkey = 123456;
uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_ENABLE;
uint8_t oob_support = ESP_BLE_OOB_DISABLE;
BLUFI_INFO("BLE SMP passkey: %06" PRIu32 " (WARNING: Change this default value for production or don't use static passkey!)\n", passkey);
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, &auth_option, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t));
/* If your BLE device acts as a Slave, the init_key means you hope which types of key of the master should distribute to you,
and the response key means which key you can distribute to the master;
If your BLE device acts as a master, the response key means you hope which types of key of the slave should distribute to you,
and the init key means which key you can distribute to the slave. */
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t));
}
#endif // #if CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE
esp_err_t esp_blufi_host_deinit(void)
{
int ret;
@@ -112,8 +144,11 @@ esp_err_t esp_blufi_host_and_cb_init(esp_blufi_callbacks_t *example_callbacks)
return ret;
}
return ESP_OK;
#ifdef CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE
esp_blufi_set_ble_security_params();
#endif // CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE
return ESP_OK;
}
#endif /* CONFIG_BT_BLUEDROID_ENABLED */