mirror of
https://github.com/espressif/esp-idf.git
synced 2026-06-04 20:26:38 +03:00
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:
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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, ¶m, 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, ¶m, 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, ¶m, 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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
18
components/bt/common/include/esp_assume.h
Normal file
18
components/bt/common/include/esp_assume.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
----------------------------
|
||||
|
||||
@@ -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 相关说明
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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).
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user