diff --git a/components/bt/common/osi/thread.c b/components/bt/common/osi/thread.c index ec409c634d1..cd8294b7832 100644 --- a/components/bt/common/osi/thread.c +++ b/components/bt/common/osi/thread.c @@ -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) { 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 !OSI_EVENT_HAS_FLAG(event, OSI_EVENT_FLAG_DELETING) && - event->item.func != NULL && - !OSI_EVENT_HAS_FLAG(event, OSI_EVENT_FLAG_QUEUED) && - !OSI_EVENT_HAS_FLAG(event, OSI_EVENT_FLAG_POSTING); + if (OSI_EVENT_HAS_FLAG(event, OSI_EVENT_FLAG_DELETING) || + event->item.func == NULL || + OSI_EVENT_HAS_FLAG(event, OSI_EVENT_FLAG_QUEUED)) { + 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) @@ -714,6 +731,7 @@ static void osi_thread_generic_event_handler(void *context) OSI_EVENT_SET_FLAG(event, OSI_EVENT_FLAG_RUNNING); func = event->item.func; func_context = event->item.context; + OSI_TRACE_DEBUG("%s enter ev=%p flags=0x%x", __func__, event, event->flags); osi_mutex_unlock(&event->lock); 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_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_event_release(event); @@ -755,6 +774,7 @@ bool osi_thread_post_event(struct osi_event *event, uint32_t timeout) uint8_t queue_idx = 0; if (!osi_event_acquire(event)) { + OSI_TRACE_EVENT("%s acquire fail ev=%p", __func__, event); return false; } @@ -782,6 +802,9 @@ bool osi_thread_post_event(struct osi_event *event, uint32_t timeout) osi_mutex_unlock(&event->lock); 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); diff --git a/components/bt/host/bluedroid/api/include/api/esp_gatt_defs.h b/components/bt/host/bluedroid/api/include/api/esp_gatt_defs.h index 57736c29076..4b34bda61f3 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_gatt_defs.h +++ b/components/bt/host/bluedroid/api/include/api/esp_gatt_defs.h @@ -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_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_SIGNED_NO_MITM = 3, /*!< Signed data, no MITM protection. Corresponds to BTA_GATT_AUTH_REQ_SIGNED_NO_MITM. */ - 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_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, /*!< CSRK signed write with MITM. Use with `ESP_GATT_WRITE_TYPE_NO_RSP` on a bonded, unencrypted link. */ } 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. */ #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) -/** @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) /** @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. */ #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) /** @brief Has extended properties.Corresponds to BTA_GATT_CHAR_PROP_BIT_EXT_PROP. */ diff --git a/components/bt/host/bluedroid/api/include/api/esp_gattc_api.h b/components/bt/host/bluedroid/api/include/api/esp_gattc_api.h index 086cf211688..03d575f5fbf 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_gattc_api.h +++ b/components/bt/host/bluedroid/api/include/api/esp_gattc_api.h @@ -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. * 4. If `auth_req` is not `ESP_GATT_AUTH_REQ_NONE`, the stack may start encryption * 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 * - ESP_OK: Success diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index cb6bf9b6a4d..5f908b2ea09 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -155,11 +155,21 @@ void hci_shut_down(void) bool hci_downstream_data_post(uint32_t timeout) { + bool ret; + if (hci_host_env.downstream_data_ready == NULL) { HCI_TRACE_WARNING("%s downstream_data_ready event not created", __func__); 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) @@ -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 * H4 type header added (1 byte). */ + UNUSED(arg); + while (hci_host_check_send_available()) { /*Now Target only allowed one packet per TX*/ BT_HDR *pkt = packet_fragmenter->fragment_current_packet(); @@ -264,6 +276,11 @@ static void hci_downstream_data_handler(void *arg) 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(