Skip to content

Commit a2904d2

Browse files
lrh2000Vudentz
authored andcommitted
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. Since hci_conn_link invokes both hci_conn_get and hci_conn_hold, hci_conn_unlink should perform both hci_conn_put and hci_conn_drop as well. However, currently it performs only hci_conn_put. This patch makes hci_conn_unlink call hci_conn_drop as well, which simplifies the logic in hci_conn_del a bit and may benefit future users of hci_conn_unlink. But it is noted that this change additionally implies that hci_conn_unlink can queue disc_work on conn itself, with the following call stack: hci_conn_unlink(conn) [conn->parent == NULL] -> hci_conn_unlink(child) [child->parent == conn] -> hci_conn_drop(child->parent) -> queue_delayed_work(&conn->disc_work) Queued disc_work after hci_conn_del can be spurious, so during the process of hci_conn_del, it is necessary to make the call to cancel_delayed_work(&conn->disc_work) after invoking hci_conn_unlink. Signed-off-by: Ruihan Li <[email protected]> Co-developed-by: Luiz Augusto von Dentz <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent a2ac591 commit a2904d2

File tree

1 file changed

+6
-15
lines changed

1 file changed

+6
-15
lines changed

net/bluetooth/hci_conn.c

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,7 +1100,9 @@ static void hci_conn_unlink(struct hci_conn *conn)
11001100
* yet at this point. Delete it now, otherwise it is
11011101
* possible for it to be stuck and can't be deleted.
11021102
*/
1103-
if (child->handle == HCI_CONN_HANDLE_UNSET)
1103+
if ((child->type == SCO_LINK ||
1104+
child->type == ESCO_LINK) &&
1105+
child->handle == HCI_CONN_HANDLE_UNSET)
11041106
hci_conn_del(child);
11051107
}
11061108

@@ -1113,6 +1115,7 @@ static void hci_conn_unlink(struct hci_conn *conn)
11131115
list_del_rcu(&conn->link->list);
11141116
synchronize_rcu();
11151117

1118+
hci_conn_drop(conn->parent);
11161119
hci_conn_put(conn->parent);
11171120
conn->parent = NULL;
11181121

@@ -1126,12 +1129,13 @@ void hci_conn_del(struct hci_conn *conn)
11261129

11271130
BT_DBG("%s hcon %p handle %d", hdev->name, conn, conn->handle);
11281131

1132+
hci_conn_unlink(conn);
1133+
11291134
cancel_delayed_work_sync(&conn->disc_work);
11301135
cancel_delayed_work_sync(&conn->auto_accept_work);
11311136
cancel_delayed_work_sync(&conn->idle_work);
11321137

11331138
if (conn->type == ACL_LINK) {
1134-
hci_conn_unlink(conn);
11351139
/* Unacked frames */
11361140
hdev->acl_cnt += conn->sent;
11371141
} else if (conn->type == LE_LINK) {
@@ -1142,13 +1146,6 @@ void hci_conn_del(struct hci_conn *conn)
11421146
else
11431147
hdev->acl_cnt += conn->sent;
11441148
} else {
1145-
struct hci_conn *acl = conn->parent;
1146-
1147-
if (acl) {
1148-
hci_conn_unlink(conn);
1149-
hci_conn_drop(acl);
1150-
}
1151-
11521149
/* Unacked ISO frames */
11531150
if (conn->type == ISO_LINK) {
11541151
if (hdev->iso_pkts)
@@ -2485,12 +2482,6 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
24852482
list)) != NULL) {
24862483
conn->state = BT_CLOSED;
24872484
hci_disconn_cfm(conn, HCI_ERROR_LOCAL_HOST_TERM);
2488-
2489-
/* Unlink before deleting otherwise it is possible that
2490-
* hci_conn_del removes the link which may cause the list to
2491-
* contain items already freed.
2492-
*/
2493-
hci_conn_unlink(conn);
24942485
hci_conn_del(conn);
24952486
}
24962487
}

0 commit comments

Comments
 (0)