Merge branch 'bugfix/nimble_issues_16092026_v5.3' into 'release/v5.3'

fix(nimble): Fix nimble issues 16092026 (v5.3)

See merge request espressif/esp-idf!52872
This commit is contained in:
Rahul Tank
2026-09-18 13:57:24 +05:30
8 changed files with 217 additions and 55 deletions
+1 -1
View File
@@ -34,7 +34,7 @@ function(register_bt_ctrl_libs)
set(lib_path "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/lib_${TARGET_SRC_NAME}/${TARGET_SRC_NAME}-bt-lib") set(lib_path "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/lib_${TARGET_SRC_NAME}/${TARGET_SRC_NAME}-bt-lib")
# BLE controller library # BLE controller library
if(NOT CONFIG_BT_DUAL_MODE_ARCH OR CONFIG_BT_CTRL_BLE_ENABLE) if(NOT CONFIG_BT_DUAL_MODE_ARCH OR CONFIG_BT_CTRL_BLE_ENABLE)
if(EXISTS "${lib_path}/libble_app.a") if(NOT EXISTS "${lib_path}/${idf_target}")
if(CONFIG_BT_CTRL_RUN_IN_FLASH_ONLY AND EXISTS "${lib_path}/libble_app_flash.a") if(CONFIG_BT_CTRL_RUN_IN_FLASH_ONLY AND EXISTS "${lib_path}/libble_app_flash.a")
add_prebuilt_library(libble_app "${lib_path}/libble_app_flash.a" REQUIRES esp_phy bt) add_prebuilt_library(libble_app "${lib_path}/libble_app_flash.a" REQUIRES esp_phy bt)
else() else()
+69 -4
View File
@@ -202,6 +202,71 @@ menu "Security (SMP)"
Enabling this option will delete the pairing of the device and stack will NOT post any event Enabling this option will delete the pairing of the device and stack will NOT post any event
to application. If this option is disabled, application will get BLE_GAP_EVENT_REPEAT_PAIRING to application. If this option is disabled, application will get BLE_GAP_EVENT_REPEAT_PAIRING
event. event.
config BT_NIMBLE_SMP_HARDENED_REPAIRING
bool "Reject re-pairing that weakens an existing bond"
default y
help
When a bond already exists, refuse a new pairing that would lower MITM
protection, drop Secure Connections, or shorten the encryption key.
Also enforce that a Pairing Response keeps the MITM/SC bits announced
in a preceding Security Request.
Same-level re-pairing (peer deleted its own bond and pairs again at the
same strength) is still allowed. A peer that must legitimately re-pair at
a lower level has to be unpaired first (ble_gap_unpair / NVS clear).
Disable only if a peer must downgrade and the application cannot unbond
it beforehand.
config BT_NIMBLE_SMP_REQUIRE_ENC_BEFORE_REPAIR
bool "Require encryption before re-pairing with a bonded peer"
default n
help
When enabled, a bonded peer cannot start SMP pairing on an unencrypted
link. The stack replies with Pairing Failed and disconnects.
This blocks same-level recovery when the peer deleted its bond and sends a
Pairing Request before encryption.
Default is disabled so existing apps and one-sided bond-deletion
recovery keep working. Enable for maximum hardening against
unauthenticated re-pairing.
config BT_NIMBLE_SMP_REMOVE_BOND_ON_PAIR_FAIL_AS_CENTRAL
bool "Remove the stored bond when pairing fails as Central"
default y
help
Erase NVS bonding keys when pairing or encryption fails while the local
device is Central (link-layer master). Historical Central behaviour and
the default: recovers when the peer deleted the bond and answers
encryption with Key Missing.
A downgrade refused by BT_NIMBLE_SMP_HARDENED_REPAIRING never erases
the bond, regardless of this option.
config BT_NIMBLE_SMP_REMOVE_BOND_ON_PAIR_FAIL_AS_PRPH
bool "Remove the stored bond when pairing fails as Peripheral"
default n
help
Erase NVS bonding keys when pairing or encryption fails while the local
device is Peripheral (link-layer slave). Default is disabled so a failed
pairing does not drop the bond; unbond explicitly from the app if needed.
A downgrade refused by BT_NIMBLE_SMP_HARDENED_REPAIRING never erases
the bond, regardless of this option.
config BT_NIMBLE_SMP_UNBOND_ON_KEY_MISSING
bool "Drop the local LE keys when the peer reports it has no key"
default n
help
As Central, an encryption attempt using the stored LTK can fail with
"PIN or Key Missing" when the peer deleted the bond. When enabled, the
local keys are discarded so re-pairing can proceed on the same link.
Default is disabled: the bond is kept and the link is dropped, so a peer
cannot strip the stored security level by refusing to encrypt. With the
default, BT_NIMBLE_SMP_REMOVE_BOND_ON_PAIR_FAIL_AS_CENTRAL still recovers
Central-side Key Missing by erasing on the failure path.
endif endif
endmenu #SMP endmenu #SMP
@@ -426,28 +491,28 @@ menu "GATT / ATT"
config BT_NIMBLE_GATT_CACHING_MAX_SVCS config BT_NIMBLE_GATT_CACHING_MAX_SVCS
int "Maximum number of services per connection" int "Maximum number of services per connection"
depends on BT_NIMBLE_GATT_CACHING depends on BT_NIMBLE_GATT_CACHING
default 64 default 8
help help
Set this option to set the upper limit on number of services per connection to be cached. Set this option to set the upper limit on number of services per connection to be cached.
config BT_NIMBLE_GATT_CACHING_MAX_INCL_SVCS config BT_NIMBLE_GATT_CACHING_MAX_INCL_SVCS
int "Maximum number of included services per connection" int "Maximum number of included services per connection"
depends on BT_NIMBLE_GATT_CACHING depends on BT_NIMBLE_GATT_CACHING
default 64 default 8
help help
Set this option to set the upper limit on number of included services per connection to be cached. Set this option to set the upper limit on number of included services per connection to be cached.
config BT_NIMBLE_GATT_CACHING_MAX_CHRS config BT_NIMBLE_GATT_CACHING_MAX_CHRS
int "Maximum number of characteristics per connection" int "Maximum number of characteristics per connection"
depends on BT_NIMBLE_GATT_CACHING depends on BT_NIMBLE_GATT_CACHING
default 64 default 58
help help
Set this option to set the upper limit on number of characteristics per connection to be cached. Set this option to set the upper limit on number of characteristics per connection to be cached.
config BT_NIMBLE_GATT_CACHING_MAX_DSCS config BT_NIMBLE_GATT_CACHING_MAX_DSCS
int "Maximum number of descriptors per connection" int "Maximum number of descriptors per connection"
depends on BT_NIMBLE_GATT_CACHING depends on BT_NIMBLE_GATT_CACHING
default 64 default 58
help help
Set this option to set the upper limit on number of descriptors per connection to be cached. Set this option to set the upper limit on number of descriptors per connection to be cached.
@@ -2241,6 +2241,51 @@
#endif #endif
#endif #endif
/* Bool Kconfig: defined=1 when y, absent when n. Non-ESP builds keep syscfg defaults. */
#ifndef MYNEWT_VAL_BLE_SMP_HARDENED_REPAIRING
#if defined(CONFIG_BT_NIMBLE_SMP_HARDENED_REPAIRING)
#define MYNEWT_VAL_BLE_SMP_HARDENED_REPAIRING (1)
#elif defined(CONFIG_BT_NIMBLE_ENABLED)
#define MYNEWT_VAL_BLE_SMP_HARDENED_REPAIRING (0)
#else
#define MYNEWT_VAL_BLE_SMP_HARDENED_REPAIRING (1)
#endif
#endif
#ifndef MYNEWT_VAL_BLE_SMP_REQUIRE_ENC_BEFORE_REPAIR
#if defined(CONFIG_BT_NIMBLE_SMP_REQUIRE_ENC_BEFORE_REPAIR)
#define MYNEWT_VAL_BLE_SMP_REQUIRE_ENC_BEFORE_REPAIR (1)
#else
#define MYNEWT_VAL_BLE_SMP_REQUIRE_ENC_BEFORE_REPAIR (0)
#endif
#endif
#ifndef MYNEWT_VAL_BLE_SMP_REMOVE_BOND_ON_PAIR_FAIL_AS_CENTRAL
#if defined(CONFIG_BT_NIMBLE_SMP_REMOVE_BOND_ON_PAIR_FAIL_AS_CENTRAL)
#define MYNEWT_VAL_BLE_SMP_REMOVE_BOND_ON_PAIR_FAIL_AS_CENTRAL (1)
#elif defined(CONFIG_BT_NIMBLE_ENABLED)
#define MYNEWT_VAL_BLE_SMP_REMOVE_BOND_ON_PAIR_FAIL_AS_CENTRAL (0)
#else
#define MYNEWT_VAL_BLE_SMP_REMOVE_BOND_ON_PAIR_FAIL_AS_CENTRAL (1)
#endif
#endif
#ifndef MYNEWT_VAL_BLE_SMP_REMOVE_BOND_ON_PAIR_FAIL_AS_PERIPHERAL
#if defined(CONFIG_BT_NIMBLE_SMP_REMOVE_BOND_ON_PAIR_FAIL_AS_PRPH)
#define MYNEWT_VAL_BLE_SMP_REMOVE_BOND_ON_PAIR_FAIL_AS_PERIPHERAL (1)
#else
#define MYNEWT_VAL_BLE_SMP_REMOVE_BOND_ON_PAIR_FAIL_AS_PERIPHERAL (0)
#endif
#endif
#ifndef MYNEWT_VAL_BLE_SMP_UNBOND_ON_KEY_MISSING
#if defined(CONFIG_BT_NIMBLE_SMP_UNBOND_ON_KEY_MISSING)
#define MYNEWT_VAL_BLE_SMP_UNBOND_ON_KEY_MISSING (1)
#else
#define MYNEWT_VAL_BLE_SMP_UNBOND_ON_KEY_MISSING (0)
#endif
#endif
#ifndef MYNEWT_VAL_BT_NIMBLE_MEM_OPTIMIZATION #ifndef MYNEWT_VAL_BT_NIMBLE_MEM_OPTIMIZATION
#ifdef CONFIG_BT_NIMBLE_MEM_OPTIMIZATION #ifdef CONFIG_BT_NIMBLE_MEM_OPTIMIZATION
#define MYNEWT_VAL_BT_NIMBLE_MEM_OPTIMIZATION CONFIG_BT_NIMBLE_MEM_OPTIMIZATION #define MYNEWT_VAL_BT_NIMBLE_MEM_OPTIMIZATION CONFIG_BT_NIMBLE_MEM_OPTIMIZATION
@@ -358,6 +358,29 @@ void os_mempool_flags_set(struct os_mempool *mp, uint8_t flags);
*/ */
void os_mempool_flags_clear(struct os_mempool *mp, uint8_t flags); void os_mempool_flags_clear(struct os_mempool *mp, uint8_t flags);
/**
* @brief Deinitialize a memory pool.
*
* @param mp Pointer to memory pool
*/
void os_mempool_deinit(struct os_mempool *mp);
/**
* @brief Deinitialize all of memory pools.
*
* @param is_controller Whether called from controller.
*
* @return OS_OK on success; OS_INVALID_PARM if not found corresponding memory pools.
*/
os_error_t os_mempool_deinit_all(bool is_controller);
/**
* @brief Check if there are any live memory pools.
*
* @return true if there are any live memory pools; false otherwise.
*/
bool os_mempool_has_live_pool(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
+22 -1
View File
@@ -735,6 +735,11 @@ os_mempool_module_init(void)
static os_error_t static os_error_t
os_mempool_mem_free(struct os_mempool *mp) os_mempool_mem_free(struct os_mempool *mp)
{ {
/* Extended mempool has its own free logic */
if (mp->mp_flags & OS_MEMPOOL_F_EXT) {
return OS_OK;
}
/* For runtime allocation mode, check whether all blocks have been freed */ /* For runtime allocation mode, check whether all blocks have been freed */
if (!(mp->mp_flags & OS_MEMPOOL_F_RUNTIME)) { if (!(mp->mp_flags & OS_MEMPOOL_F_RUNTIME)) {
return OS_EINVAL; return OS_EINVAL;
@@ -767,8 +772,15 @@ os_mempool_mem_free(struct os_mempool *mp)
#endif #endif
void void
os_mempool_deinit(bool is_controller) os_mempool_deinit(struct os_mempool *mp)
{ {
os_mempool_unregister(mp);
}
os_error_t
os_mempool_deinit_all(bool is_controller)
{
os_error_t err = OS_INVALID_PARM;
struct os_mempool *mp = NULL; struct os_mempool *mp = NULL;
struct os_mempool *next = NULL; struct os_mempool *next = NULL;
@@ -780,8 +792,17 @@ os_mempool_deinit(bool is_controller)
next = STAILQ_NEXT(mp, mp_list); next = STAILQ_NEXT(mp, mp_list);
os_mempool_unregister(mp); os_mempool_unregister(mp);
mp = next; mp = next;
err = OS_OK;
} else { } else {
mp = STAILQ_NEXT(mp, mp_list); mp = STAILQ_NEXT(mp, mp_list);
} }
} }
return err;
}
bool
os_mempool_has_live_pool(void)
{
return !STAILQ_EMPTY(&g_os_mempool_list);
} }
+51 -47
View File
@@ -428,6 +428,9 @@ static void read_device_services(esp_hidh_dev_t *dev)
dev->config.report_maps = NULL; dev->config.report_maps = NULL;
goto done; goto done;
} }
/* HOGP defaults to Report Protocol Mode; the Protocol Mode
* characteristic is often write-only, so it cannot be read back. */
memset(dev->protocol_mode, ESP_HID_PROTOCOL_MODE_REPORT, dev->config.report_maps_len);
} }
for (uint16_t s = 0; s < svc_count; s++) { for (uint16_t s = 0; s < svc_count; s++) {
@@ -467,6 +470,7 @@ static void read_device_services(esp_hidh_dev_t *dev)
for (uint16_t c = 0; c < ccount; c++) { for (uint16_t c = 0; c < ccount; c++) {
cuuid = ble_uuid_u16(&char_result[c].uuid.u); cuuid = ble_uuid_u16(&char_result[c].uuid.u);
chandle = char_result[c].val_handle; chandle = char_result[c].val_handle;
report = NULL;
ESP_LOGD(TAG, " CHAR:(%d), handle: %d, perm: 0x%02x, uuid: 0x%04x", ESP_LOGD(TAG, " CHAR:(%d), handle: %d, perm: 0x%02x, uuid: 0x%04x",
c + 1, chandle, char_result[c].properties, cuuid); c + 1, chandle, char_result[c].properties, cuuid);
if (suuid == BLE_SVC_GAP_UUID16) { if (suuid == BLE_SVC_GAP_UUID16) {
@@ -514,21 +518,22 @@ static void read_device_services(esp_hidh_dev_t *dev)
} }
} }
} }
continue; }
} else { continue;
if (cuuid == BLE_SVC_HID_CHR_UUID16_PROTOCOL_MODE) { } else if (suuid == BLE_SVC_HID_UUID16) {
if (char_result[c].properties & BLE_GATT_CHR_PROP_READ) { if (cuuid == BLE_SVC_HID_CHR_UUID16_PROTOCOL_MODE) {
if (read_char(dev->ble.conn_id, chandle, &rdata, &rlen) == 0 && rlen) { if ((char_result[c].properties & BLE_GATT_CHR_PROP_READ) != 0
dev->protocol_mode[hidindex] = *((uint8_t *)rdata); && dev->protocol_mode != NULL && hidindex < dev->config.report_maps_len) {
free(rdata); if (read_char(dev->ble.conn_id, chandle, &rdata, &rlen) == 0 && rlen) {
rdata = NULL; dev->protocol_mode[hidindex] = *((uint8_t *)rdata);
}
} }
free(rdata);
rdata = NULL;
} }
continue; continue;
} } else if (cuuid == BLE_SVC_HID_CHR_UUID16_REPORT_MAP) {
if (cuuid == BLE_SVC_HID_CHR_UUID16_REPORT_MAP) { if ((char_result[c].properties & BLE_GATT_CHR_PROP_READ) != 0
if (char_result[c].properties & BLE_GATT_CHR_PROP_READ) { && dev->config.report_maps != NULL && hidindex < dev->config.report_maps_len) {
if (read_char(dev->ble.conn_id, chandle, &rdata, &rlen) == 0 && rlen) { if (read_char(dev->ble.conn_id, chandle, &rdata, &rlen) == 0 && rlen) {
uint8_t *copy = nimble_hidh_dup_bytes(rdata, rlen); uint8_t *copy = nimble_hidh_dup_bytes(rdata, rlen);
if (copy) { if (copy) {
@@ -537,41 +542,38 @@ static void read_device_services(esp_hidh_dev_t *dev)
dev->config.report_maps[hidindex].len = rlen; dev->config.report_maps[hidindex].len = rlen;
} }
} }
continue; free(rdata);
} else if (cuuid == BLE_SVC_HID_CHR_UUID16_BOOT_KBD_INP || cuuid == BLE_SVC_HID_CHR_UUID16_BOOT_KBD_OUT rdata = NULL;
|| cuuid == BLE_SVC_HID_CHR_UUID16_BOOT_MOUSE_INP || cuuid == BLE_SVC_HID_CHR_UUID16_RPT) { }
report = (esp_hidh_dev_report_t *)malloc(sizeof(esp_hidh_dev_report_t)); continue;
if (report == NULL) { } else if (cuuid == BLE_SVC_HID_CHR_UUID16_BOOT_KBD_INP || cuuid == BLE_SVC_HID_CHR_UUID16_BOOT_KBD_OUT
ESP_LOGE(TAG, "malloc esp_hidh_dev_report_t failed"); || cuuid == BLE_SVC_HID_CHR_UUID16_BOOT_MOUSE_INP || cuuid == BLE_SVC_HID_CHR_UUID16_RPT) {
goto done; report = (esp_hidh_dev_report_t *)malloc(sizeof(esp_hidh_dev_report_t));
} if (report == NULL) {
report->next = NULL; ESP_LOGE(TAG, "malloc esp_hidh_dev_report_t failed");
report->permissions = char_result[c].properties; goto done;
report->handle = chandle; }
report->ccc_handle = 0; report->next = NULL;
report->report_id = 0; report->permissions = char_result[c].properties;
report->map_index = hidindex; report->handle = chandle;
if (cuuid == BLE_SVC_HID_CHR_UUID16_BOOT_KBD_INP) { report->ccc_handle = 0;
report->protocol_mode = ESP_HID_PROTOCOL_MODE_BOOT; report->report_id = 0;
report->report_type = ESP_HID_REPORT_TYPE_INPUT; report->map_index = hidindex;
report->usage = ESP_HID_USAGE_KEYBOARD; if (cuuid == BLE_SVC_HID_CHR_UUID16_BOOT_KBD_INP) {
report->value_len = 8; report->protocol_mode = ESP_HID_PROTOCOL_MODE_BOOT;
} else if (cuuid == BLE_SVC_HID_CHR_UUID16_BOOT_KBD_OUT) { report->report_type = ESP_HID_REPORT_TYPE_INPUT;
report->protocol_mode = ESP_HID_PROTOCOL_MODE_BOOT; report->usage = ESP_HID_USAGE_KEYBOARD;
report->report_type = ESP_HID_REPORT_TYPE_OUTPUT; report->value_len = 8;
report->usage = ESP_HID_USAGE_KEYBOARD; } else if (cuuid == BLE_SVC_HID_CHR_UUID16_BOOT_KBD_OUT) {
report->value_len = 8; report->protocol_mode = ESP_HID_PROTOCOL_MODE_BOOT;
} else if (cuuid == BLE_SVC_HID_CHR_UUID16_BOOT_MOUSE_INP) { report->report_type = ESP_HID_REPORT_TYPE_OUTPUT;
report->protocol_mode = ESP_HID_PROTOCOL_MODE_BOOT; report->usage = ESP_HID_USAGE_KEYBOARD;
report->report_type = ESP_HID_REPORT_TYPE_INPUT; report->value_len = 8;
report->usage = ESP_HID_USAGE_MOUSE; } else if (cuuid == BLE_SVC_HID_CHR_UUID16_BOOT_MOUSE_INP) {
report->value_len = 8; report->protocol_mode = ESP_HID_PROTOCOL_MODE_BOOT;
} else { report->report_type = ESP_HID_REPORT_TYPE_INPUT;
report->protocol_mode = ESP_HID_PROTOCOL_MODE_REPORT; report->usage = ESP_HID_USAGE_MOUSE;
report->report_type = 0; report->value_len = 8;
report->usage = ESP_HID_USAGE_GENERIC;
report->value_len = 0;
}
} else { } else {
report->protocol_mode = ESP_HID_PROTOCOL_MODE_REPORT; report->protocol_mode = ESP_HID_PROTOCOL_MODE_REPORT;
report->report_type = 0; report->report_type = 0;
@@ -581,6 +583,8 @@ static void read_device_services(esp_hidh_dev_t *dev)
} else { } else {
continue; continue;
} }
} else {
continue;
} }
struct ble_gatt_dsc descr_result[HIDH_MAX_DSCS]; struct ble_gatt_dsc descr_result[HIDH_MAX_DSCS];
uint16_t num_dsc = HIDH_MAX_DSCS; uint16_t num_dsc = HIDH_MAX_DSCS;
@@ -18,6 +18,10 @@
#define BLE_PAWR_RSP_SLOT_SPACING (10) /*!< Time between response slots (N * 0.125 ms) */ #define BLE_PAWR_RSP_SLOT_SPACING (10) /*!< Time between response slots (N * 0.125 ms) */
#define BLE_PAWR_NUM_RSP_SLOTS (25) /*!< Number of subevent response slots */ #define BLE_PAWR_NUM_RSP_SLOTS (25) /*!< Number of subevent response slots */
#define BLE_PAWR_SUB_DATA_LEN (20) #define BLE_PAWR_SUB_DATA_LEN (20)
/* Give the controller a few periodic intervals to report the outcome of a
* synchronized connection attempt before retrying from another subevent.
*/
#define BLE_PAWR_CONN_TIMEOUT_MS (3 * BLE_PAWR_EVENT_PERIODIC_INTERVAL_MS)
#define TAG "NimBLE_BLE_PAwR_CONN" #define TAG "NimBLE_BLE_PAwR_CONN"
@@ -162,7 +166,7 @@ gap_event_cb(struct ble_gap_event *event, void *arg)
phy_mask = 0x01; phy_mask = 0x01;
if (conn == 0) { if (conn == 0) {
rc = ble_gap_connect_with_synced(own_addr_type,adv_handle,subevent,&peer_addr,30000,phy_mask,NULL,NULL,NULL,gap_event_cb,NULL); rc = ble_gap_connect_with_synced(own_addr_type,adv_handle,subevent,&peer_addr,BLE_PAWR_CONN_TIMEOUT_MS,phy_mask,NULL,NULL,NULL,gap_event_cb,NULL);
if (rc != 0 ) { if (rc != 0 ) {
ESP_LOGI(TAG,"Error: Failed to connect to device , rc = %d\n",rc); ESP_LOGI(TAG,"Error: Failed to connect to device , rc = %d\n",rc);
} else { } else {