From 2dc8830907c24e4894838a9d4ae51cb93bf4861c Mon Sep 17 00:00:00 2001 From: Sumeet Singh Date: Fri, 26 Jun 2026 12:25:44 +0530 Subject: [PATCH 1/6] fix(nimble): Add npl locks to avoid race condition (v5.5) --- .../host/nimble/esp-hci/src/esp_nimble_hci.c | 3 - components/bt/host/nimble/nimble | 2 +- .../npl/freertos/src/npl_os_freertos.c | 303 +++++++++++++++--- 3 files changed, 265 insertions(+), 43 deletions(-) diff --git a/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c b/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c index cc36004685a..9fda6c49cb6 100644 --- a/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c +++ b/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c @@ -182,7 +182,6 @@ static void ble_hci_rx_acl(uint8_t *data, uint16_t len) { struct os_mbuf *m = NULL; int rc; - int sr; int retry_count = 1; @@ -216,9 +215,7 @@ static void ble_hci_rx_acl(uint8_t *data, uint16_t len) os_mbuf_free_chain(m); return; } - OS_ENTER_CRITICAL(sr); ble_transport_to_hs_acl(m); - OS_EXIT_CRITICAL(sr); } #endif diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 685675c0128..bdc5010548e 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 685675c0128deafdd201c9eb82e61d227364646c +Subproject commit bdc5010548e988a770adb8af107d01feb850c0ca diff --git a/components/bt/porting/npl/freertos/src/npl_os_freertos.c b/components/bt/porting/npl/freertos/src/npl_os_freertos.c index 5430647bb3e..c06258323fa 100644 --- a/components/bt/porting/npl/freertos/src/npl_os_freertos.c +++ b/components/bt/porting/npl/freertos/src/npl_os_freertos.c @@ -25,6 +25,8 @@ portMUX_TYPE ble_port_mutex = portMUX_INITIALIZER_UNLOCKED; +static SemaphoreHandle_t npl_eventq_sync; + #if BLE_NPL_USE_ESP_TIMER static const char *TAG = "Timer"; #endif @@ -197,6 +199,115 @@ IRAM_ATTR in_isr(void) return xPortInIsrContext() != 0; } +static void +npl_eventq_sync_init(void) +{ + if (npl_eventq_sync == NULL) { + npl_eventq_sync = xSemaphoreCreateMutex(); + BLE_LL_ASSERT(npl_eventq_sync); + } +} + +static void +npl_eventq_lock(void) +{ + if (!in_isr()) { + BLE_LL_ASSERT(npl_eventq_sync); + xSemaphoreTake(npl_eventq_sync, portMAX_DELAY); + } +} + +static void +npl_eventq_unlock(void) +{ + if (!in_isr()) { + xSemaphoreGive(npl_eventq_sync); + } +} + +static bool IRAM_ATTR +npl_eventq_queued_get_isr(struct ble_npl_event_freertos *event) +{ + bool queued; + + portENTER_CRITICAL_ISR(&ble_port_mutex); + queued = event->queued; + portEXIT_CRITICAL_ISR(&ble_port_mutex); + return queued; +} + +static void IRAM_ATTR +npl_eventq_queued_set_isr(struct ble_npl_event_freertos *event, bool queued) +{ + portENTER_CRITICAL_ISR(&ble_port_mutex); + event->queued = queued; + portEXIT_CRITICAL_ISR(&ble_port_mutex); +} + +static bool IRAM_ATTR +npl_eventq_queued_claim_isr(struct ble_npl_event_freertos *event) +{ + bool already; + + portENTER_CRITICAL_ISR(&ble_port_mutex); + already = event->queued; + if (!already) { + event->queued = true; + } + portEXIT_CRITICAL_ISR(&ble_port_mutex); + return already; +} + +static void IRAM_ATTR +npl_eventq_queued_set_task(struct ble_npl_event_freertos *event, bool queued) +{ + portENTER_CRITICAL(&ble_port_mutex); + event->queued = queued; + portEXIT_CRITICAL(&ble_port_mutex); +} + +static bool IRAM_ATTR +npl_eventq_queued_get_task(struct ble_npl_event_freertos *event) +{ + bool queued; + + portENTER_CRITICAL(&ble_port_mutex); + queued = event->queued; + portEXIT_CRITICAL(&ble_port_mutex); + return queued; +} + +static bool IRAM_ATTR +npl_eventq_queued_claim(struct ble_npl_event_freertos *event) +{ + bool already; + + portENTER_CRITICAL(&ble_port_mutex); + already = event->queued; + if (!already) { + event->queued = true; + } + portEXIT_CRITICAL(&ble_port_mutex); + return already; +} + +static void IRAM_ATTR +npl_eventq_lost_event_clear(struct ble_npl_event *ev) +{ + struct ble_npl_event_freertos *lost; + + if (ev == NULL) { + return; + } + + lost = (struct ble_npl_event_freertos *)ev->event; + if (lost == NULL) { + return; + } + + lost->queued = false; +} + struct ble_npl_event * IRAM_ATTR npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo) { @@ -211,16 +322,63 @@ IRAM_ATTR npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo if( woken == pdTRUE ) { portYIELD_FROM_ISR(); } - } else { - ret = xQueueReceive(eventq->q, &ev, tmo); - } - BLE_LL_ASSERT(ret == pdPASS || ret == errQUEUE_EMPTY); + BLE_LL_ASSERT(ret == pdPASS || ret == errQUEUE_EMPTY); - if (ev) { - struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event; - if (event) { - event->queued = false; - } + if (ev) { + struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event; + if (event) { + npl_eventq_queued_set_isr(event, false); + } + } + } else if (tmo == 0) { + npl_eventq_lock(); + portENTER_CRITICAL(&ble_port_mutex); + ret = xQueueReceive(eventq->q, &ev, 0); + if (ret == pdPASS && ev != NULL) { + struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event; + if (event) { + event->queued = false; + } + } + portEXIT_CRITICAL(&ble_port_mutex); + npl_eventq_unlock(); + } else { + TickType_t deadline = 0; + TickType_t remaining; + + if (tmo != portMAX_DELAY) { + deadline = xTaskGetTickCount() + tmo; + } + + for (;;) { + if (tmo == portMAX_DELAY) { + ret = xQueuePeek(eventq->q, &ev, portMAX_DELAY); + } else { + remaining = deadline - xTaskGetTickCount(); + if (remaining > tmo) { + return NULL; + } + ret = xQueuePeek(eventq->q, &ev, remaining); + } + if (ret != pdPASS) { + return NULL; + } + + npl_eventq_lock(); + portENTER_CRITICAL(&ble_port_mutex); + ret = xQueueReceive(eventq->q, &ev, 0); + if (ret == pdPASS && ev != NULL) { + struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event; + if (event) { + event->queued = false; + } + portEXIT_CRITICAL(&ble_port_mutex); + npl_eventq_unlock(); + break; + } + portEXIT_CRITICAL(&ble_port_mutex); + npl_eventq_unlock(); + } } return ev; @@ -234,22 +392,35 @@ IRAM_ATTR npl_freertos_eventq_put(struct ble_npl_eventq *evq, struct ble_npl_eve struct ble_npl_eventq_freertos *eventq = (struct ble_npl_eventq_freertos *)evq->eventq; struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event; - if (event->queued) { - return; - } - - event->queued = true; - if (in_isr()) { + if (npl_eventq_queued_claim_isr(event)) { + return; + } + ret = xQueueSendToBackFromISR(eventq->q, &ev, &woken); + if (ret != pdPASS) { + npl_eventq_queued_set_isr(event, false); + return; + } if( woken == pdTRUE ) { portYIELD_FROM_ISR(); } + return; } else { - ret = xQueueSendToBack(eventq->q, &ev, portMAX_DELAY); - } + npl_eventq_lock(); - BLE_LL_ASSERT(ret == pdPASS); + if (npl_eventq_queued_claim(event)) { + npl_eventq_unlock(); + return; + } + + ret = xQueueSendToBack(eventq->q, &ev, 0); + if (ret != pdPASS) { + ESP_LOGW("NimBLE", "eventq put: queue full, event dropped"); + npl_eventq_queued_set_task(event, false); + } + npl_eventq_unlock(); + } } void @@ -260,22 +431,35 @@ IRAM_ATTR npl_freertos_eventq_put_to_front(struct ble_npl_eventq *evq, struct bl struct ble_npl_eventq_freertos *eventq = (struct ble_npl_eventq_freertos *)evq->eventq; struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event; - if (event->queued) { - return; - } - - event->queued = true; - if (in_isr()) { + if (npl_eventq_queued_claim_isr(event)) { + return; + } + ret = xQueueSendToFrontFromISR(eventq->q, &ev, &woken); + if (ret != pdPASS) { + npl_eventq_queued_set_isr(event, false); + return; + } if( woken == pdTRUE ) { portYIELD_FROM_ISR(); } + return; } else { - ret = xQueueSendToFront(eventq->q, &ev, portMAX_DELAY); - } + npl_eventq_lock(); - BLE_LL_ASSERT(ret == pdPASS); + if (npl_eventq_queued_claim(event)) { + npl_eventq_unlock(); + return; + } + + ret = xQueueSendToFront(eventq->q, &ev, 0); + if (ret != pdPASS) { + ESP_LOGW("NimBLE", "eventq put_to_front: queue full, event dropped"); + npl_eventq_queued_set_task(event, false); + } + npl_eventq_unlock(); + } } void @@ -286,14 +470,11 @@ IRAM_ATTR npl_freertos_eventq_remove(struct ble_npl_eventq *evq, BaseType_t ret; int i; int count; + bool removed; BaseType_t woken, woken2; struct ble_npl_eventq_freertos *eventq = (struct ble_npl_eventq_freertos *)evq->eventq; struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event; - if (!event->queued) { - return; - } - /* * XXX We cannot extract element from inside FreeRTOS queue so as a quick * workaround we'll just remove all elements and add them back except the @@ -302,46 +483,77 @@ IRAM_ATTR npl_freertos_eventq_remove(struct ble_npl_eventq *evq, */ if (in_isr()) { + if (!npl_eventq_queued_get_isr(event)) { + return; + } + + removed = false; woken = pdFALSE; + portENTER_CRITICAL_ISR(&ble_port_mutex); count = uxQueueMessagesWaitingFromISR(eventq->q); for (i = 0; i < count; i++) { ret = xQueueReceiveFromISR(eventq->q, &tmp_ev, &woken2); - BLE_LL_ASSERT(ret == pdPASS); + if (ret != pdPASS) { + break; + } woken |= woken2; if (tmp_ev == ev) { + removed = true; continue; } ret = xQueueSendToBackFromISR(eventq->q, &tmp_ev, &woken2); - BLE_LL_ASSERT(ret == pdPASS); + if (ret != pdPASS) { + npl_eventq_lost_event_clear(tmp_ev); + break; + } woken |= woken2; } + if (removed) { + event->queued = false; + } + portEXIT_CRITICAL_ISR(&ble_port_mutex); if( woken == pdTRUE ) { portYIELD_FROM_ISR(); } } else { - portENTER_CRITICAL(&ble_port_mutex); + removed = false; + npl_eventq_lock(); + if (!npl_eventq_queued_get_task(event)) { + npl_eventq_unlock(); + return; + } + + portENTER_CRITICAL(&ble_port_mutex); count = uxQueueMessagesWaiting(eventq->q); for (i = 0; i < count; i++) { ret = xQueueReceive(eventq->q, &tmp_ev, 0); - BLE_LL_ASSERT(ret == pdPASS); + if (ret != pdPASS) { + break; + } if (tmp_ev == ev) { + removed = true; continue; } ret = xQueueSendToBack(eventq->q, &tmp_ev, 0); - BLE_LL_ASSERT(ret == pdPASS); + if (ret != pdPASS) { + npl_eventq_lost_event_clear(tmp_ev); + break; + } + } + if (removed) { + event->queued = 0; } - portEXIT_CRITICAL(&ble_port_mutex); - } - event->queued = 0; + npl_eventq_unlock(); + } } ble_npl_error_t @@ -1129,6 +1341,9 @@ int npl_freertos_set_controller_npl_info(ble_npl_count_info_t *ctrl_npl_info) int npl_freertos_mempool_init(void) { int rc = -1; + + npl_eventq_sync_init(); + uint16_t ble_total_evt_count = 0; uint16_t ble_total_co_count = 0; uint16_t ble_total_evtq_count = 0; @@ -1218,6 +1433,11 @@ int npl_freertos_mempool_init(void) return 0; _error: + if (npl_eventq_sync) { + vSemaphoreDelete(npl_eventq_sync); + npl_eventq_sync = NULL; + } + if (ble_freertos_ev_buf) { bt_osi_mem_free_internal(ble_freertos_ev_buf); ble_freertos_ev_buf = NULL; @@ -1247,6 +1467,11 @@ _error: void npl_freertos_mempool_deinit(void) { + if (npl_eventq_sync) { + vSemaphoreDelete(npl_eventq_sync); + npl_eventq_sync = NULL; + } + if (ble_freertos_ev_buf) { bt_osi_mem_free_internal(ble_freertos_ev_buf); ble_freertos_ev_buf = NULL; From 4a123df27ccfc7157bcad9320cd5d2454d75fddf Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Mon, 29 Jun 2026 11:27:50 +0530 Subject: [PATCH 2/6] fix(nimble): Defer Events / ATT related information from stack Defer Events/ ATT related GAP events from stack until connection event is sent to GAP layer --- components/bt/host/nimble/Kconfig.in | 10 +++ components/bt/host/nimble/nimble | 2 +- .../host/nimble/port/include/esp_nimble_cfg.h | 9 ++ .../npl/freertos/src/npl_os_freertos.c | 90 ++++++++++++------- 4 files changed, 79 insertions(+), 32 deletions(-) diff --git a/components/bt/host/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in index a89c505bac4..1b46c484ee7 100644 --- a/components/bt/host/nimble/Kconfig.in +++ b/components/bt/host/nimble/Kconfig.in @@ -349,6 +349,16 @@ menu "GAP" Enable this option to send number-of-completed-packets event to controller after disconnection + config BT_NIMBLE_DEFER_CONN_EVENTS_UNTIL_CONNECT + bool "Defer connection GAP/ATT events until CONNECT callback" + depends on BT_NIMBLE_ENABLED + default y + help + Queue connection-related GAP callbacks and ATT server requests until + BLE_GAP_EVENT_CONNECT event is delivered for that connection handle. + Required when the host delays CONNECT so applications never receive other + events before CONNECT event. + endmenu #GAP menu "GATT / ATT" diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index bdc5010548e..37599327e21 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit bdc5010548e988a770adb8af107d01feb850c0ca +Subproject commit 37599327e214accc849d0d007295028b0ec262ab diff --git a/components/bt/host/nimble/port/include/esp_nimble_cfg.h b/components/bt/host/nimble/port/include/esp_nimble_cfg.h index a0f62f36aa2..e4c095ff2d5 100644 --- a/components/bt/host/nimble/port/include/esp_nimble_cfg.h +++ b/components/bt/host/nimble/port/include/esp_nimble_cfg.h @@ -2390,4 +2390,13 @@ #endif #endif +#ifndef MYNEWT_VAL_BLE_DEFER_CONN_EVENTS +#ifdef CONFIG_BT_NIMBLE_DEFER_CONN_EVENTS_UNTIL_CONNECT +#define MYNEWT_VAL_BLE_DEFER_CONN_EVENTS CONFIG_BT_NIMBLE_DEFER_CONN_EVENTS_UNTIL_CONNECT +#else +#define MYNEWT_VAL_BLE_DEFER_CONN_EVENTS (0) +#endif +#endif + + #endif diff --git a/components/bt/porting/npl/freertos/src/npl_os_freertos.c b/components/bt/porting/npl/freertos/src/npl_os_freertos.c index c06258323fa..8d0f92a6e3e 100644 --- a/components/bt/porting/npl/freertos/src/npl_os_freertos.c +++ b/components/bt/porting/npl/freertos/src/npl_os_freertos.c @@ -26,6 +26,7 @@ portMUX_TYPE ble_port_mutex = portMUX_INITIALIZER_UNLOCKED; static SemaphoreHandle_t npl_eventq_sync; +static uint8_t hw_critical_state_status[portNUM_PROCESSORS]; #if BLE_NPL_USE_ESP_TIMER static const char *TAG = "Timer"; @@ -203,25 +204,35 @@ static void npl_eventq_sync_init(void) { if (npl_eventq_sync == NULL) { - npl_eventq_sync = xSemaphoreCreateMutex(); + npl_eventq_sync = xSemaphoreCreateRecursiveMutex(); BLE_LL_ASSERT(npl_eventq_sync); } } -static void +static bool npl_eventq_lock(void) { - if (!in_isr()) { - BLE_LL_ASSERT(npl_eventq_sync); - xSemaphoreTake(npl_eventq_sync, portMAX_DELAY); + BaseType_t core; + + if (in_isr()) { + return false; } + + core = xPortGetCoreID(); + if (core >= portNUM_PROCESSORS || hw_critical_state_status[core] != 0) { + return false; + } + + BLE_LL_ASSERT(npl_eventq_sync); + xSemaphoreTakeRecursive(npl_eventq_sync, portMAX_DELAY); + return true; } static void -npl_eventq_unlock(void) +npl_eventq_unlock(bool locked) { - if (!in_isr()) { - xSemaphoreGive(npl_eventq_sync); + if (locked) { + xSemaphoreGiveRecursive(npl_eventq_sync); } } @@ -331,7 +342,8 @@ IRAM_ATTR npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo } } } else if (tmo == 0) { - npl_eventq_lock(); + bool locked = npl_eventq_lock(); + portENTER_CRITICAL(&ble_port_mutex); ret = xQueueReceive(eventq->q, &ev, 0); if (ret == pdPASS && ev != NULL) { @@ -341,7 +353,7 @@ IRAM_ATTR npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo } } portEXIT_CRITICAL(&ble_port_mutex); - npl_eventq_unlock(); + npl_eventq_unlock(locked); } else { TickType_t deadline = 0; TickType_t remaining; @@ -364,7 +376,8 @@ IRAM_ATTR npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo return NULL; } - npl_eventq_lock(); + bool locked = npl_eventq_lock(); + portENTER_CRITICAL(&ble_port_mutex); ret = xQueueReceive(eventq->q, &ev, 0); if (ret == pdPASS && ev != NULL) { @@ -372,12 +385,13 @@ IRAM_ATTR npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo if (event) { event->queued = false; } - portEXIT_CRITICAL(&ble_port_mutex); - npl_eventq_unlock(); - break; } portEXIT_CRITICAL(&ble_port_mutex); - npl_eventq_unlock(); + if (ret == pdPASS && ev != NULL) { + npl_eventq_unlock(locked); + break; + } + npl_eventq_unlock(locked); } } @@ -407,10 +421,10 @@ IRAM_ATTR npl_freertos_eventq_put(struct ble_npl_eventq *evq, struct ble_npl_eve } return; } else { - npl_eventq_lock(); + bool locked = npl_eventq_lock(); if (npl_eventq_queued_claim(event)) { - npl_eventq_unlock(); + npl_eventq_unlock(locked); return; } @@ -419,7 +433,7 @@ IRAM_ATTR npl_freertos_eventq_put(struct ble_npl_eventq *evq, struct ble_npl_eve ESP_LOGW("NimBLE", "eventq put: queue full, event dropped"); npl_eventq_queued_set_task(event, false); } - npl_eventq_unlock(); + npl_eventq_unlock(locked); } } @@ -446,10 +460,10 @@ IRAM_ATTR npl_freertos_eventq_put_to_front(struct ble_npl_eventq *evq, struct bl } return; } else { - npl_eventq_lock(); + bool locked = npl_eventq_lock(); if (npl_eventq_queued_claim(event)) { - npl_eventq_unlock(); + npl_eventq_unlock(locked); return; } @@ -458,7 +472,7 @@ IRAM_ATTR npl_freertos_eventq_put_to_front(struct ble_npl_eventq *evq, struct bl ESP_LOGW("NimBLE", "eventq put_to_front: queue full, event dropped"); npl_eventq_queued_set_task(event, false); } - npl_eventq_unlock(); + npl_eventq_unlock(locked); } } @@ -522,9 +536,10 @@ IRAM_ATTR npl_freertos_eventq_remove(struct ble_npl_eventq *evq, } else { removed = false; - npl_eventq_lock(); + bool locked = npl_eventq_lock(); + if (!npl_eventq_queued_get_task(event)) { - npl_eventq_unlock(); + npl_eventq_unlock(locked); return; } @@ -548,11 +563,10 @@ IRAM_ATTR npl_freertos_eventq_remove(struct ble_npl_eventq *evq, } } if (removed) { - event->queued = 0; + event->queued = false; } portEXIT_CRITICAL(&ble_port_mutex); - - npl_eventq_unlock(); + npl_eventq_unlock(locked); } } @@ -1231,26 +1245,40 @@ IRAM_ATTR npl_freertos_time_delay(ble_npl_time_t ticks) } -uint8_t hw_critical_state_status = 0; - uint32_t IRAM_ATTR npl_freertos_hw_enter_critical(void) { - ++hw_critical_state_status; + BaseType_t core; + portENTER_CRITICAL(&ble_port_mutex); + core = xPortGetCoreID(); + if (core < portNUM_PROCESSORS) { + ++hw_critical_state_status[core]; + } return 0; } uint8_t IRAM_ATTR npl_freertos_hw_is_in_critical(void) { - return hw_critical_state_status; + BaseType_t core; + + core = xPortGetCoreID(); + if (core >= portNUM_PROCESSORS) { + return 0; + } + return hw_critical_state_status[core]; } void IRAM_ATTR npl_freertos_hw_exit_critical(uint32_t ctx) { - --hw_critical_state_status; + BaseType_t core; + + core = xPortGetCoreID(); + if (core < portNUM_PROCESSORS && hw_critical_state_status[core] > 0) { + --hw_critical_state_status[core]; + } portEXIT_CRITICAL(&ble_port_mutex); } From f7d56dc7783aacfa7c7f4b434fb8ffa83a9253e3 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Thu, 11 Jun 2026 11:42:05 +0530 Subject: [PATCH 3/6] fix(nimble): Fixes for AI reported issues --- components/bt/host/nimble/nimble | 2 +- .../host/nimble/port/include/esp_nimble_mem.h | 31 +++--- .../bt/host/nimble/port/src/esp_nimble_mem.c | 99 ++++++++----------- .../npl/freertos/src/npl_os_freertos.c | 84 +++++++++------- .../ble_chan_sound_reflector/main/main.c | 2 +- .../ble_l2cap_coc/coc_blecent/main/main.c | 2 +- .../ble_l2cap_coc/coc_bleprph/main/main.c | 21 ++-- 7 files changed, 112 insertions(+), 129 deletions(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 37599327e21..1a714b03dce 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 37599327e214accc849d0d007295028b0ec262ab +Subproject commit 1a714b03dcea55e58066e21213a5f150f2e50088 diff --git a/components/bt/host/nimble/port/include/esp_nimble_mem.h b/components/bt/host/nimble/port/include/esp_nimble_mem.h index dd60c741cfe..bc57004da8e 100644 --- a/components/bt/host/nimble/port/include/esp_nimble_mem.h +++ b/components/bt/host/nimble/port/include/esp_nimble_mem.h @@ -17,6 +17,8 @@ void *nimble_mem_malloc(size_t size); void *nimble_mem_calloc(size_t n, size_t size); +void *nimble_mem_realloc(void *ptr, size_t size); + void nimble_mem_free(void *ptr); #if CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED @@ -89,17 +91,6 @@ void nimble_mem_dbg_set_section_end(uint8_t index); */ uint32_t nimble_mem_dbg_get_max_size_section(uint8_t index); -/** - * @brief Reallocate memory with debug tracking - * - * @param ptr Pointer to memory to reallocate - * @param new_size New size of allocation - * @param func Function name where realloc occurred - * @param line Line number where realloc occurred - * @return Pointer to reallocated memory - */ -void *nimble_mem_dbg_realloc(void *ptr, size_t new_size, const char *func, int line); - #endif // CONFIG_BT_NIMBLE_MEM_DEBUG @@ -127,11 +118,17 @@ void *nimble_mem_dbg_realloc(void *ptr, size_t new_size, const char *func, int l #define nimble_platform_mem_realloc(ptr, new_size) \ ({ \ - void *p; \ - do { \ - p = nimble_mem_dbg_realloc(ptr, new_size, __func__, __LINE__); \ - } while (0); \ - p; \ + void *_old = (void *)(ptr); \ + size_t _nsz = (size_t)(new_size); \ + void *_new = nimble_mem_realloc(_old, _nsz); \ + if (_new == NULL && _nsz > 0) { \ + /* realloc failed: original block still alive, keep its debug record */ \ + } else { \ + /* success or free (new_size==0): clean old, record new */ \ + if (_old) nimble_mem_dbg_clean(_old, __func__, __LINE__); \ + if (_new) nimble_mem_dbg_record(_new, _nsz, __func__, __LINE__); \ + } \ + _new; \ }) #define nimble_platform_mem_free(ptr) \ @@ -145,7 +142,7 @@ do { \ #define nimble_platform_mem_malloc nimble_mem_malloc #define nimble_platform_mem_calloc nimble_mem_calloc -#define nimble_platform_mem_realloc realloc +#define nimble_platform_mem_realloc nimble_mem_realloc #define nimble_platform_mem_free nimble_mem_free #endif // CONFIG_BT_NIMBLE_MEM_DEBUG diff --git a/components/bt/host/nimble/port/src/esp_nimble_mem.c b/components/bt/host/nimble/port/src/esp_nimble_mem.c index 3f8e8ed55d0..642f185a8ad 100644 --- a/components/bt/host/nimble/port/src/esp_nimble_mem.c +++ b/components/bt/host/nimble/port/src/esp_nimble_mem.c @@ -79,6 +79,7 @@ void nimble_mem_dbg_record(void *p, int size, const char *func, int line) if (i >= NIMBLE_MEM_DBG_INFO_MAX) { ESP_LOGE("BT_NIMBLE_MEM", "%s full %s %d !!\n", __func__, func, line); + return; } nimble_mem_dbg_current_size += size; @@ -190,66 +191,6 @@ uint32_t nimble_mem_dbg_get_max_size_section(uint8_t index) return nimble_mem_dbg_max_size_section[index].max_size; } -void *nimble_mem_dbg_realloc(void *ptr, size_t new_size, const char *func, int line) -{ - size_t old_size = 0; - int i; - - void *new_ptr = realloc(ptr, new_size); - if (new_ptr == NULL && new_size > 0) { - // realloc failed, keep old ptr record - return NULL; - } - - // Find and clean old record if ptr is not NULL - if (ptr != NULL) { - for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) { - if (nimble_mem_dbg_info[i].p == ptr) { - old_size = nimble_mem_dbg_info[i].size; - nimble_mem_dbg_current_size -= old_size; - - nimble_mem_dbg_info[i].p = NULL; - nimble_mem_dbg_info[i].size = 0; - nimble_mem_dbg_info[i].func = NULL; - nimble_mem_dbg_info[i].line = 0; - nimble_mem_dbg_count--; - break; - } - } - } - - // Record the new allocation if new_size > 0 - if (new_ptr != NULL && new_size > 0) { - for (i = 0; i < NIMBLE_MEM_DBG_INFO_MAX; i++) { - if (nimble_mem_dbg_info[i].p == NULL) { - nimble_mem_dbg_info[i].p = new_ptr; - nimble_mem_dbg_info[i].size = new_size; - nimble_mem_dbg_info[i].func = func; - nimble_mem_dbg_info[i].line = line; - nimble_mem_dbg_count++; - break; - } - } - - if (i >= NIMBLE_MEM_DBG_INFO_MAX) { - ESP_LOGE("BT_NIMBLE_MEM", "%s full %s %d !!\n", __func__, func, line); - } - - nimble_mem_dbg_current_size += new_size; - if (nimble_mem_dbg_max_size < nimble_mem_dbg_current_size) { - nimble_mem_dbg_max_size = nimble_mem_dbg_current_size; - } - - for (i = 0; i < NIMBLE_MEM_DBG_MAX_SECTION_NUM; i++) { - if (nimble_mem_dbg_max_size_section[i].used && - nimble_mem_dbg_max_size_section[i].max_size < nimble_mem_dbg_current_size) { - nimble_mem_dbg_max_size_section[i].max_size = nimble_mem_dbg_current_size; - } - } - } - - return new_ptr; -} #endif // CONFIG_BT_NIMBLE_MEM_DEBUG #if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE @@ -306,6 +247,44 @@ void *nimble_mem_calloc(size_t n, size_t size) return mem; } +#if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE +IRAM_ATTR +#endif +void *nimble_mem_realloc(void *ptr, size_t size) +{ + void *mem = NULL; +#if CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED + size_t old_size = 0; + if (ptr) { + old_size = heap_caps_get_allocated_size(ptr); + } +#endif + +#ifdef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL + mem = heap_caps_realloc(ptr, size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); +#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL + mem = heap_caps_realloc(ptr, size, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT); +#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_IRAM_8BIT + mem = heap_caps_realloc_prefer(ptr, size, 2, + MALLOC_CAP_INTERNAL|MALLOC_CAP_IRAM_8BIT, + MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); +#else + mem = realloc(ptr, size); +#endif + +#if CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED + if (mem) { + size_t new_size = heap_caps_get_allocated_size(mem); + host_mem_used_size = host_mem_used_size - old_size + new_size; + } else if (ptr && size == 0) { + host_mem_used_size -= old_size; + } +#endif // CONFIG_BT_LE_USED_MEM_STATISTICS_ENABLED + + return mem; +} + + #if !CONFIG_BT_NIMBLE_LOW_SPEED_MODE IRAM_ATTR #endif diff --git a/components/bt/porting/npl/freertos/src/npl_os_freertos.c b/components/bt/porting/npl/freertos/src/npl_os_freertos.c index 8d0f92a6e3e..5a591ed9412 100644 --- a/components/bt/porting/npl/freertos/src/npl_os_freertos.c +++ b/components/bt/porting/npl/freertos/src/npl_os_freertos.c @@ -247,28 +247,6 @@ npl_eventq_queued_get_isr(struct ble_npl_event_freertos *event) return queued; } -static void IRAM_ATTR -npl_eventq_queued_set_isr(struct ble_npl_event_freertos *event, bool queued) -{ - portENTER_CRITICAL_ISR(&ble_port_mutex); - event->queued = queued; - portEXIT_CRITICAL_ISR(&ble_port_mutex); -} - -static bool IRAM_ATTR -npl_eventq_queued_claim_isr(struct ble_npl_event_freertos *event) -{ - bool already; - - portENTER_CRITICAL_ISR(&ble_port_mutex); - already = event->queued; - if (!already) { - event->queued = true; - } - portEXIT_CRITICAL_ISR(&ble_port_mutex); - return already; -} - static void IRAM_ATTR npl_eventq_queued_set_task(struct ble_npl_event_freertos *event, bool queued) { @@ -329,18 +307,22 @@ IRAM_ATTR npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo if (in_isr()) { BLE_LL_ASSERT(tmo == 0); + woken = pdFALSE; + + portENTER_CRITICAL_ISR(&ble_port_mutex); ret = xQueueReceiveFromISR(eventq->q, &ev, &woken); - if( woken == pdTRUE ) { + if (ret == pdPASS && ev != NULL) { + struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event; + if (event) { + event->queued = false; + } + } + portEXIT_CRITICAL_ISR(&ble_port_mutex); + + if (woken == pdTRUE) { portYIELD_FROM_ISR(); } BLE_LL_ASSERT(ret == pdPASS || ret == errQUEUE_EMPTY); - - if (ev) { - struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event; - if (event) { - npl_eventq_queued_set_isr(event, false); - } - } } else if (tmo == 0) { bool locked = npl_eventq_lock(); @@ -407,16 +389,24 @@ IRAM_ATTR npl_freertos_eventq_put(struct ble_npl_eventq *evq, struct ble_npl_eve struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event; if (in_isr()) { - if (npl_eventq_queued_claim_isr(event)) { + woken = pdFALSE; + + portENTER_CRITICAL_ISR(&ble_port_mutex); + if (event->queued) { + portEXIT_CRITICAL_ISR(&ble_port_mutex); return; } + event->queued = true; ret = xQueueSendToBackFromISR(eventq->q, &ev, &woken); if (ret != pdPASS) { - npl_eventq_queued_set_isr(event, false); + event->queued = false; + portEXIT_CRITICAL_ISR(&ble_port_mutex); return; } - if( woken == pdTRUE ) { + portEXIT_CRITICAL_ISR(&ble_port_mutex); + + if (woken == pdTRUE) { portYIELD_FROM_ISR(); } return; @@ -446,16 +436,24 @@ IRAM_ATTR npl_freertos_eventq_put_to_front(struct ble_npl_eventq *evq, struct bl struct ble_npl_event_freertos *event = (struct ble_npl_event_freertos *)ev->event; if (in_isr()) { - if (npl_eventq_queued_claim_isr(event)) { + woken = pdFALSE; + + portENTER_CRITICAL_ISR(&ble_port_mutex); + if (event->queued) { + portEXIT_CRITICAL_ISR(&ble_port_mutex); return; } + event->queued = true; ret = xQueueSendToFrontFromISR(eventq->q, &ev, &woken); if (ret != pdPASS) { - npl_eventq_queued_set_isr(event, false); + event->queued = false; + portEXIT_CRITICAL_ISR(&ble_port_mutex); return; } - if( woken == pdTRUE ) { + portEXIT_CRITICAL_ISR(&ble_port_mutex); + + if (woken == pdTRUE) { portYIELD_FROM_ISR(); } return; @@ -1059,9 +1057,19 @@ IRAM_ATTR npl_freertos_callout_stop(struct ble_npl_callout *co) } #if BLE_NPL_USE_ESP_TIMER - esp_timer_stop(callout->handle); + if (!in_isr()) { + esp_timer_stop(callout->handle); + } #else - xTimerStop(callout->handle, portMAX_DELAY); + if (in_isr()) { + BaseType_t woken = pdFALSE; + xTimerStopFromISR(callout->handle, &woken); + if (woken == pdTRUE) { + portYIELD_FROM_ISR(); + } + } else { + xTimerStop(callout->handle, portMAX_DELAY); + } #endif if (callout->evq) { diff --git a/examples/bluetooth/nimble/ble_chan_sound_reflector/main/main.c b/examples/bluetooth/nimble/ble_chan_sound_reflector/main/main.c index 3c0d6f2f241..d367d3fbb66 100644 --- a/examples/bluetooth/nimble/ble_chan_sound_reflector/main/main.c +++ b/examples/bluetooth/nimble/ble_chan_sound_reflector/main/main.c @@ -367,7 +367,7 @@ bleprph_gap_event(struct ble_gap_event *event, void *arg) rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc); assert(rc == 0); bleprph_print_conn_desc(&desc); - struct ble_cs_reflector_setup_params params; + struct ble_cs_reflector_setup_params params = {0}; params.cb=blecs_gap_event; ble_cs_reflector_setup(¶ms); diff --git a/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/main/main.c b/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/main/main.c index c7f4fa68efe..91a1691376f 100644 --- a/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/main/main.c +++ b/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/main/main.c @@ -97,7 +97,7 @@ blecent_l2cap_coc_send_data(struct ble_l2cap_chan *chan) static void blecent_l2cap_coc_on_disc_complete(const struct peer *peer, int status, void *arg) { - uint16_t psm = 0x1002; + uint16_t psm = 0x0080; struct os_mbuf *sdu_rx = NULL; int rc; diff --git a/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/main/main.c b/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/main/main.c index 3f3c46a1663..02734f1ff78 100644 --- a/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/main/main.c +++ b/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/main/main.c @@ -34,7 +34,7 @@ void ble_store_config_init(void); #define COC_BUF_COUNT (20 * MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)) #define MTU 512 -uint16_t psm = 0x1002; +uint16_t psm = 0x0080; static os_membuf_t sdu_coc_mem[OS_MEMPOOL_SIZE(COC_BUF_COUNT, MTU)]; static struct os_mempool sdu_coc_mbuf_mempool; static struct os_mbuf_pool sdu_os_mbuf_pool; @@ -332,16 +332,6 @@ bleprph_gap_event(struct ble_gap_event *event, void *arg) ext_bleprph_advertise(); #else bleprph_advertise(); -#endif - } else { - rc = ble_gap_conn_find(event->connect.conn_handle, &desc); - assert(rc == 0); - bleprph_print_conn_desc(&desc); -#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) >= 1 - rc = ble_l2cap_create_server(psm, MTU, bleprph_l2cap_coc_event_cb, NULL); - if (rc != 0) { - MODLOG_DFLT(ERROR, "Failed to create L2CAP CoC server; rc=%d", rc); - } #endif } return 0; @@ -413,6 +403,15 @@ bleprph_on_sync(void) MODLOG_DFLT(INFO, "Device Address: "); print_addr(addr_val); MODLOG_DFLT(INFO, "\n"); + +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) >= 1 + rc = ble_l2cap_create_server(psm, MTU, bleprph_l2cap_coc_event_cb, NULL); + if (rc != 0 && rc != BLE_HS_EALREADY) { + MODLOG_DFLT(ERROR, "Failed to create L2CAP COC server; rc=%d\n", rc); + return; + } +#endif + /* Begin advertising. */ #if CONFIG_EXAMPLE_EXTENDED_ADV ext_bleprph_advertise(); From 052a16bb4d5f2fecf7d3157e17ee123b0121f6b3 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Thu, 9 Jul 2026 17:53:55 +0530 Subject: [PATCH 4/6] fix(nimble): Fix bond-store overflow when IRK is enabled --- components/bt/host/nimble/nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 1a714b03dce..05eb8804bd5 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 1a714b03dcea55e58066e21213a5f150f2e50088 +Subproject commit 05eb8804bd50c7bc68c8c752ff322c8052254a39 From 9fd7cb7e606a06111e1b14be7f4e00d77d9cf3dd Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Thu, 16 Jul 2026 10:30:17 +0530 Subject: [PATCH 5/6] fix(nimble): Fix ECC HW byte-order and dropped SOC_ESP_NIMBLE_CONTROLLER --- .../tinycrypt/port/esp_tinycrypt_port.c | 93 ++++++++++++++++--- .../tinycrypt/port/esp_tinycrypt_port.h | 11 ++- components/bt/common/tinycrypt/src/ecc.c | 91 +++++++++++------- components/bt/common/tinycrypt/src/ecc_dh.c | 15 +-- components/bt/common/tinycrypt/src/ecc_dsa.c | 6 -- components/bt/host/nimble/nimble | 2 +- 6 files changed, 151 insertions(+), 67 deletions(-) diff --git a/components/bt/common/tinycrypt/port/esp_tinycrypt_port.c b/components/bt/common/tinycrypt/port/esp_tinycrypt_port.c index c4424c56ebb..16bbfb822ce 100644 --- a/components/bt/common/tinycrypt/port/esp_tinycrypt_port.c +++ b/components/bt/common/tinycrypt/port/esp_tinycrypt_port.c @@ -1,24 +1,47 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "esp_tinycrypt_port.h" +#include + #include "esp_crypto_lock.h" #include "esp_private/esp_crypto_lock_internal.h" +#include #if SOC_ECC_SUPPORTED #include "hal/ecc_hal.h" #include "hal/ecc_ll.h" #endif /* SOC_ECC_SUPPORTED */ +#define ECC_MAX_PARAM_BYTES 48 #if SOC_ECC_SUPPORTED -static void esp_tinycrypt_acquire_ecc_hardware(void) +static void uecc_vli_native_to_le(uint8_t *le, const uECC_word_t *native, uint16_t len) +{ + uint8_t be[ECC_MAX_PARAM_BYTES]; + + uECC_vli_nativeToBytes(be, len, native); + for (uint16_t i = 0; i < len; i++) { + le[i] = be[len - 1 - i]; + } +} + +static void uecc_vli_le_to_native(uECC_word_t *native, const uint8_t *le, uint16_t len) +{ + uint8_t be[ECC_MAX_PARAM_BYTES]; + + for (uint16_t i = 0; i < len; i++) { + be[i] = le[len - 1 - i]; + } + uECC_vli_bytesToNative(native, be, len); +} + +static void esp_tinycrypt_acquire_ecc_hardware(void) { esp_crypto_ecc_lock_acquire(); - ECC_RCC_ATOMIC() { ecc_ll_enable_bus_clock(true); ecc_ll_power_up(); @@ -26,23 +49,29 @@ static void esp_tinycrypt_acquire_ecc_hardware(void) } } -static void esp_tinycrypt_release_ecc_hardware(void) +static void esp_tinycrypt_release_ecc_hardware(void) { ECC_RCC_ATOMIC() { ecc_ll_enable_bus_clock(false); ecc_ll_power_down(); } - esp_crypto_ecc_lock_release(); } +#endif /* SOC_ECC_SUPPORTED */ int esp_tinycrypt_verify_ecc_point(const uint8_t *pk_x, const uint8_t *pk_y, uint8_t length) { +#if SOC_ECC_SUPPORTED int result; + uint8_t px_le[ECC_MAX_PARAM_BYTES]; + uint8_t py_le[ECC_MAX_PARAM_BYTES]; + + uecc_vli_native_to_le(px_le, (const uECC_word_t *)pk_x, length); + uecc_vli_native_to_le(py_le, (const uECC_word_t *)pk_y, length); esp_tinycrypt_acquire_ecc_hardware(); - ecc_hal_write_verify_param(pk_x, pk_y, length); + ecc_hal_write_verify_param(px_le, py_le, length); ecc_hal_set_mode(ECC_MODE_VERIFY); ecc_hal_start_calc(); while (!ecc_hal_is_calc_finished()); @@ -55,17 +84,40 @@ int esp_tinycrypt_verify_ecc_point(const uint8_t *pk_x, const uint8_t *pk_y, uin } else { return -1; } +#else + (void)pk_x; + (void)pk_y; + (void)length; + return -1; +#endif /* SOC_ECC_SUPPORTED */ } -int esp_tinycrypt_calc_ecc_mult(const uint8_t *p_x, const uint8_t *p_y, const uint8_t *scalar, - uint8_t *r_x, uint8_t *r_y, uint8_t num_bytes, bool verify_first) +int esp_tinycrypt_calc_ecc_mult(const uECC_word_t *point_x, const uECC_word_t *point_y, + const uECC_word_t *scalar, uECC_word_t *result_x, + uECC_word_t *result_y, uint8_t num_bytes, bool verify_first) { - int ret = -1; +#if SOC_ECC_SUPPORTED + int ret; ecc_mode_t work_mode = verify_first ? ECC_MODE_VERIFY_THEN_POINT_MUL : ECC_MODE_POINT_MUL; + uint8_t k_le[ECC_MAX_PARAM_BYTES]; + uint8_t px_le[ECC_MAX_PARAM_BYTES]; + uint8_t py_le[ECC_MAX_PARAM_BYTES]; + uint8_t rx_le[ECC_MAX_PARAM_BYTES]; + uint8_t ry_le[ECC_MAX_PARAM_BYTES]; + + memset(k_le, 0, sizeof(k_le)); + memset(px_le, 0, sizeof(px_le)); + memset(py_le, 0, sizeof(py_le)); + memset(rx_le, 0, sizeof(rx_le)); + memset(ry_le, 0, sizeof(ry_le)); + + uecc_vli_native_to_le(k_le, scalar, num_bytes); + uecc_vli_native_to_le(px_le, point_x, num_bytes); + uecc_vli_native_to_le(py_le, point_y, num_bytes); esp_tinycrypt_acquire_ecc_hardware(); - ecc_hal_write_mul_param(scalar, p_x, p_y, num_bytes); + ecc_hal_write_mul_param(k_le, px_le, py_le, num_bytes); ecc_hal_set_mode(work_mode); /* * Enable constant-time point multiplication operations for the ECC hardware accelerator, @@ -78,10 +130,25 @@ int esp_tinycrypt_calc_ecc_mult(const uint8_t *p_x, const uint8_t *p_y, const ui while (!ecc_hal_is_calc_finished()); - ret = ecc_hal_read_mul_result(r_x, r_y, num_bytes); + ret = ecc_hal_read_mul_result(rx_le, ry_le, num_bytes); esp_tinycrypt_release_ecc_hardware(); - return ret; -} + if (ret != 0) { + return -1; + } + + uecc_vli_le_to_native(result_x, rx_le, num_bytes); + uecc_vli_le_to_native(result_y, ry_le, num_bytes); + return 0; +#else + (void)point_x; + (void)point_y; + (void)scalar; + (void)result_x; + (void)result_y; + (void)num_bytes; + (void)verify_first; + return -1; #endif /* SOC_ECC_SUPPORTED */ +} diff --git a/components/bt/common/tinycrypt/port/esp_tinycrypt_port.h b/components/bt/common/tinycrypt/port/esp_tinycrypt_port.h index 4fdf82c2f9c..90e6ef0c2e9 100644 --- a/components/bt/common/tinycrypt/port/esp_tinycrypt_port.h +++ b/components/bt/common/tinycrypt/port/esp_tinycrypt_port.h @@ -1,15 +1,20 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ +#pragma once + #include #include #include "soc/soc_caps.h" #if SOC_ECC_SUPPORTED +#include + int esp_tinycrypt_verify_ecc_point(const uint8_t *pk_x, const uint8_t *pk_y, uint8_t length); -int esp_tinycrypt_calc_ecc_mult(const uint8_t *p_x, const uint8_t *p_y, const uint8_t *scalar, - uint8_t *r_x, uint8_t *r_y, uint8_t num_bytes, bool verify_first); +int esp_tinycrypt_calc_ecc_mult(const uECC_word_t *point_x, const uECC_word_t *point_y, + const uECC_word_t *scalar, uECC_word_t *result_x, + uECC_word_t *result_y, uint8_t num_bytes, bool verify_first); #endif /* SOC_ECC_SUPPORTED */ diff --git a/components/bt/common/tinycrypt/src/ecc.c b/components/bt/common/tinycrypt/src/ecc.c index d35031be68d..72cc5f299dd 100644 --- a/components/bt/common/tinycrypt/src/ecc.c +++ b/components/bt/common/tinycrypt/src/ecc.c @@ -58,7 +58,6 @@ #include #include -#include #include #include @@ -664,7 +663,6 @@ void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z, uECC_vli_modMult_fast(Y1, Y1, t1, curve); /* y1 * z^3 */ } -#if !SOC_ECC_SUPPORTED || SOC_ESP_NIMBLE_CONTROLLER /* P = (x1, y1) => 2P, (x2, y2) => P' */ static void XYcZ_initial_double(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * X2, uECC_word_t * Y2, @@ -730,7 +728,6 @@ static void XYcZ_addC(uECC_word_t * X1, uECC_word_t * Y1, uECC_vli_set(X1, t7, num_words); } -#endif /* !SOC_ECC_SUPPORTED */ void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * X2, uECC_word_t * Y2, @@ -763,16 +760,28 @@ void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point, const uECC_word_t * initial_Z, bitcount_t num_bits, uECC_Curve curve) { -#if SOC_ECC_SUPPORTED && !SOC_ESP_NIMBLE_CONTROLLER - wordcount_t num_words = curve->num_words; +#if SOC_ECC_SUPPORTED + wordcount_t num_words = curve->num_words; - /* Only p256r1 is supported currently. */ - assert (curve == uECC_secp256r1()); - - esp_tinycrypt_calc_ecc_mult((const uint8_t *)&point[0], (const uint8_t *)&point[num_words], - (uint8_t *)scalar, (uint8_t *)&result[0], (uint8_t *)&result[num_words], - num_words * uECC_WORD_SIZE, false); -#else + /* + * The ECC peripheral accepts canonical scalars only. Calls using the + * regularized software scalar use one additional bit and must stay on + * the software ladder. + */ + if (initial_Z == 0 && num_bits == curve->num_n_bits && + (curve == uECC_secp256r1() +#if uECC_SUPPORTS_secp192r1 + || curve == uECC_secp192r1() +#endif /* uECC_SUPPORTS_secp192r1 */ + )) { + if (esp_tinycrypt_calc_ecc_mult(point, point + num_words, scalar, + result, result + num_words, + num_words * uECC_WORD_SIZE, false) == 0) { + return; + } + } +#endif /* SOC_ECC_SUPPORTED */ + { /* R0 and R1 */ uECC_word_t Rx[2][NUM_ECC_WORDS]; uECC_word_t Ry[2][NUM_ECC_WORDS]; @@ -811,7 +820,7 @@ void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point, uECC_vli_set(result, Rx[0], num_words); uECC_vli_set(result + num_words, Ry[0], num_words); -#endif /* SOC_ECC_SUPPORTED */ + } } uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0, @@ -847,22 +856,33 @@ uECC_word_t EccPoint_compute_public_key(uECC_word_t *result, uECC_word_t *private_key, uECC_Curve curve) { -#if !SOC_ECC_SUPPORTED || SOC_ESP_NIMBLE_CONTROLLER +#if SOC_ECC_SUPPORTED + /* + * The ECC peripheral requires a canonical scalar. regularize_k() + * produces k + n or k + 2n for the software constant-time ladder, + * which is mathematically equivalent but outside the HW input range. + */ + if (curve == uECC_secp256r1() +#if uECC_SUPPORTS_secp192r1 + || curve == uECC_secp192r1() +#endif /* uECC_SUPPORTS_secp192r1 */ + ) { + EccPoint_mult(result, curve->G, private_key, 0, + curve->num_n_bits, curve); + return !EccPoint_isZero(result, curve); + } +#endif /* SOC_ECC_SUPPORTED */ + uECC_word_t tmp1[NUM_ECC_WORDS]; - uECC_word_t tmp2[NUM_ECC_WORDS]; + uECC_word_t tmp2[NUM_ECC_WORDS]; uECC_word_t *p2[2] = {tmp1, tmp2}; uECC_word_t carry; -#endif -#if SOC_ECC_SUPPORTED && !SOC_ESP_NIMBLE_CONTROLLER - EccPoint_mult(result, curve->G, private_key, 0, curve->num_n_bits, curve); -#else /* Regularize the bitcount for the private key so that attackers cannot * use a side channel attack to learn the number of leading zeros. */ carry = regularize_k(private_key, tmp1, tmp2, curve); EccPoint_mult(result, curve->G, p2[!carry], 0, curve->num_n_bits + 1, curve); -#endif if (EccPoint_isZero(result, curve)) { return 0; @@ -935,18 +955,20 @@ int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) return -2; } -#if SOC_ECC_SUPPORTED && !SOC_ESP_NIMBLE_CONTROLLER - /* Only p256r1 is supported currently. */ - if (curve != uECC_secp256r1()) { - return -5; - } - - if (esp_tinycrypt_verify_ecc_point((const uint8_t *)&point[0], - (const uint8_t *)&point[num_words], - num_words * uECC_WORD_SIZE)) { - return -3; - } -#else +#if SOC_ECC_SUPPORTED + if (curve == uECC_secp256r1() +#if uECC_SUPPORTS_secp192r1 + || curve == uECC_secp192r1() +#endif /* uECC_SUPPORTS_secp192r1 */ + ) { + if (esp_tinycrypt_verify_ecc_point((const uint8_t *)&point[0], + (const uint8_t *)&point[num_words], + num_words * uECC_WORD_SIZE) == 0) { + return 0; + } + } +#endif /* SOC_ECC_SUPPORTED */ + { uECC_word_t tmp1[NUM_ECC_WORDS]; uECC_word_t tmp2[NUM_ECC_WORDS]; @@ -954,9 +976,10 @@ int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */ /* Make sure that y^2 == x^3 + ax + b */ - if (uECC_vli_equal(tmp1, tmp2, num_words) != 0) + if (uECC_vli_equal(tmp1, tmp2, num_words) != 0) { return -3; -#endif /* SOC_ECC_SUPPORTED */ + } + } return 0; } diff --git a/components/bt/common/tinycrypt/src/ecc_dh.c b/components/bt/common/tinycrypt/src/ecc_dh.c index eeee90d6aa2..d740a429eb8 100644 --- a/components/bt/common/tinycrypt/src/ecc_dh.c +++ b/components/bt/common/tinycrypt/src/ecc_dh.c @@ -147,11 +147,9 @@ int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key, uECC_word_t _private[NUM_ECC_WORDS]; uECC_word_t tmp[NUM_ECC_WORDS]; -#if !SOC_ECC_SUPPORTED || SOC_ESP_NIMBLE_CONTROLLER uECC_word_t *p2[2] = {_private, tmp}; uECC_word_t *initial_Z = 0; uECC_word_t carry; -#endif wordcount_t num_words = curve->num_words; wordcount_t num_bytes = curve->num_bytes; int r; @@ -167,11 +165,11 @@ int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key, public_key + num_bytes, num_bytes); -#if SOC_ECC_SUPPORTED && !SOC_ESP_NIMBLE_CONTROLLER - EccPoint_mult(_public, _public, _private, 0, curve->num_n_bits, curve); -#else - /* Regularize the bitcount for the private key so that attackers cannot use a - * side channel attack to learn the number of leading zeros. */ + /* + * Use the software ladder for ECDH. Its regularized scalar is unsuitable + * for the ECC peripheral, and EccPoint_mult() can otherwise silently fall + * back to the software ladder with an unregularized scalar. + */ carry = regularize_k(_private, _private, tmp, curve); /* If an RNG function was specified, try to get a random initial Z value to @@ -187,17 +185,14 @@ int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key, EccPoint_mult(_public, _public, p2[!carry], initial_Z, curve->num_n_bits + 1, curve); -#endif uECC_vli_nativeToBytes(secret, num_bytes, _public); r = !EccPoint_isZero(_public, curve); clear_and_out: /* erasing temporary buffer used to store secret: */ -#if !SOC_ECC_SUPPORTED || SOC_ESP_NIMBLE_CONTROLLER memset(p2, 0, sizeof(p2)); __asm__ __volatile__("" :: "g"(p2) : "memory"); -#endif memset(_public, 0, sizeof(_public)); __asm__ __volatile__("" :: "g"(_public) : "memory"); memset(tmp, 0, sizeof(tmp)); diff --git a/components/bt/common/tinycrypt/src/ecc_dsa.c b/components/bt/common/tinycrypt/src/ecc_dsa.c index d167ee9104a..aef4bfe2fa9 100644 --- a/components/bt/common/tinycrypt/src/ecc_dsa.c +++ b/components/bt/common/tinycrypt/src/ecc_dsa.c @@ -101,10 +101,8 @@ int uECC_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash, uECC_word_t tmp[NUM_ECC_WORDS]; uECC_word_t s[NUM_ECC_WORDS]; -#if !SOC_ECC_SUPPORTED || SOC_ESP_NIMBLE_CONTROLLER uECC_word_t *k2[2] = {tmp, s}; uECC_word_t carry; -#endif uECC_word_t p[NUM_ECC_WORDS * 2]; wordcount_t num_words = curve->num_words; wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); @@ -116,12 +114,8 @@ int uECC_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash, return 0; } -#if SOC_ECC_SUPPORTED && !SOC_ESP_NIMBLE_CONTROLLER - EccPoint_mult(p, curve->G, k, 0, num_n_bits, curve); -#else carry = regularize_k(k, tmp, s, curve); EccPoint_mult(p, curve->G, k2[!carry], 0, num_n_bits + 1, curve); -#endif if (uECC_vli_isZero(p, num_words)) { return 0; } diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 05eb8804bd5..d53d8f2b863 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 05eb8804bd50c7bc68c8c752ff322c8052254a39 +Subproject commit d53d8f2b8639f5ee858f92d75efa80df6e6e1a52 From 9c47306adfc26d619da3dd4d6f52ddb0c6d32069 Mon Sep 17 00:00:00 2001 From: Sumeet Singh Date: Mon, 13 Jul 2026 15:41:37 +0530 Subject: [PATCH 6/6] fix(nimble): Add option to disable IEEE and UDI Characteristic in DIS (v5.5) --- components/bt/host/nimble/Kconfig.in | 14 ++++++++++++++ components/bt/host/nimble/nimble | 2 +- .../bt/host/nimble/port/include/esp_nimble_cfg.h | 12 ++++++++++++ examples/provisioning/wifi_prov_mgr/partitions.csv | 2 +- 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/components/bt/host/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in index 1b46c484ee7..e51b8ded2e1 100644 --- a/components/bt/host/nimble/Kconfig.in +++ b/components/bt/host/nimble/Kconfig.in @@ -1002,6 +1002,20 @@ menu "Services" help Enable the DIS PnP ID characteristic + config BT_NIMBLE_SVC_DIS_IEEE + depends on BT_NIMBLE_DIS_SERVICE + bool "IEEE" + default y + help + Enable the DIS IEEE characteristic + + config BT_NIMBLE_SVC_DIS_UDI + depends on BT_NIMBLE_DIS_SERVICE + bool "UDI" + default y + help + Enable the DIS UDI characteristic + config BT_NIMBLE_SVC_DIS_INCLUDED depends on BT_NIMBLE_DIS_SERVICE bool "DIS as an Included Service" diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index d53d8f2b863..3cacd66e838 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit d53d8f2b8639f5ee858f92d75efa80df6e6e1a52 +Subproject commit 3cacd66e838b03b84b778892b20beef4473e6cd3 diff --git a/components/bt/host/nimble/port/include/esp_nimble_cfg.h b/components/bt/host/nimble/port/include/esp_nimble_cfg.h index e4c095ff2d5..14f7d687152 100644 --- a/components/bt/host/nimble/port/include/esp_nimble_cfg.h +++ b/components/bt/host/nimble/port/include/esp_nimble_cfg.h @@ -1842,6 +1842,18 @@ #define MYNEWT_VAL_BLE_SVC_DIS_PNP_ID_READ_PERM (-1) #endif +#if CONFIG_BT_NIMBLE_SVC_DIS_IEEE +#define MYNEWT_VAL_BLE_SVC_DIS_IEEE_READ_PERM (0) +#else +#define MYNEWT_VAL_BLE_SVC_DIS_IEEE_READ_PERM (-1) +#endif + +#if CONFIG_BT_NIMBLE_SVC_DIS_UDI +#define MYNEWT_VAL_BLE_SVC_DIS_UDI_READ_PERM (0) +#else +#define MYNEWT_VAL_BLE_SVC_DIS_UDI_READ_PERM (-1) +#endif + #ifndef MYNEWT_VAL_BLE_SVC_DIS_INCLUDED #define MYNEWT_VAL_BLE_SVC_DIS_INCLUDED (CONFIG_BT_NIMBLE_SVC_DIS_INCLUDED) #endif diff --git a/examples/provisioning/wifi_prov_mgr/partitions.csv b/examples/provisioning/wifi_prov_mgr/partitions.csv index 2028c32c6ee..25d7b157d3d 100644 --- a/examples/provisioning/wifi_prov_mgr/partitions.csv +++ b/examples/provisioning/wifi_prov_mgr/partitions.csv @@ -2,4 +2,4 @@ # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, , 0x6000, phy_init, data, phy, , 0x1000, -factory, app, factory, , 0x15c000, +factory, app, factory, , 0x15d000,