Commit 089df601 authored by Sylvio Alves's avatar Sylvio Alves Committed by Benjamin Cabé
Browse files

bluetooth: esp32: fix VHCI semaphore misuse in HCI send path



The TX flow control semaphore was initialized with a count of 1 and
released again after every bt_esp32_send() call. This broke the VHCI
flow control contract and could allow sending more packets than the
controller advertised.

This prevents host/controller overruns and ensures proper synchronization
with the ESP32 VHCI interface.

Signed-off-by: default avatarSylvio Alves <sylvio.alves@espressif.com>
parent 71be3c28
Loading
Loading
Loading
Loading
+16 −10
Original line number Diff line number Diff line
@@ -25,7 +25,8 @@ struct bt_esp32_data {
	bt_hci_recv_t recv;
};

static K_SEM_DEFINE(hci_send_sem, 1, 1);
/* VHCI notifies when exactly one more HCI packet can be sent */
static K_SEM_DEFINE(hci_send_sem, 0, 1);

static bool is_hci_event_discardable(const uint8_t *evt_data)
{
@@ -64,7 +65,7 @@ static struct net_buf *bt_esp_evt_recv(uint8_t *data, size_t remaining)
		return NULL;
	}

	discardable = is_hci_event_discardable(data);
	discardable = is_hci_event_discardable(data, remaining);

	memcpy((void *)&hdr, data, sizeof(hdr));
	data += sizeof(hdr);
@@ -242,22 +243,21 @@ static int bt_esp32_send(const struct device *dev, struct net_buf *buf)

	LOG_HEXDUMP_DBG(buf->data, buf->len, "Final HCI buffer:");

	/* Wait for controller credit (callback gives the semaphore) */
	if (k_sem_take(&hci_send_sem, HCI_BT_ESP32_TIMEOUT) != 0) {
		LOG_ERR("Send packet timeout error");
		err = -ETIMEDOUT;
	} else {
		if (!esp_vhci_host_check_send_available()) {
		LOG_WRN("Controller not ready to receive packets");
			LOG_WRN("VHCI not available, sending anyway");
		}

	if (k_sem_take(&hci_send_sem, HCI_BT_ESP32_TIMEOUT) == 0) {
		esp_vhci_host_send_packet(buf->data, buf->len);
	} else {
		LOG_ERR("Send packet timeout error");
		err = -ETIMEDOUT;
	}

	if (!err) {
		net_buf_unref(buf);
	}

	k_sem_give(&hci_send_sem);

	return err;
}
@@ -291,6 +291,10 @@ static int bt_esp32_ble_init(void)

	esp_vhci_host_register_callback(&vhci_host_cb);

	if (esp_vhci_host_check_send_available()) {
		k_sem_give(&hci_send_sem);
	}

	return 0;
}

@@ -318,6 +322,8 @@ static int bt_esp32_open(const struct device *dev, bt_hci_recv_t recv)
	struct bt_esp32_data *hci = dev->data;
	int err;

	k_sem_reset(&hci_send_sem);

	err = bt_esp32_ble_init();
	if (err) {
		return err;