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

fix(ble/bluedroid): allow osi_event re-post during POSTING window (5.3)

See merge request espressif/esp-idf!52041
This commit is contained in:
Jiang Jiang Jian
2026-08-31 10:46:08 +08:00
4 changed files with 52 additions and 10 deletions

View File

@@ -534,13 +534,30 @@ static bool osi_event_can_bind_locked(const struct osi_event *event, osi_thread_
static bool osi_event_can_post_locked(const struct osi_event *event) static bool osi_event_can_post_locked(const struct osi_event *event)
{ {
if (event->thread == NULL || event->queue_idx >= event->thread->work_queue_num) { if (event->thread == NULL || event->queue_idx >= event->thread->work_queue_num) {
OSI_TRACE_EVENT("%s deny ev=%p flags=0x%x qidx=%u",
__func__, event, event ? event->flags : 0,
event ? event->queue_idx : 0);
return false; return false;
} }
return !OSI_EVENT_HAS_FLAG(event, OSI_EVENT_FLAG_DELETING) && if (OSI_EVENT_HAS_FLAG(event, OSI_EVENT_FLAG_DELETING) ||
event->item.func != NULL && event->item.func == NULL ||
!OSI_EVENT_HAS_FLAG(event, OSI_EVENT_FLAG_QUEUED) && OSI_EVENT_HAS_FLAG(event, OSI_EVENT_FLAG_QUEUED)) {
!OSI_EVENT_HAS_FLAG(event, OSI_EVENT_FLAG_POSTING); OSI_TRACE_EVENT("%s deny ev=%p flags=0x%x qidx=%u wq_len=%d",
__func__, event, event->flags, event->queue_idx,
osi_thread_queue_wait_size(event->thread, event->queue_idx));
return false;
}
/* Do NOT gate on OSI_EVENT_FLAG_POSTING here. POSTING marks the window in
* osi_thread_post_event() between osi_thread_post() (enqueue) and the
* poster clearing the flag. During that window the generic event handler
* may already have run and cleared QUEUED. A concurrent post that arrives
* after QUEUED is cleared is a legitimate re-post (new work arrived while
* the handler was draining) and must be accepted; rejecting it causes a
* lost wakeup. QUEUED alone prevents genuine double-queueing. POSTING is
* retained only for osi_event_is_idle()/osi_event_should_free(). */
return true;
} }
static bool osi_event_is_alive_locked(const struct osi_event *event) static bool osi_event_is_alive_locked(const struct osi_event *event)
@@ -714,6 +731,7 @@ static void osi_thread_generic_event_handler(void *context)
OSI_EVENT_SET_FLAG(event, OSI_EVENT_FLAG_RUNNING); OSI_EVENT_SET_FLAG(event, OSI_EVENT_FLAG_RUNNING);
func = event->item.func; func = event->item.func;
func_context = event->item.context; func_context = event->item.context;
OSI_TRACE_DEBUG("%s enter ev=%p flags=0x%x", __func__, event, event->flags);
osi_mutex_unlock(&event->lock); osi_mutex_unlock(&event->lock);
if (func != NULL) { if (func != NULL) {
@@ -722,6 +740,7 @@ static void osi_thread_generic_event_handler(void *context)
osi_mutex_lock(&event->lock, OSI_MUTEX_MAX_TIMEOUT); osi_mutex_lock(&event->lock, OSI_MUTEX_MAX_TIMEOUT);
OSI_EVENT_CLEAR_FLAG(event, OSI_EVENT_FLAG_RUNNING); OSI_EVENT_CLEAR_FLAG(event, OSI_EVENT_FLAG_RUNNING);
OSI_TRACE_DEBUG("%s exit ev=%p flags=0x%x", __func__, event, event->flags);
osi_mutex_unlock(&event->lock); osi_mutex_unlock(&event->lock);
osi_event_release(event); osi_event_release(event);
@@ -755,6 +774,7 @@ bool osi_thread_post_event(struct osi_event *event, uint32_t timeout)
uint8_t queue_idx = 0; uint8_t queue_idx = 0;
if (!osi_event_acquire(event)) { if (!osi_event_acquire(event)) {
OSI_TRACE_EVENT("%s acquire fail ev=%p", __func__, event);
return false; return false;
} }
@@ -782,6 +802,9 @@ bool osi_thread_post_event(struct osi_event *event, uint32_t timeout)
osi_mutex_unlock(&event->lock); osi_mutex_unlock(&event->lock);
if (!ret) { if (!ret) {
OSI_TRACE_EVENT("%s enqueue fail ev=%p qidx=%u wq_len=%d",
__func__, event, queue_idx,
osi_thread_queue_wait_size(thread, queue_idx));
osi_event_release(event); osi_event_release(event);
} }
osi_event_release(event); osi_event_release(event);

View File

@@ -375,8 +375,8 @@ typedef enum {
ESP_GATT_AUTH_REQ_NONE = 0, /*!< No authentication required. Corresponds to BTA_GATT_AUTH_REQ_NONE. */ ESP_GATT_AUTH_REQ_NONE = 0, /*!< No authentication required. Corresponds to BTA_GATT_AUTH_REQ_NONE. */
ESP_GATT_AUTH_REQ_NO_MITM = 1, /*!< Unauthenticated encryption. Corresponds to BTA_GATT_AUTH_REQ_NO_MITM. */ ESP_GATT_AUTH_REQ_NO_MITM = 1, /*!< Unauthenticated encryption. Corresponds to BTA_GATT_AUTH_REQ_NO_MITM. */
ESP_GATT_AUTH_REQ_MITM = 2, /*!< Authenticated encryption (MITM protection). Corresponds to BTA_GATT_AUTH_REQ_MITM. */ ESP_GATT_AUTH_REQ_MITM = 2, /*!< Authenticated encryption (MITM protection). Corresponds to BTA_GATT_AUTH_REQ_MITM. */
ESP_GATT_AUTH_REQ_SIGNED_NO_MITM = 3, /*!< Signed data, no MITM protection. Corresponds to BTA_GATT_AUTH_REQ_SIGNED_NO_MITM. */ ESP_GATT_AUTH_REQ_SIGNED_NO_MITM = 3, /*!< CSRK signed write, no MITM. Use with `ESP_GATT_WRITE_TYPE_NO_RSP` on a bonded, unencrypted link. */
ESP_GATT_AUTH_REQ_SIGNED_MITM = 4, /*!< Signed data with MITM protection. Corresponds to BTA_GATT_AUTH_REQ_SIGNED_MITM. */ ESP_GATT_AUTH_REQ_SIGNED_MITM = 4, /*!< CSRK signed write with MITM. Use with `ESP_GATT_WRITE_TYPE_NO_RSP` on a bonded, unencrypted link. */
} esp_gatt_auth_req_t; } esp_gatt_auth_req_t;
@@ -410,10 +410,10 @@ typedef enum {
/** @brief Permission to write to the attribute with encrypted MITM protection. Corresponds to BTA_GATT_PERM_WRITE_ENC_MITM. */ /** @brief Permission to write to the attribute with encrypted MITM protection. Corresponds to BTA_GATT_PERM_WRITE_ENC_MITM. */
#define ESP_GATT_PERM_WRITE_ENC_MITM (1 << 6) #define ESP_GATT_PERM_WRITE_ENC_MITM (1 << 6)
/** @brief Permission for signed writes to the attribute. Corresponds to BTA_GATT_PERM_WRITE_SIGNED. */ /** @brief Signed write without link encryption (CSRK). Requires `ESP_GATT_CHAR_PROP_BIT_AUTH`. Corresponds to BTA_GATT_PERM_WRITE_SIGNED. */
#define ESP_GATT_PERM_WRITE_SIGNED (1 << 7) #define ESP_GATT_PERM_WRITE_SIGNED (1 << 7)
/** @brief Permission for signed writes to the attribute with MITM protection. Corresponds to BTA_GATT_PERM_WRITE_SIGNED_MITM. */ /** @brief Signed write with MITM-protected CSRK. Requires `ESP_GATT_CHAR_PROP_BIT_AUTH`. Corresponds to BTA_GATT_PERM_WRITE_SIGNED_MITM. */
#define ESP_GATT_PERM_WRITE_SIGNED_MITM (1 << 8) #define ESP_GATT_PERM_WRITE_SIGNED_MITM (1 << 8)
/** @brief Permission to read the attribute with authorization. */ /** @brief Permission to read the attribute with authorization. */
@@ -463,7 +463,7 @@ typedef uint16_t esp_gatt_perm_t; ///< Type to represent GATT attribute permissi
/** @brief Ability to indicate.Corresponds to BTA_GATT_CHAR_PROP_BIT_INDICATE. */ /** @brief Ability to indicate.Corresponds to BTA_GATT_CHAR_PROP_BIT_INDICATE. */
#define ESP_GATT_CHAR_PROP_BIT_INDICATE (1 << 5) #define ESP_GATT_CHAR_PROP_BIT_INDICATE (1 << 5)
/** @brief Ability to authenticate.Corresponds to BTA_GATT_CHAR_PROP_BIT_AUTH. */ /** @brief Authenticated Signed Writes (ATT Signed Write Command, 0xD2). Requires matching `ESP_GATT_PERM_WRITE_SIGNED`. Corresponds to BTA_GATT_CHAR_PROP_BIT_AUTH. */
#define ESP_GATT_CHAR_PROP_BIT_AUTH (1 << 6) #define ESP_GATT_CHAR_PROP_BIT_AUTH (1 << 6)
/** @brief Has extended properties.Corresponds to BTA_GATT_CHAR_PROP_BIT_EXT_PROP. */ /** @brief Has extended properties.Corresponds to BTA_GATT_CHAR_PROP_BIT_EXT_PROP. */

View File

@@ -915,6 +915,8 @@ esp_err_t esp_ble_gattc_read_char_descr (esp_gatt_if_t gattc_if,
* 3. `handle` must be greater than 0. * 3. `handle` must be greater than 0.
* 4. If `auth_req` is not `ESP_GATT_AUTH_REQ_NONE`, the stack may start encryption * 4. If `auth_req` is not `ESP_GATT_AUTH_REQ_NONE`, the stack may start encryption
* or SMP pairing before sending the ATT write. * or SMP pairing before sending the ATT write.
* 5. `ESP_GATT_AUTH_REQ_SIGNED_*` with `ESP_GATT_WRITE_TYPE_NO_RSP` sends ATT Signed
* Write Command when bonded (CSRK) and the link is not encrypted.
* *
* @return * @return
* - ESP_OK: Success * - ESP_OK: Success

View File

@@ -155,11 +155,21 @@ void hci_shut_down(void)
bool hci_downstream_data_post(uint32_t timeout) bool hci_downstream_data_post(uint32_t timeout)
{ {
bool ret;
if (hci_host_env.downstream_data_ready == NULL) { if (hci_host_env.downstream_data_ready == NULL) {
HCI_TRACE_WARNING("%s downstream_data_ready event not created", __func__); HCI_TRACE_WARNING("%s downstream_data_ready event not created", __func__);
return false; return false;
} }
return osi_thread_post_event(hci_host_env.downstream_data_ready, timeout);
ret = osi_thread_post_event(hci_host_env.downstream_data_ready, timeout);
if (!ret) {
HCI_TRACE_DEBUG("%s post fail credits=%d cmdq=%u pktq=%u",
__func__, hci_host_env.command_credits,
(unsigned)fixed_pkt_queue_length(hci_host_env.command_queue),
(unsigned)fixed_queue_length(hci_host_env.packet_queue));
}
return ret;
} }
static int hci_layer_init_env(void) static int hci_layer_init_env(void)
@@ -249,6 +259,8 @@ static void hci_downstream_data_handler(void *arg)
* All packets will be directly copied to single queue in driver layer with * All packets will be directly copied to single queue in driver layer with
* H4 type header added (1 byte). * H4 type header added (1 byte).
*/ */
UNUSED(arg);
while (hci_host_check_send_available()) { while (hci_host_check_send_available()) {
/*Now Target only allowed one packet per TX*/ /*Now Target only allowed one packet per TX*/
BT_HDR *pkt = packet_fragmenter->fragment_current_packet(); BT_HDR *pkt = packet_fragmenter->fragment_current_packet();
@@ -264,6 +276,11 @@ static void hci_downstream_data_handler(void *arg)
break; break;
} }
} }
HCI_TRACE_DEBUG("%s done credits=%d cmdq=%u pktq=%u",
__func__, hci_host_env.command_credits,
(unsigned)fixed_pkt_queue_length(hci_host_env.command_queue),
(unsigned)fixed_queue_length(hci_host_env.packet_queue));
} }
static void transmit_command( static void transmit_command(