| From 3651c6b7e6c32e4ebea0e8ad19967d8afc915ea0 Mon Sep 17 00:00:00 2001 |
| From: Yun-Hao Chung <howardchung@google.com> |
| Date: Wed, 4 Oct 2023 10:09:36 +0000 |
| Subject: [PATCH] CHROMIUM: Bluetooth: Use addr instead of hci_conn in LE |
| Connection complete |
| |
| Connections may be cleanup while waiting for the commands to complete. |
| If this happens, it might be the reason we see crashes below which |
| indicates that the |conn->hdev| is NULL, which can be caused by freeing |
| the memory of the |hci_conn| earliar. |
| |
| This fixes the issue by passing the address data instead of the hci_conn |
| to the HCI command sync work so that we can check if such hci_conn |
| exists before accessing it. |
| |
| Call Trace: |
| ? __die_body+0x1f/0x63 |
| ? no_context+0x32f/0x506 |
| ? exc_page_fault+0x2d8/0x400 |
| ? __hci_cmd_sync_sk+0x464/0x4b7 [bluetooth (HASH:202e 2)] |
| ? asm_exc_page_fault+0x1e/0x30 |
| ? hci_connect_le_sync+0x49/0x49 [bluetooth (HASH:202e 2)] |
| ? hci_pend_le_action_lookup+0x12/0x68 [bluetooth (HASH:202e 2)] |
| hci_connect_le_scan_cleanup+0x82/0x252 [bluetooth (HASH:202e 2)] |
| create_le_conn_complete+0xc9/0xdb [bluetooth (HASH:202e 2)] |
| hci_cmd_sync_work+0x11a/0x15b [bluetooth (HASH:202e 2)] |
| process_one_work+0x18d/0x416 |
| worker_thread+0x11a/0x289 |
| kthread+0x13e/0x14f |
| ? process_one_work+0x416/0x416 |
| ? kthread_blkcg+0x31/0x31 |
| ret_from_fork+0x1f/0x30 |
| |
| UPSTREAM-TASK=b:303584676 |
| BUG=b:204408624 |
| TEST=run CUJ on hatch v5.15 with MX keys. |
| TEST=run bluetooth_AdapterLEHealth on hatch v5.15. |
| |
| Change-Id: Ieb313a0aa7140a8478b3e1e5c0d8c6ccc89d1b6e |
| Signed-off-by: Yun-Hao Chung <howardchung@google.com> |
| Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/4914662 |
| Reviewed-by: Archie Pusaka <apusaka@chromium.org> |
| Tested-by: Yun-Hao Chung <howardchung@chromium.org> |
| Commit-Queue: Yun-Hao Chung <howardchung@chromium.org> |
| --- |
| net/bluetooth/hci_conn.c | 51 ++++++++++++++++++++++++++++++++++++++-- |
| 1 file changed, 49 insertions(+), 2 deletions(-) |
| |
| diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c |
| index f9ffcf4602c713366a1551dafdf26b5ad623058e..f1e6367e9e5fe6d03634902c63aa6517462721f7 100644 |
| --- a/net/bluetooth/hci_conn.c |
| +++ b/net/bluetooth/hci_conn.c |
| @@ -50,6 +50,11 @@ struct conn_handle_t { |
| __u16 handle; |
| }; |
| |
| +struct le_conn_data { |
| + bdaddr_t dst; |
| + u8 dst_type; |
| +}; |
| + |
| static const struct sco_param esco_param_cvsd[] = { |
| { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a, 0x01 }, /* S3 */ |
| { EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007, 0x01 }, /* S2 */ |
| @@ -1280,6 +1285,8 @@ u8 hci_conn_set_handle(struct hci_conn *conn, u16 handle) |
| |
| static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err) |
| { |
| + |
| + struct le_conn_data *conn_data = data; |
| struct hci_conn *conn; |
| u16 handle = PTR_UINT(data); |
| |
| @@ -1289,8 +1296,22 @@ static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err) |
| |
| bt_dev_dbg(hdev, "err %d", err); |
| |
| + if (!conn_data) { |
| + bt_dev_err(hdev, "conn_data is NULL"); |
| + return; |
| + } |
| + |
| hci_dev_lock(hdev); |
| |
| + conn = hci_conn_hash_lookup_le(hdev, &conn_data->dst, conn_data->dst_type); |
| + |
| + if (!conn) { |
| + bt_dev_err(hdev, |
| + "can't find conn with addr:%pMR,type:%d, skip the connection", |
| + &conn_data->dst, conn_data->dst_type); |
| + goto done; |
| + } |
| + |
| if (!err) { |
| hci_connect_le_scan_cleanup(conn, 0x00); |
| goto done; |
| @@ -1305,11 +1326,13 @@ static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err) |
| hci_conn_failed(conn, bt_status(err)); |
| |
| done: |
| + kfree(conn_data); |
| hci_dev_unlock(hdev); |
| } |
| |
| static int hci_connect_le_sync(struct hci_dev *hdev, void *data) |
| { |
| + struct le_conn_data *conn_data = data; |
| struct hci_conn *conn; |
| u16 handle = PTR_UINT(data); |
| |
| @@ -1317,6 +1340,20 @@ static int hci_connect_le_sync(struct hci_dev *hdev, void *data) |
| if (!conn) |
| return 0; |
| |
| + if (!conn_data) { |
| + bt_dev_err(hdev, "conn_data is NULL"); |
| + return -ECONNABORTED; |
| + } |
| + |
| + conn = hci_conn_hash_lookup_le(hdev, &conn_data->dst, conn_data->dst_type); |
| + |
| + if (!conn) { |
| + bt_dev_err(hdev, |
| + "can't find conn with addr:%pMR,type:%d, skip the connection", |
| + &conn_data->dst, conn_data->dst_type); |
| + return -ECONNABORTED; |
| + } |
| + |
| bt_dev_dbg(hdev, "conn %p", conn); |
| |
| clear_bit(HCI_CONN_SCANNING, &conn->flags); |
| @@ -1331,6 +1368,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, |
| { |
| struct hci_conn *conn; |
| struct smp_irk *irk; |
| + struct le_conn_data *conn_data; |
| int err; |
| |
| /* Let's make sure that le is enabled.*/ |
| @@ -1391,11 +1429,20 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, |
| conn->sec_level = BT_SECURITY_LOW; |
| conn->conn_timeout = conn_timeout; |
| |
| - err = hci_cmd_sync_queue(hdev, hci_connect_le_sync, |
| - UINT_PTR(conn->handle), |
| + conn->state = BT_CONNECT; |
| + clear_bit(HCI_CONN_SCANNING, &conn->flags); |
| + |
| + conn_data = kmalloc(sizeof(*conn_data), GFP_KERNEL); |
| + if (!conn_data) |
| + return ERR_PTR(-ENOMEM); |
| + bacpy(&conn_data->dst, dst); |
| + conn_data->dst_type = dst_type; |
| + |
| + err = hci_cmd_sync_queue(hdev, hci_connect_le_sync, conn_data, |
| create_le_conn_complete); |
| if (err) { |
| hci_conn_del(conn); |
| + kfree(conn_data); |
| return ERR_PTR(err); |
| } |
| |
| -- |
| 2.42.0.655.g421f12c284-goog |
| |