diff --git a/components/bt/ble_profiles/nimble/ble_esl/include/ble_esl.h b/components/bt/ble_profiles/nimble/ble_esl/include/ble_esl.h index fa020da78d8..d255971649f 100644 --- a/components/bt/ble_profiles/nimble/ble_esl/include/ble_esl.h +++ b/components/bt/ble_profiles/nimble/ble_esl/include/ble_esl.h @@ -413,7 +413,7 @@ esp_err_t ble_esl_export_persisted_tag(ble_esl_persisted_tag_t *out); * * Performs bare field assignment (does NOT call esl_state_transition). Sets * state to UNSYNCHRONIZED and config_complete to Address|AP Sync|Resp only - * (CONFIG_BIT_ABS_TIME cleared). Does not start advertising or timers — + * (Absolute Time bit cleared). Does not start advertising or timers — * ble_esl_start() must follow to arm unsync_timer and connectable advertising. * * @param[in] info Valid association snapshot diff --git a/components/bt/ble_profiles/nimble/ble_esl/include/ble_esl_ap.h b/components/bt/ble_profiles/nimble/ble_esl/include/ble_esl_ap.h index b38486b9f44..b02cb5b6b99 100644 --- a/components/bt/ble_profiles/nimble/ble_esl/include/ble_esl_ap.h +++ b/components/bt/ble_profiles/nimble/ble_esl/include/ble_esl_ap.h @@ -106,6 +106,7 @@ typedef struct { typedef struct { ble_esl_ap_cb_t callback; /*!< Application event callback (must not be NULL) */ ble_esl_ap_pawr_config_t pawr_config; /*!< PAwR timing parameters */ + ble_esl_key_material_t ap_sync_key; /*!< PAwR train Sync Key (one per AP, not per ESL) */ } ble_esl_ap_config_t; /* ========================== Connection Event Structures ========================== */ @@ -159,7 +160,6 @@ typedef struct { typedef struct { uint8_t esl_id; /*!< ESL_ID to assign (0x00–0xFE) */ uint8_t group_id; /*!< Group_ID to assign (0x00–0x7F) */ - ble_esl_key_material_t ap_sync_key; /*!< AP Sync Key Material (session key + IV) */ ble_esl_key_material_t resp_key; /*!< ESL Response Key Material (session key + IV) */ } ble_esl_ap_esl_config_t; @@ -348,13 +348,25 @@ typedef struct { * Registers the application callback, stores PAwR timing parameters, * and allocates internal resources. Must be called before any other API. * - * @param config Pointer to AP configuration (callback + PAwR timing) + * @param config Pointer to AP configuration (callback, PAwR timing, AP Sync Key) * @return ESP_OK on success; ESP_ERR_INVALID_ARG if config/callback is NULL or * num_subevents is outside 1–128; * ESP_ERR_INVALID_STATE if already initialized */ esp_err_t ble_esl_ap_init(const ble_esl_ap_config_t *config); +/** + * @brief Set or replace the AP-wide PAwR Sync Key Material + * + * One key encrypts the whole PAwR train. ble_esl_ap_init() installs + * config->ap_sync_key; call this to rekey or restore a persisted network + * key. Does not rewrite already-configured ESLs over GATT. + * + * @param key AP Sync Key Material (session key + IV) + * @return ESP_OK on success; ESP_ERR_INVALID_ARG / ESP_ERR_INVALID_STATE + */ +esp_err_t ble_esl_ap_set_sync_key(const ble_esl_key_material_t *key); + /** * @brief Deinitialize the AP module * @@ -483,12 +495,13 @@ esp_err_t ble_esl_ap_abort_tag_connections(void); /** * @brief Write ESL configuration characteristics * - * Writes ESL Address, AP Sync Key Material, ESL Response Key Material, and - * ESL Current Absolute Time in sequence. Async — result via + * Writes ESL Address, the AP-wide Sync Key already installed by + * ble_esl_ap_init() / ble_esl_ap_set_sync_key(), ESL Response Key Material, + * and ESL Current Absolute Time in sequence. Async — result via * BLE_ESL_AP_EVT_CONFIGURED. * * @param conn_handle Connection handle of the connected ESL - * @param config Pointer to configuration parameters + * @param config Pointer to per-ESL parameters (address + response key) * @return ESP_OK if operation initiated; error code on failure */ esp_err_t ble_esl_ap_configure(uint16_t conn_handle, @@ -537,14 +550,17 @@ bool ble_esl_ap_synchronize_in_progress(void); /** * @brief Write ESL Current Absolute Time on an encrypted ACL link * - * Uses the current boot monotonic clock (esp_timer_get_time()/1000). - * Completion is BLE_ESL_AP_EVT_ABS_TIME_WRITTEN (once, if this returns ESP_OK). + * @p abs_time_ms is the ESL 32-bit millisecond counter (wrapping), not a + * POSIX/RTC timestamp. The application owns the epoch (boot monotonic, + * persisted network time, SNTP-derived, etc.). Completion is + * BLE_ESL_AP_EVT_ABS_TIME_WRITTEN (once, if this returns ESP_OK). * Rejected while configure occupies the same connection. * * @param conn_handle Connection handle of the connected ESL + * @param abs_time_ms Absolute time in milliseconds to write to the ESL * @return ESP_OK if the GATT write was initiated */ -esp_err_t ble_esl_ap_write_absolute_time(uint16_t conn_handle); +esp_err_t ble_esl_ap_write_absolute_time(uint16_t conn_handle, uint32_t abs_time_ms); /** * @brief In-memory association snapshot used to seed AP tracking after reboot @@ -552,15 +568,14 @@ esp_err_t ble_esl_ap_write_absolute_time(uint16_t conn_handle); * Not an NVS/wire blob. Call after ble_esl_ap_init(); may be invoked * multiple times (once per ESL), including after ble_esl_ap_start_pawr(). * Key material is not checked for all-zeros — the application must - * quarantine corrupt records. The AP Sync Key of the last successful - * restore is installed as the current PAwR key. + * quarantine corrupt records. The AP Sync Key is AP-wide: restore it + * once via ble_esl_ap_init() / ble_esl_ap_set_sync_key(), not per ESL. */ typedef struct { ble_esl_address_t esl_address; /*!< ESL Address (ESL_ID + Group_ID) */ uint8_t ble_addr[6]; /*!< Identity address of the ESL */ uint8_t ble_addr_type; /*!< BLE address type */ - ble_esl_key_material_t ap_sync_key; - ble_esl_key_material_t resp_key; + ble_esl_key_material_t resp_key; /*!< Per-ESL Response Key Material */ } ble_esl_ap_persisted_esl_t; esp_err_t ble_esl_ap_restore_persisted_esl(const ble_esl_ap_persisted_esl_t *info); diff --git a/components/bt/ble_profiles/nimble/ble_esl/src/ap/ap_connection.c b/components/bt/ble_profiles/nimble/ble_esl/src/ap/ap_connection.c index 334d9fd880b..f8633be5f03 100644 --- a/components/bt/ble_profiles/nimble/ble_esl/src/ap/ap_connection.c +++ b/components/bt/ble_profiles/nimble/ble_esl/src/ap/ap_connection.c @@ -269,6 +269,8 @@ esp_err_t ble_esl_ap_init(const ble_esl_ap_config_t *config) g_esl_ap->app_cb = config->callback; g_esl_ap->pawr_config = config->pawr_config; g_esl_ap->initialized = true; + ble_esl_ap_pawr_set_sync_key(&config->ap_sync_key); + g_esl_ap->ap_sync_key_valid = true; g_esl_ap->pawr_started = false; g_esl_ap->pawr_active = false; @@ -335,6 +337,19 @@ esp_err_t ble_esl_ap_init(const ble_esl_ap_config_t *config) return ESP_OK; } +esp_err_t ble_esl_ap_set_sync_key(const ble_esl_key_material_t *key) +{ + if (g_esl_ap == NULL || !g_esl_ap->initialized) { + return ESP_ERR_INVALID_STATE; + } + if (key == NULL) { + return ESP_ERR_INVALID_ARG; + } + ble_esl_ap_pawr_set_sync_key(key); + g_esl_ap->ap_sync_key_valid = true; + return ESP_OK; +} + /** * @brief Run the disconnect cleanup for one established link during deinit * diff --git a/components/bt/ble_profiles/nimble/ble_esl/src/ap/ap_lifecycle.c b/components/bt/ble_profiles/nimble/ble_esl/src/ap/ap_lifecycle.c index 8ac62102cb8..ea8b1b83937 100644 --- a/components/bt/ble_profiles/nimble/ble_esl/src/ap/ap_lifecycle.c +++ b/components/bt/ble_profiles/nimble/ble_esl/src/ap/ap_lifecycle.c @@ -64,6 +64,7 @@ _Static_assert(sizeof(ble_esl_key_material_t) == BLE_ESL_KEY_MATERIAL_SIZE, typedef struct { uint16_t conn_handle; ble_esl_ap_esl_config_t config; + ble_esl_key_material_t ap_sync_key; /*!< Snapshot of the AP-wide sync key */ uint16_t esl_addr; uint32_t lf_generation; } configure_ctx_t; @@ -182,8 +183,7 @@ static TaskHandle_t s_lifecycle_holder; _Static_assert(sizeof(ble_esl_key_material_t) == 24, "sync key packed 24"); _Static_assert(sizeof(ble_esl_key_material_t) == 24, "resp key packed 24"); /* In-memory compactness only — not an NVS/wire layout. */ -_Static_assert(offsetof(ble_esl_ap_persisted_esl_t, ap_sync_key) == 9, "flat key block start"); -_Static_assert(offsetof(ble_esl_ap_persisted_esl_t, resp_key) == 9 + 24, "resp key follows sync"); +_Static_assert(offsetof(ble_esl_ap_persisted_esl_t, resp_key) == 9, "resp key follows identity"); static void lf_lock(void) { @@ -261,11 +261,9 @@ static void lf_release(ble_esl_ap_conn_t *conn, uint32_t generation) } } -static esp_err_t write_abs_time_bytes(uint16_t conn_handle, +static esp_err_t write_abs_time_bytes(uint16_t conn_handle, uint32_t abs_time_ms, ble_esl_ap_gatt_cb_t cb, void *user_data) { - int64_t now_us = esp_timer_get_time(); - uint32_t abs_time_ms = (uint32_t)(now_us / 1000ULL); uint8_t abs_time_data[4] = { (uint8_t)(abs_time_ms & 0xFF), (uint8_t)((abs_time_ms >> 8) & 0xFF), @@ -318,7 +316,7 @@ static void write_abs_time_gatt_cb(uint16_t conn_handle, esp_err_t status, free(ctx); } -esp_err_t ble_esl_ap_write_absolute_time(uint16_t conn_handle) +esp_err_t ble_esl_ap_write_absolute_time(uint16_t conn_handle, uint32_t abs_time_ms) { if (g_esl_ap == NULL) { return ESP_ERR_INVALID_STATE; @@ -346,7 +344,8 @@ esp_err_t ble_esl_ap_write_absolute_time(uint16_t conn_handle) ctx->generation = gen; ctx->public_event = true; - esp_err_t ret = write_abs_time_bytes(conn_handle, write_abs_time_gatt_cb, ctx); + esp_err_t ret = write_abs_time_bytes(conn_handle, abs_time_ms, + write_abs_time_gatt_cb, ctx); if (ret != ESP_OK) { lf_lock(); conn = ble_esl_ap_find_conn(conn_handle); @@ -369,7 +368,9 @@ static esp_err_t write_abs_time_for_configure(uint16_t conn_handle, uint32_t gen ctx->public_event = false; ctx->chained_cb = configure_write_abs_time_cb; ctx->user_data = configure_ctx; - esp_err_t ret = write_abs_time_bytes(conn_handle, write_abs_time_gatt_cb, ctx); + uint32_t abs_time_ms = (uint32_t)(esp_timer_get_time() / 1000ULL); + esp_err_t ret = write_abs_time_bytes(conn_handle, abs_time_ms, + write_abs_time_gatt_cb, ctx); if (ret != ESP_OK) { free(ctx); } @@ -624,6 +625,11 @@ esp_err_t ble_esl_ap_configure(uint16_t conn_handle, return ESP_ERR_INVALID_ARG; } + if (!g_esl_ap->ap_sync_key_valid) { + ESP_LOGE(TAG, "configure: AP Sync Key not set"); + return ESP_ERR_INVALID_STATE; + } + /* Validate connection handle */ ble_esl_ap_conn_t *conn = ble_esl_ap_find_conn(conn_handle); if (conn == NULL) { @@ -639,6 +645,7 @@ esp_err_t ble_esl_ap_configure(uint16_t conn_handle, ctx->conn_handle = conn_handle; memcpy(&ctx->config, config, sizeof(ble_esl_ap_esl_config_t)); + ctx->ap_sync_key = g_esl_ap->ap_sync_key; ctx->esl_addr = BLE_ESL_AP_MAKE_ADDR(config->esl_id, config->group_id); /* Store ESL address in connection context for cross-reference */ @@ -681,9 +688,6 @@ esp_err_t ble_esl_ap_configure(uint16_t conn_handle, return occ; } - /* Set PAwR sync key (shared across all ESLs) */ - ble_esl_ap_pawr_set_sync_key(&config->ap_sync_key); - /* Set per-ESL response key */ esp_err_t ret = ble_esl_ap_pawr_set_response_key(ctx->esl_addr, &config->resp_key); @@ -731,8 +735,8 @@ static void configure_write_addr_cb(uint16_t conn_handle, esp_err_t status, /* Step 2: Write AP Sync Key Material (24 bytes: 16-byte key + 8-byte IV) */ esp_err_t ret = ble_esl_ap_gatt_write(conn_handle, BLE_ESL_CHR_UUID_AP_SYNC_KEY, - (const uint8_t *)&ctx->config.ap_sync_key, - sizeof(ctx->config.ap_sync_key), + (const uint8_t *)&ctx->ap_sync_key, + sizeof(ctx->ap_sync_key), configure_write_sync_key_cb, ctx); if (ret != ESP_OK) { ESP_LOGE(TAG, "configure: failed to initiate AP Sync Key write: %s", @@ -1699,13 +1703,23 @@ esp_err_t ble_esl_ap_restore_persisted_esl(const ble_esl_ap_persisted_esl_t *inf return ESP_ERR_INVALID_ARG; } + if (!g_esl_ap->ap_sync_key_valid) { + ESP_LOGE(TAG, "restore: AP Sync Key not set"); + return ESP_ERR_INVALID_STATE; + } + ble_esl_ap_tracking_lock(); ble_esl_ap_esl_entry_t *esl = ble_esl_ap_find_esl(esl_addr); if (esl == NULL) { esl = ble_esl_ap_find_esl_by_ble_addr(info->ble_addr, info->ble_addr_type); } + bool created = false; + ble_esl_ap_esl_entry_t backup = { 0 }; if (esl == NULL) { esl = ble_esl_ap_alloc_esl(); + created = true; + } else { + backup = *esl; } if (esl == NULL) { ble_esl_ap_tracking_unlock(); @@ -1722,24 +1736,26 @@ esp_err_t ble_esl_ap_restore_persisted_esl(const ble_esl_ap_persisted_esl_t *inf esl->pending_pawr_cmd_opcode = 0; esl->resp_key = info->resp_key; esl->last_sync_time_us = 0; - ble_esl_ap_tracking_unlock(); - ble_esl_ap_pawr_set_sync_key(&info->ap_sync_key); - - esp_err_t ret = ble_esl_ap_pawr_set_response_key(esl_addr, - &info->resp_key); - if (ret != ESP_OK) { - ESP_LOGW(TAG, "restore: set response key for 0x%04X failed: %s", - esl_addr, esp_err_to_name(ret)); - } - - ret = ble_esl_ap_update_esl_state(esl_addr, - BLE_ESL_STATE_UNSYNCHRONIZED); + ble_esl_ap_state_evt_snap_t snap = { 0 }; + esp_err_t ret = ble_esl_ap_update_esl_state_locked(esl_addr, + BLE_ESL_STATE_UNSYNCHRONIZED, + &snap); if (ret != ESP_OK) { + if (created) { + memset(esl, 0, sizeof(*esl)); + esl->in_use = false; + esl->conn_handle = BLE_ESL_AP_CONN_HANDLE_INVALID; + } else { + *esl = backup; + } + ble_esl_ap_tracking_unlock(); ESP_LOGE(TAG, "restore: failed to mark ESL 0x%04X unsynchronized: %s", esl_addr, esp_err_to_name(ret)); return ret; } + ble_esl_ap_tracking_unlock(); + ble_esl_ap_dispatch_state_evt(&snap); ESP_LOGI(TAG, "Restored ESL 0x%04X from persistence (awaiting resync)", esl_addr); diff --git a/components/bt/ble_profiles/nimble/ble_esl/src/ap/ble_esl_ap_int.h b/components/bt/ble_profiles/nimble/ble_esl/src/ap/ble_esl_ap_int.h index cc439887f9a..aacccad5c22 100644 --- a/components/bt/ble_profiles/nimble/ble_esl/src/ap/ble_esl_ap_int.h +++ b/components/bt/ble_profiles/nimble/ble_esl/src/ap/ble_esl_ap_int.h @@ -247,6 +247,7 @@ typedef struct { /* PAwR broadcaster state */ ble_esl_key_material_t ap_sync_key; /*!< AP Sync Key Material */ + bool ap_sync_key_valid; /*!< Sync key installed via init/setter */ uint8_t randomizer[BLE_ESL_RANDOMIZER_SIZE]; /*!< Current AP Randomizer (5 octets, LE) */ bool pawr_active; /*!< PAwR broadcaster is running */ ble_esl_ap_pawr_pending_t *pawr_pending; /*!< Per-subevent pending TX buffers (num_subevents entries) */ diff --git a/components/bt/ble_profiles/nimble/ble_esl/src/esl/ble_esl_state_int.h b/components/bt/ble_profiles/nimble/ble_esl/src/esl/ble_esl_state_int.h index 20b6574e0f9..a5d50c49e08 100644 --- a/components/bt/ble_profiles/nimble/ble_esl/src/esl/ble_esl_state_int.h +++ b/components/bt/ble_profiles/nimble/ble_esl/src/esl/ble_esl_state_int.h @@ -30,12 +30,12 @@ extern "C" { /* ========================== Configuration Bitmask ========================== */ -#define CONFIG_BIT_ADDRESS (1 << 0) -#define CONFIG_BIT_AP_SYNC_KEY (1 << 1) -#define CONFIG_BIT_RESP_KEY (1 << 2) -#define CONFIG_BIT_ABS_TIME (1 << 3) -#define CONFIG_COMPLETE_MASK (CONFIG_BIT_ADDRESS | CONFIG_BIT_AP_SYNC_KEY | \ - CONFIG_BIT_RESP_KEY | CONFIG_BIT_ABS_TIME) +#define ESL_CONFIG_BIT_ADDRESS (1 << 0) +#define ESL_CONFIG_BIT_AP_SYNC_KEY (1 << 1) +#define ESL_CONFIG_BIT_RESP_KEY (1 << 2) +#define ESL_CONFIG_BIT_ABS_TIME (1 << 3) +#define ESL_CONFIG_COMPLETE_MASK (ESL_CONFIG_BIT_ADDRESS | ESL_CONFIG_BIT_AP_SYNC_KEY | \ + ESL_CONFIG_BIT_RESP_KEY | ESL_CONFIG_BIT_ABS_TIME) /* ========================== Internal State Context ========================== */ typedef struct { @@ -65,9 +65,7 @@ typedef struct { * retiring_* tracks a locally terminated old sync so its SYNC_LOST does not * look like a natural loss of the new train. */ uint16_t current_sync_handle; /* Valid periodic sync; BLE_HS_CONN_HANDLE_NONE if none */ - uint32_t sync_generation; /* Bumps each time current_sync_handle is assigned a new value */ uint16_t retiring_sync_handle; /* Locally terminated old sync awaiting SYNC_LOST */ - uint32_t retiring_sync_generation; /* Snapshot of sync_generation when current was retired */ bool retiring_local_terminate; /* retiring SYNC_LOST is expected; do not change ESL state */ bool past_received; /* PAST completed in Updating state */ bool pawr_synced; /* Synchronized to the AP's PAwR train (retained across Updating) */ diff --git a/components/bt/ble_profiles/nimble/ble_esl/src/esl/esl_gatts.c b/components/bt/ble_profiles/nimble/ble_esl/src/esl/esl_gatts.c index 5185d75c0a9..c726846ab8f 100644 --- a/components/bt/ble_profiles/nimble/ble_esl/src/esl/esl_gatts.c +++ b/components/bt/ble_profiles/nimble/ble_esl/src/esl/esl_gatts.c @@ -241,7 +241,7 @@ static int handle_write_esl_address(struct os_mbuf *om) s_esl_gatts->ctx->esl_address = addr; s_esl_gatts->ctx->address_valid = true; - s_esl_gatts->ctx->config_complete |= CONFIG_BIT_ADDRESS; + s_esl_gatts->ctx->config_complete |= ESL_CONFIG_BIT_ADDRESS; ESP_LOGI(TAG, "ESL Address set: id=0x%02x group=0x%02x", addr.esl_id, BLE_ESL_ADDR_GROUP_ID(addr)); return 0; @@ -261,7 +261,7 @@ static int handle_write_ap_sync_key(struct os_mbuf *om) } s_esl_gatts->ctx->ap_sync_key_valid = true; - s_esl_gatts->ctx->config_complete |= CONFIG_BIT_AP_SYNC_KEY; + s_esl_gatts->ctx->config_complete |= ESL_CONFIG_BIT_AP_SYNC_KEY; ESP_LOGI(TAG, "AP Sync Key Material written"); return 0; } @@ -280,7 +280,7 @@ static int handle_write_resp_key(struct os_mbuf *om) } s_esl_gatts->ctx->resp_key_valid = true; - s_esl_gatts->ctx->config_complete |= CONFIG_BIT_RESP_KEY; + s_esl_gatts->ctx->config_complete |= ESL_CONFIG_BIT_RESP_KEY; ESP_LOGI(TAG, "ESL Response Key Material written"); return 0; } @@ -300,7 +300,7 @@ static int handle_write_abs_time(struct os_mbuf *om) s_esl_gatts->ctx->abs_time_base = time_val; s_esl_gatts->ctx->abs_time_offset_us = esp_timer_get_time(); - s_esl_gatts->ctx->config_complete |= CONFIG_BIT_ABS_TIME; + s_esl_gatts->ctx->config_complete |= ESL_CONFIG_BIT_ABS_TIME; ESP_LOGI(TAG, "ESL Absolute Time set: %" PRIu32 " ms", time_val); return 0; } diff --git a/components/bt/ble_profiles/nimble/ble_esl/src/esl/esl_persisted_tag_map.h b/components/bt/ble_profiles/nimble/ble_esl/src/esl/esl_persisted_tag_map.h index 721a2eff344..be8bb33f582 100644 --- a/components/bt/ble_profiles/nimble/ble_esl/src/esl/esl_persisted_tag_map.h +++ b/components/bt/ble_profiles/nimble/ble_esl/src/esl/esl_persisted_tag_map.h @@ -6,7 +6,7 @@ /** * @file esl_persisted_tag_map.h - * @brief Pure helpers for TAG persisted snapshot field mapping (host-testable). + * @brief Helpers for TAG persisted snapshot field mapping. */ #pragma once @@ -14,20 +14,15 @@ #include #include #include "ble_esl_common.h" +#include "ble_esl_state_int.h" #ifdef __cplusplus extern "C" { #endif -#ifndef CONFIG_BIT_ADDRESS -#define CONFIG_BIT_ADDRESS (1 << 0) -#define CONFIG_BIT_AP_SYNC_KEY (1 << 1) -#define CONFIG_BIT_RESP_KEY (1 << 2) -#define CONFIG_BIT_ABS_TIME (1 << 3) -#endif - +/* Persist does not store Absolute Time; restore must leave that bit clear. */ #define ESL_PERSISTED_CONFIG_MASK \ - (CONFIG_BIT_ADDRESS | CONFIG_BIT_AP_SYNC_KEY | CONFIG_BIT_RESP_KEY) + (ESL_CONFIG_BIT_ADDRESS | ESL_CONFIG_BIT_AP_SYNC_KEY | ESL_CONFIG_BIT_RESP_KEY) typedef struct { ble_esl_address_t esl_address; diff --git a/components/bt/ble_profiles/nimble/ble_esl/src/esl/esl_state.c b/components/bt/ble_profiles/nimble/ble_esl/src/esl/esl_state.c index 14be6340611..4626848d040 100644 --- a/components/bt/ble_profiles/nimble/ble_esl/src/esl/esl_state.c +++ b/components/bt/ble_profiles/nimble/ble_esl/src/esl/esl_state.c @@ -11,7 +11,6 @@ #include #include -#include #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" @@ -58,7 +57,6 @@ static void clear_retiring_sync(void) return; } s_ctx->retiring_sync_handle = BLE_HS_CONN_HANDLE_NONE; - s_ctx->retiring_sync_generation = 0; s_ctx->retiring_local_terminate = false; } @@ -68,7 +66,6 @@ static void clear_current_sync_bookkeeping(void) return; } s_ctx->current_sync_handle = BLE_HS_CONN_HANDLE_NONE; - /* sync_generation is monotonic across NONE assignments; do not reset. */ } static void install_current_sync(uint16_t sync_handle) @@ -77,11 +74,6 @@ static void install_current_sync(uint16_t sync_handle) return; } s_ctx->current_sync_handle = sync_handle; - if (s_ctx->sync_generation == UINT32_MAX) { - s_ctx->sync_generation = 1; - } else { - s_ctx->sync_generation++; - } } /** @@ -112,10 +104,8 @@ static esp_err_t retire_current_sync(bool rearm_past) } uint16_t old_handle = s_ctx->current_sync_handle; - uint32_t old_generation = s_ctx->sync_generation; s_ctx->retiring_sync_handle = old_handle; - s_ctx->retiring_sync_generation = old_generation; s_ctx->retiring_local_terminate = true; s_ctx->current_sync_handle = BLE_HS_CONN_HANDLE_NONE; s_ctx->past_pending = rearm_past; @@ -130,8 +120,8 @@ static esp_err_t retire_current_sync(bool rearm_past) return ESP_FAIL; } - ESP_LOGI(TAG, "Retired sync handle=%u gen=%" PRIu32 " rearm_past=%d", - old_handle, old_generation, rearm_past); + ESP_LOGI(TAG, "Retired sync handle=%u rearm_past=%d", + old_handle, rearm_past); return ESP_OK; } @@ -155,9 +145,7 @@ static void adopt_past_sync(uint16_t sync_handle) } uint16_t old_handle = s_ctx->current_sync_handle; - uint32_t old_generation = s_ctx->sync_generation; s_ctx->retiring_sync_handle = old_handle; - s_ctx->retiring_sync_generation = old_generation; s_ctx->retiring_local_terminate = true; s_ctx->current_sync_handle = BLE_HS_CONN_HANDLE_NONE; s_ctx->past_pending = false; @@ -176,7 +164,7 @@ static void adopt_past_sync(uint16_t sync_handle) } if (s_ctx->current_sync_handle == sync_handle) { - /* Same handle reported again — keep generation. */ + /* Same handle reported again. */ return; } @@ -455,7 +443,7 @@ void esl_notify_update_complete(void) case BLE_ESL_STATE_CONFIGURING: /* First provisioning also requires all mandatory configuration writes. */ if (s_ctx->past_received && - (s_ctx->config_complete & CONFIG_COMPLETE_MASK) == CONFIG_COMPLETE_MASK) { + (s_ctx->config_complete & ESL_CONFIG_COMPLETE_MASK) == ESL_CONFIG_COMPLETE_MASK) { esl_state_transition(BLE_ESL_STATE_SYNCHRONIZED); } else { ESP_LOGI(TAG, "Update Complete received in Configuring — waiting for PAST / config"); @@ -748,7 +736,7 @@ static void handle_gap_disconnect(struct ble_gap_event *event) switch (s_ctx->state) { case BLE_ESL_STATE_CONFIGURING: - if ((s_ctx->config_complete & CONFIG_COMPLETE_MASK) == CONFIG_COMPLETE_MASK) { + if ((s_ctx->config_complete & ESL_CONFIG_COMPLETE_MASK) == ESL_CONFIG_COMPLETE_MASK) { /* Configuration complete — go to Unsynchronized */ esl_state_transition(BLE_ESL_STATE_UNSYNCHRONIZED); } else { @@ -977,7 +965,7 @@ static void handle_gap_periodic_transfer(struct ble_gap_event *event) * advance the state machine before provisioning finishes. */ s_ctx->past_received = true; if (s_ctx->update_complete_received && - (s_ctx->config_complete & CONFIG_COMPLETE_MASK) == CONFIG_COMPLETE_MASK) { + (s_ctx->config_complete & ESL_CONFIG_COMPLETE_MASK) == ESL_CONFIG_COMPLETE_MASK) { esl_state_transition(BLE_ESL_STATE_SYNCHRONIZED); } else { ESP_LOGI(TAG, "PAST received in Configuring — waiting for Update Complete / config"); @@ -1118,9 +1106,7 @@ static int esl_gap_event_handler(struct ble_gap_event *event, void *arg) uint16_t lost_handle = event->periodic_sync_lost.sync_handle; esl_sync_lost_ctx_t lost_ctx = { .current_sync_handle = s_ctx->current_sync_handle, - .sync_generation = s_ctx->sync_generation, .retiring_sync_handle = s_ctx->retiring_sync_handle, - .retiring_sync_generation = s_ctx->retiring_sync_generation, .retiring_local_terminate = s_ctx->retiring_local_terminate, }; esl_sync_lost_class_t kind = esl_classify_sync_lost(&lost_ctx, lost_handle); @@ -1711,9 +1697,7 @@ esp_err_t ble_esl_restore_persisted_tag(const ble_esl_persisted_tag_t *info) s_ctx->pawr_synced = false; s_ctx->update_complete_received = false; s_ctx->current_sync_handle = BLE_HS_CONN_HANDLE_NONE; - s_ctx->sync_generation = 0; s_ctx->retiring_sync_handle = BLE_HS_CONN_HANDLE_NONE; - s_ctx->retiring_sync_generation = 0; s_ctx->retiring_local_terminate = false; s_ctx->state = BLE_ESL_STATE_UNSYNCHRONIZED; diff --git a/components/bt/ble_profiles/nimble/ble_esl/src/esl/esl_sync_lost.h b/components/bt/ble_profiles/nimble/ble_esl/src/esl/esl_sync_lost.h index 1beb6c6f65a..1df68ff7d19 100644 --- a/components/bt/ble_profiles/nimble/ble_esl/src/esl/esl_sync_lost.h +++ b/components/bt/ble_profiles/nimble/ble_esl/src/esl/esl_sync_lost.h @@ -4,6 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 * * Pure classification helpers for PERIODIC_SYNC_LOST (host-testable). + * + * SYNC_LOST carries only a handle. Handle reuse cannot be detected here, so + * classification uses current vs retiring handles plus the local-terminate + * flag — not a generation counter. */ #pragma once @@ -27,29 +31,10 @@ typedef enum { typedef struct { uint16_t current_sync_handle; - uint32_t sync_generation; uint16_t retiring_sync_handle; - uint32_t retiring_sync_generation; bool retiring_local_terminate; } esl_sync_lost_ctx_t; -static inline uint32_t esl_sync_lost_generation_hint(const esl_sync_lost_ctx_t *ctx, - uint16_t evt_sync_handle) -{ - if (ctx == NULL) { - return 0; - } - if (evt_sync_handle == ctx->current_sync_handle && - ctx->current_sync_handle != ESL_SYNC_HANDLE_NONE) { - return ctx->sync_generation; - } - if (evt_sync_handle == ctx->retiring_sync_handle && - ctx->retiring_sync_handle != ESL_SYNC_HANDLE_NONE) { - return ctx->retiring_sync_generation; - } - return 0; -} - static inline esl_sync_lost_class_t esl_classify_sync_lost(const esl_sync_lost_ctx_t *ctx, uint16_t evt_sync_handle) { @@ -65,9 +50,7 @@ static inline esl_sync_lost_class_t esl_classify_sync_lost(const esl_sync_lost_c if (evt_sync_handle == ctx->current_sync_handle && ctx->current_sync_handle != ESL_SYNC_HANDLE_NONE) { - if (esl_sync_lost_generation_hint(ctx, evt_sync_handle) == ctx->sync_generation) { - return ESL_SYNC_LOST_CURRENT_NATURAL; - } + return ESL_SYNC_LOST_CURRENT_NATURAL; } return ESL_SYNC_LOST_STALE;