2023-05-02 15:06:43

by Ruihan Li

[permalink] [raw]
Subject: [PATCH v3 5/6] Bluetooth: Unlink CISes when LE disconnects in hci_conn_del

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 <[email protected]>
---
net/bluetooth/hci_conn.c | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)

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);

--
2.40.0