From 8f1e4397920da4849771666ab71b474d9f1648b7 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 10 Aug 2026 12:56:16 -0500 Subject: [PATCH] [bluetooth_proxy] Finish the connection scan before reserving a slot (#18239) --- .../bluetooth_proxy/bluetooth_proxy.cpp | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp index 0a16567549..af52a25ec0 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp @@ -198,6 +198,10 @@ void BluetoothProxy::reset_connection_slot_(BluetoothConnection *connection, con } BluetoothConnection *BluetoothProxy::get_connection_(uint64_t address, bool reserve) { + // Finish the scan before reserving: a free slot earlier in the array must + // not win over a later slot that already holds the address, or one device + // ends up on two slots with a second connection attempt racing the first. + BluetoothConnection *free_slot = nullptr; for (uint8_t i = 0; i < this->connection_count_; i++) { auto *connection = this->connections_[i]; uint64_t conn_addr = connection->get_address(); @@ -205,18 +209,19 @@ BluetoothConnection *BluetoothProxy::get_connection_(uint64_t address, bool rese if (conn_addr == address) return connection; - if (reserve && conn_addr == 0) { - connection->send_service_ = INIT_SENDING_SERVICES; - connection->set_address(address); - // All connections must start at INIT - // We only set the state if we allocate the connection - // to avoid a race where multiple connection attempts - // are made. - connection->set_state(ClientState::INIT); - return connection; - } + if (free_slot == nullptr && conn_addr == 0) + free_slot = connection; } - return nullptr; + if (!reserve || free_slot == nullptr) + return nullptr; + free_slot->send_service_ = INIT_SENDING_SERVICES; + free_slot->set_address(address); + // All connections must start at INIT + // We only set the state if we allocate the connection + // to avoid a race where multiple connection attempts + // are made. + free_slot->set_state(ClientState::INIT); + return free_slot; } void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest &msg) {