From: Hitalo Souza <enghitalo@gmail.com>
To: linux-bluetooth@vger.kernel.org
Cc: marcel@holtmann.org, luiz.dentz@gmail.com,
linux-kernel@vger.kernel.org, Hitalo Souza <enghitalo@gmail.com>
Subject: [PATCH v2 3/6] Bluetooth: hci_event: Disconnect links that complete while being aborted
Date: Thu, 8 Oct 2026 11:12:35 -0400 [thread overview]
Message-ID: <20261008151238.2138665-4-enghitalo@gmail.com> (raw)
In-Reply-To: <20261008151238.2138665-1-enghitalo@gmail.com>
Since commit 16e3b6429159 ("Bluetooth: hci_conn: Fix modifying handle
while aborting"), and for LE since commit 181a42edddf5 ("Bluetooth: Make
handle of hci_conn be unique"), a connection that is being aborted
refuses the handle of its link when the link completes before the
connection is deleted, e.g. while the abort waits for its cancel
command. The link is up in the controller, though, and nothing
disconnects it: the event handler fails the connection or leaves it to
the abort, and the abort cancels the connect attempt and finds no handle
to disconnect. The handle then stays in use in the controller, e.g. a
SCO link left this way makes the controller reject every later setup
for the device until the ACL drops.
Disconnect the link when its connection refuses the handle, on
Connection Complete, Synchronous Connection Complete and LE (Enhanced)
Connection Complete, with the reason the connection was aborted for.
This is not done in hci_conn_set_handle() itself, as its other callers
set the handles of links that are not up yet.
Fixes: 16e3b6429159 ("Bluetooth: hci_conn: Fix modifying handle while aborting")
Fixes: 181a42edddf5 ("Bluetooth: Make handle of hci_conn be unique")
Assisted-by: LLM
Signed-off-by: Hitalo Souza <enghitalo@gmail.com>
---
net/bluetooth/hci_event.c | 41 ++++++++++++++++++++++++++++++++++++---
1 file changed, 38 insertions(+), 3 deletions(-)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index cbe53e19e..1f9b47389 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3217,6 +3217,39 @@ static int hci_read_enc_key_size(struct hci_dev *hdev, struct hci_conn *conn)
return hci_send_cmd(hdev, HCI_OP_READ_ENC_KEY_SIZE, sizeof(cp), &cp);
}
+/* Disconnects a link that came up in the controller but that no connection
+ * takes: nothing else would, and its handle would stay in use there.
+ */
+static void hci_disconnect_unused(struct hci_dev *hdev, u16 handle, u8 reason)
+{
+ struct hci_cp_disconnect cp;
+
+ /* Never for an invalid handle or one that a connection uses */
+ if (handle > HCI_CONN_HANDLE_MAX ||
+ hci_conn_hash_lookup_handle(hdev, handle))
+ return;
+
+ bt_dev_dbg(hdev, "handle 0x%4.4x reason 0x%2.2x", handle, reason);
+
+ cp.handle = cpu_to_le16(handle);
+ cp.reason = reason;
+ hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
+}
+
+/* Sets the handle of a connection whose link came up. A connection that is
+ * being aborted refuses it, so its link is disconnected: the abort only
+ * cancels the connect attempt, and finds no handle to disconnect.
+ */
+static u8 hci_conn_complete_set_handle(struct hci_conn *conn, u16 handle)
+{
+ u8 status = hci_conn_set_handle(conn, handle);
+
+ if (status && conn->abort_reason)
+ hci_disconnect_unused(conn->hdev, handle, conn->abort_reason);
+
+ return status;
+}
+
static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
@@ -3292,7 +3325,8 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
}
if (!status) {
- status = hci_conn_set_handle(conn, __le16_to_cpu(ev->handle));
+ status = hci_conn_complete_set_handle(conn,
+ __le16_to_cpu(ev->handle));
if (status)
goto done;
@@ -5208,7 +5242,8 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, void *data,
switch (status) {
case 0x00:
- status = hci_conn_set_handle(conn, __le16_to_cpu(ev->handle));
+ status = hci_conn_complete_set_handle(conn,
+ __le16_to_cpu(ev->handle));
if (status) {
conn->state = BT_CLOSED;
break;
@@ -5974,7 +6009,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
* hci_conn_failed function which is triggered by the HCI
* request completion callbacks used for connecting.
*/
- if (status || hci_conn_set_handle(conn, handle))
+ if (status || hci_conn_complete_set_handle(conn, handle))
goto unlock;
/* Drop the connection if it has been aborted */
--
2.55.0
next prev parent reply other threads:[~2026-10-08 15:12 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-08 15:12 [PATCH v2 0/6] Bluetooth: Fix SCO setup failures after an abandoned setup Hitalo Souza
2026-10-08 15:12 ` [PATCH v2 1/6] Bluetooth: hci_event: Don't fail a connected SCO link on setup errors Hitalo Souza
2026-10-08 15:12 ` [PATCH v2 2/6] Bluetooth: hci_conn: Don't set up a SCO link that is already up Hitalo Souza
2026-10-08 15:12 ` Hitalo Souza [this message]
2026-10-08 15:12 ` [PATCH v2 4/6] Bluetooth: Don't leave abandoned SCO links up in the controller Hitalo Souza
2026-10-08 15:12 ` [PATCH v2 5/6] Bluetooth: hci_event: Disconnect an ACL link that completes after its abort Hitalo Souza
2026-10-08 15:12 ` [PATCH v2 6/6] Bluetooth: hci_event: Notify the driver only of SCO links that came up Hitalo Souza
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261008151238.2138665-4-enghitalo@gmail.com \
--to=enghitalo@gmail.com \
--cc=linux-bluetooth@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luiz.dentz@gmail.com \
--cc=marcel@holtmann.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®