diff mbox series

[v3,5/6] Bluetooth: Unlink CISes when LE disconnects in hci_conn_del

Message ID 20230502145737.140856-6-lrh2000@pku.edu.cn (mailing list archive)
State Superseded
Headers show
Series Bluetooth: Fix potential double free caused by hci_conn_unlink | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
tedd_an/CheckPatch success CheckPatch PASS
tedd_an/GitLint fail WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search 13: B3 Line contains hard tab characters (\t): " All SCO, eSCO, and CIS connections on a physical link should be" 14: B3 Line contains hard tab characters (\t): " disconnected before the ACL connection on the same physical" 15: B3 Line contains hard tab characters (\t): " connection is disconnected. If it does not, they will be" 16: B3 Line contains hard tab characters (\t): " implicitly disconnected as part of the ACL disconnection." 17: B3 Line contains hard tab characters (\t): " ..." 18: B3 Line contains hard tab characters (\t): " Note: As specified in Section 7.7.5, on the Central, the handle" 19: B3 Line contains hard tab characters (\t): " for a CIS remains valid even after disconnection and, therefore," 20: B3 Line contains hard tab characters (\t): " the Host can recreate a disconnected CIS at a later point in" 21: B3 Line contains hard tab characters (\t): " time using the same connection handle."
tedd_an/SubjectPrefix success Gitlint PASS
tedd_an/IncrementalBuild success Incremental Build PASS

Commit Message

Ruihan Li May 2, 2023, 2:57 p.m. UTC
Currently, hci_conn_del calls hci_conn_unlink for BR/EDR, (e)SCO, and
CIS connections, i.e., everything except LE connections. However, if
(e)SCO connections are unlinked when BR/EDR disconnects, CIS connections
should also be unlinked when LE disconnects.

In terms of disconnection behavior, CIS and (e)SCO connections are not
too different. One peculiarity of CIS is that when CIS connections are
disconnected, the CIS handle isn't deleted, as per [BLUETOOTH CORE
SPECIFICATION Version 5.4 | Vol 4, Part E] 7.1.6 Disconnect command:

	All SCO, eSCO, and CIS connections on a physical link should be
	disconnected before the ACL connection on the same physical
	connection is disconnected. If it does not, they will be
	implicitly disconnected as part of the ACL disconnection.
	...
	Note: As specified in Section 7.7.5, on the Central, the handle
	for a CIS remains valid even after disconnection and, therefore,
	the Host can recreate a disconnected CIS at a later point in
	time using the same connection handle.

This peculiarity has nothing to do with the code, as long as the current
implementation always ties the CIS handle, the CIS connection, and the
LE connection together in hci_link, and manually performs CIS deletion
in cis_cleanup after CIS disconnections.

Signed-off-by: Ruihan Li <lrh2000@pku.edu.cn>
---
 net/bluetooth/hci_conn.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)
diff mbox series

Patch

diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index e76ebb50d..de553e062 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1092,7 +1092,9 @@  static void hci_conn_unlink(struct hci_conn *conn)
 			 * yet at this point. Delete it now, otherwise it is
 			 * possible for it to be stuck and can't be deleted.
 			 */
-			if (child->handle == HCI_CONN_HANDLE_UNSET)
+			if ((child->type == SCO_LINK ||
+			     child->type == ESCO_LINK) &&
+			    child->handle == HCI_CONN_HANDLE_UNSET)
 				hci_conn_del(child);
 		}
 
@@ -1119,11 +1121,17 @@  void hci_conn_del(struct hci_conn *conn)
 
 	BT_DBG("%s hcon %p handle %d", hdev->name, conn, conn->handle);
 
+	hci_conn_unlink(conn);
+
+	/* hci_conn_unlink may trigger additional disc_work, so
+	 * ensure to perform cancelling after that.
+	 */
+	cancel_delayed_work_sync(&conn->disc_work);
+
 	cancel_delayed_work_sync(&conn->auto_accept_work);
 	cancel_delayed_work_sync(&conn->idle_work);
 
 	if (conn->type == ACL_LINK) {
-		hci_conn_unlink(conn);
 		/* Unacked frames */
 		hdev->acl_cnt += conn->sent;
 	} else if (conn->type == LE_LINK) {
@@ -1134,8 +1142,6 @@  void hci_conn_del(struct hci_conn *conn)
 		else
 			hdev->acl_cnt += conn->sent;
 	} else {
-		hci_conn_unlink(conn);
-
 		/* Unacked ISO frames */
 		if (conn->type == ISO_LINK) {
 			if (hdev->iso_pkts)
@@ -1147,11 +1153,6 @@  void hci_conn_del(struct hci_conn *conn)
 		}
 	}
 
-	/* hci_conn_unlink may trigger additional disc_work, so
-	 * ensure to perform cancelling after that.
-	 */
-	cancel_delayed_work_sync(&conn->disc_work);
-
 	if (conn->amp_mgr)
 		amp_mgr_put(conn->amp_mgr);