Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PW_SID:918106] [v1] Bluetooth: hci_sync: Fix disconnect complete event timeout issue #2622

Open
wants to merge 1 commit into
base: workflow
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,8 @@ struct hci_conn {

struct bt_codec codec;

struct completion disc_ev_comp;

void (*connect_cfm_cb) (struct hci_conn *conn, u8 status);
void (*security_cfm_cb) (struct hci_conn *conn, u8 status);
void (*disconn_cfm_cb) (struct hci_conn *conn, u8 reason);
Expand Down
9 changes: 9 additions & 0 deletions net/bluetooth/hci_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,15 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t

hci_conn_init_sysfs(conn);

/* This disc_ev_comp is inited when we send a disconnect request to
* the remote device but fail to receive the disconnect complete
* event within the expected time (2 seconds). This occurs because
* the remote device doesn't ack the terminate indication, forcing
* the controller to wait for the supervision timeout.
*/
init_completion(&conn->disc_ev_comp);
complete(&conn->disc_ev_comp);

return conn;
}

Expand Down
9 changes: 9 additions & 0 deletions net/bluetooth/hci_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -3368,6 +3368,15 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, void *data,
if (!conn)
goto unlock;

/* Wake up disc_ev_comp here is ok. Since we hold the hdev lock
* hci_abort_conn_sync will wait hdev lock release to continue.
*/
if (!completion_done(&conn->disc_ev_comp)) {
complete(&conn->disc_ev_comp);
/* Add some delay for hci_abort_conn_sync to handle the complete */
usleep_range(100, 1000);
}

if (ev->status) {
mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
conn->dst_type, ev->status);
Expand Down
18 changes: 18 additions & 0 deletions net/bluetooth/hci_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -5590,6 +5590,24 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason)
break;
}

/* Check whether the connection is successfully disconnected.
* Sometimes the remote device doesn't acknowledge the
* LL_TERMINATE_IND in time, requiring the controller to wait
* for the supervision timeout, which may exceed 2 seconds. In
* this case, we need to wait for the HCI_EV_DISCONN_COMPLETE
* event before cleaning up the connection.
*/
if (err == -ETIMEDOUT) {
u32 idle_delay = msecs_to_jiffies(10 * conn->le_supv_timeout);

reinit_completion(&conn->disc_ev_comp);
if (!wait_for_completion_timeout(&conn->disc_ev_comp, idle_delay)) {
bt_dev_warn(hdev, "Failed to get complete");
mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
conn->dst_type, conn->abort_reason);
}
}

hci_dev_lock(hdev);

/* Check if the connection has been cleaned up concurrently */
Expand Down
Loading