fix(blufi): support DH negotiation on SoCs without hardware MPI

This commit is contained in:
Rahul Tank
2026-04-10 10:31:13 +05:30
parent 2994fca5ba
commit fb4ba7c453
6 changed files with 552 additions and 34 deletions
@@ -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
*/
@@ -33,9 +33,131 @@
#include "esp_err.h"
#include "esp_blufi.h"
#include <esp_gap_ble_api.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "soc/soc_caps.h"
#if (BLUFI_INCLUDED == TRUE)
#if !SOC_MPI_SUPPORTED
#define BLUFI_RX_QUEUE_LEN 8
#define BLUFI_RX_TASK_STACK_SIZE 4096
#define BLUFI_RX_TASK_PRIO (tskIDLE_PRIORITY + 1)
typedef struct {
uint8_t *data;
uint16_t len;
} blufi_rx_item_t;
static QueueHandle_t s_blufi_rx_queue;
static TaskHandle_t s_blufi_rx_task_hdl;
static void blufi_rx_task(void *arg)
{
blufi_rx_item_t item;
while (xQueueReceive(s_blufi_rx_queue, &item, portMAX_DELAY) == pdTRUE) {
if (item.data == NULL) {
break;
}
btc_blufi_recv_handler(item.data, item.len);
free(item.data);
}
s_blufi_rx_task_hdl = NULL;
vTaskDelete(NULL);
}
static int blufi_rx_worker_start(void)
{
if (s_blufi_rx_queue != NULL && s_blufi_rx_task_hdl != NULL) {
return 0;
}
if (s_blufi_rx_queue != NULL && s_blufi_rx_task_hdl == NULL) {
blufi_rx_item_t item;
while (xQueueReceive(s_blufi_rx_queue, &item, 0) == pdTRUE) {
free(item.data);
}
vQueueDelete(s_blufi_rx_queue);
s_blufi_rx_queue = NULL;
}
s_blufi_rx_queue = xQueueCreate(BLUFI_RX_QUEUE_LEN, sizeof(blufi_rx_item_t));
if (s_blufi_rx_queue == NULL) {
BTC_TRACE_ERROR("failed to create BLUFI RX queue");
return -1;
}
BaseType_t ret = xTaskCreate(blufi_rx_task, "blufi_rx", BLUFI_RX_TASK_STACK_SIZE,
NULL, BLUFI_RX_TASK_PRIO, &s_blufi_rx_task_hdl);
if (ret != pdPASS) {
BTC_TRACE_ERROR("failed to create BLUFI RX task");
vQueueDelete(s_blufi_rx_queue);
s_blufi_rx_queue = NULL;
return -1;
}
return 0;
}
static void blufi_rx_worker_stop(void)
{
if (s_blufi_rx_queue == NULL) {
return;
}
blufi_rx_item_t stop = { .data = NULL, .len = 0 };
if (xQueueSend(s_blufi_rx_queue, &stop, 0) != pdTRUE) {
blufi_rx_item_t item;
while (xQueueReceive(s_blufi_rx_queue, &item, 0) == pdTRUE) {
free(item.data);
}
(void)xQueueSend(s_blufi_rx_queue, &stop, 0);
}
while (s_blufi_rx_task_hdl != NULL) {
vTaskDelay(pdMS_TO_TICKS(10));
}
blufi_rx_item_t item;
while (xQueueReceive(s_blufi_rx_queue, &item, 0) == pdTRUE) {
free(item.data);
}
vQueueDelete(s_blufi_rx_queue);
s_blufi_rx_queue = NULL;
}
static bool blufi_rx_enqueue(const uint8_t *data, uint16_t len)
{
if (len == 0) {
return false;
}
if (s_blufi_rx_queue == NULL) {
if (blufi_rx_worker_start() != 0) {
return false;
}
}
uint8_t *copy = malloc(len);
if (copy == NULL) {
return false;
}
memcpy(copy, data, len);
blufi_rx_item_t item = { .data = copy, .len = len };
if (xQueueSend(s_blufi_rx_queue, &item, 0) != pdTRUE) {
free(copy);
return false;
}
return true;
}
#endif /* !SOC_MPI_SUPPORTED */
static uint8_t server_if;
static uint16_t conn_id;
static uint8_t blufi_service_uuid128[32] = {
@@ -241,7 +363,6 @@ void blufi_create_service(void)
uint8_t esp_blufi_init(void)
{
/* register the BLUFI profile to the BTA_GATTS module*/
BTA_GATTS_AppRegister(&blufi_app_uuid, blufi_profile_cb);
return GATT_SUCCESS;
@@ -363,8 +484,15 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
}
if (p_data->req_data.p_data->write_req.handle == blufi_env.handle_char_p2e) {
#if !SOC_MPI_SUPPORTED
if (!blufi_rx_enqueue(&p_data->req_data.p_data->write_req.value[0],
p_data->req_data.p_data->write_req.len)) {
BLUFI_TRACE_ERROR("failed to enqueue BLUFI RX data");
}
#else
btc_blufi_recv_handler(&p_data->req_data.p_data->write_req.value[0],
p_data->req_data.p_data->write_req.len);
#endif
}
break;
}
@@ -375,7 +503,13 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
GATT_SUCCESS, NULL);
if (blufi_env.prepare_buf && p_data->req_data.p_data->exec_write == GATT_PREP_WRITE_EXEC) {
#if !SOC_MPI_SUPPORTED
if (!blufi_rx_enqueue(blufi_env.prepare_buf, blufi_env.prepare_len)) {
BLUFI_TRACE_ERROR("failed to enqueue BLUFI RX exec data");
}
#else
btc_blufi_recv_handler(blufi_env.prepare_buf, blufi_env.prepare_len);
#endif
}
if (blufi_env.prepare_buf) {
@@ -523,6 +657,9 @@ void esp_blufi_send_notify(void *arg)
void esp_blufi_deinit(void)
{
#if !SOC_MPI_SUPPORTED
blufi_rx_worker_stop();
#endif
BTA_GATTS_StopService(blufi_env.handle_srvc);
BTA_GATTS_DeleteService(blufi_env.handle_srvc);
/* register the BLUFI profile to the BTA_GATTS module*/
@@ -18,6 +18,9 @@
#include "esp_blufi.h"
#include "osi/allocator.h"
#include "console/console.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
/*nimBLE Host*/
#include "nimble/nimble_port.h"
@@ -29,6 +32,7 @@
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#include "soc/soc_caps.h"
#if (BLUFI_INCLUDED == TRUE)
@@ -37,6 +41,104 @@ static uint8_t own_addr_type;
struct gatt_value gatt_values[SERVER_MAX_VALUES];
const static char *TAG = "BLUFI_EXAMPLE";
#if !SOC_MPI_SUPPORTED
#define BLUFI_RX_QUEUE_LEN 8
#define BLUFI_RX_TASK_STACK_SIZE 8192
#define BLUFI_RX_TASK_PRIO (tskIDLE_PRIORITY + 1)
typedef struct {
uint8_t *data;
uint16_t len;
} blufi_rx_item_t;
static QueueHandle_t s_blufi_rx_queue;
static TaskHandle_t s_blufi_rx_task_hdl;
static void blufi_rx_task(void *arg)
{
blufi_rx_item_t item;
while (xQueueReceive(s_blufi_rx_queue, &item, portMAX_DELAY) == pdTRUE) {
if (item.data == NULL) {
break;
}
btc_blufi_recv_handler(item.data, item.len);
free(item.data);
}
s_blufi_rx_task_hdl = NULL;
vTaskDelete(NULL);
}
static int blufi_rx_worker_start(void)
{
if (s_blufi_rx_queue != NULL && s_blufi_rx_task_hdl != NULL) {
return 0;
}
if (s_blufi_rx_queue != NULL && s_blufi_rx_task_hdl == NULL) {
/* Recover from partial state: stale queue left after worker exit. */
blufi_rx_item_t item;
while (xQueueReceive(s_blufi_rx_queue, &item, 0) == pdTRUE) {
free(item.data);
}
vQueueDelete(s_blufi_rx_queue);
s_blufi_rx_queue = NULL;
}
s_blufi_rx_queue = xQueueCreate(BLUFI_RX_QUEUE_LEN, sizeof(blufi_rx_item_t));
if (s_blufi_rx_queue == NULL) {
ESP_LOGE(TAG, "failed to create BLUFI RX queue");
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
BaseType_t ret = xTaskCreate(blufi_rx_task, "blufi_rx", BLUFI_RX_TASK_STACK_SIZE,
NULL, BLUFI_RX_TASK_PRIO, &s_blufi_rx_task_hdl);
if (ret != pdPASS) {
ESP_LOGE(TAG, "failed to create BLUFI RX task");
vQueueDelete(s_blufi_rx_queue);
s_blufi_rx_queue = NULL;
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
return 0;
}
static void blufi_rx_worker_stop(void)
{
if (s_blufi_rx_queue == NULL) {
return;
}
blufi_rx_item_t stop = {
.data = NULL,
.len = 0,
};
if (xQueueSend(s_blufi_rx_queue, &stop, 0) != pdTRUE) {
/* Queue is full; free pending packets and resend stop marker. */
blufi_rx_item_t item;
while (xQueueReceive(s_blufi_rx_queue, &item, 0) == pdTRUE) {
free(item.data);
}
(void)xQueueSend(s_blufi_rx_queue, &stop, 0);
}
while (s_blufi_rx_task_hdl != NULL) {
vTaskDelay(pdMS_TO_TICKS(10));
}
/* Drain and free any queued packets before deleting the queue. */
blufi_rx_item_t item;
while (xQueueReceive(s_blufi_rx_queue, &item, 0) == pdTRUE) {
free(item.data);
}
vQueueDelete(s_blufi_rx_queue);
s_blufi_rx_queue = NULL;
}
#endif /* !SOC_MPI_SUPPORTED */
enum {
GATT_VALUE_TYPE_CHR,
GATT_VALUE_TYPE_DSC,
@@ -142,13 +244,30 @@ static size_t write_value(uint16_t conn_handle, uint16_t attr_handle,
return BLE_ATT_ERR_UNLIKELY;
}
btc_blufi_recv_handler(flat_buf, pkt_len);
if (value->buf != NULL) {
os_mbuf_free_chain(value->buf);
value->buf = NULL;
}
#if !SOC_MPI_SUPPORTED
if (s_blufi_rx_queue == NULL) {
free(flat_buf);
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
if (pkt_len > 0) {
blufi_rx_item_t item = {
.data = flat_buf,
.len = pkt_len,
};
if (xQueueSend(s_blufi_rx_queue, &item, 0) != pdTRUE) {
free(flat_buf);
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
} else {
free(flat_buf);
}
#else /* SOC_MPI_SUPPORTED */
value->buf = os_msys_get(0, 0);
if (value->buf == NULL) {
free(flat_buf);
@@ -164,7 +283,9 @@ static size_t write_value(uint16_t conn_handle, uint16_t attr_handle,
}
}
btc_blufi_recv_handler(flat_buf, pkt_len);
free(flat_buf);
#endif
return 0;
}
@@ -278,16 +399,30 @@ static void deinit_gatt_values(void)
int esp_blufi_gatt_svr_init(void)
{
int rc;
#if !SOC_MPI_SUPPORTED
rc = blufi_rx_worker_start();
if (rc != 0) {
return rc;
}
#endif
ble_svc_gap_init();
ble_svc_gatt_init();
rc = ble_gatts_count_cfg(gatt_svr_svcs);
if (rc != 0) {
#if !SOC_MPI_SUPPORTED
blufi_rx_worker_stop();
#endif
return rc;
}
rc = ble_gatts_add_svcs(gatt_svr_svcs);
if (rc != 0) {
#if !SOC_MPI_SUPPORTED
blufi_rx_worker_stop();
#endif
return rc;
}
@@ -297,6 +432,10 @@ int esp_blufi_gatt_svr_init(void)
int esp_blufi_gatt_svr_deinit(void)
{
#if !SOC_MPI_SUPPORTED
blufi_rx_worker_stop();
#endif
deinit_gatt_values();
ble_gatts_free_svcs();