Bluetooth: Fix Deadlock on Legacy Scan/Pair
Fix nested calls to hci_dev_lock().
Signed-off-by: Brian Gix <bgix@codeaurora.org>
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 1e59cb3..2276428 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3088,12 +3088,16 @@
num_reports = skb->data[0];
ev = (void *) &skb->data[1];
+ hci_dev_lock(hdev);
+
while (num_reports--) {
mgmt_device_found(hdev->id, &ev->bdaddr, ev->bdaddr_type,
1, NULL, 0, ev->length, ev->data);
hci_add_adv_entry(hdev, ev);
ev = (void *) (ev->data + ev->length + 1);
}
+
+ hci_dev_unlock(hdev);
}
static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 79e0891..72d249e 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2426,8 +2426,6 @@
if (!hdev)
return -ENODEV;
- hci_dev_lock(hdev);
-
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
ev.auto_confirm = 0;
@@ -2452,7 +2450,6 @@
ev.event = event;
put_unaligned_le32(value, &ev.value);
- hci_dev_unlock(hdev);
hci_dev_put(hdev);
return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
@@ -2623,8 +2620,6 @@
struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
struct hci_cp_le_set_scan_enable le_cp = {0, 0};
- hci_dev_lock(hdev);
-
ilp->int_phase *= 2;
ilp->int_count = 0;
if (ilp->mode == SCAN_LE) {
@@ -2638,7 +2633,6 @@
ilp->mode = SCAN_BR;
del_timer_sync(&ilp->le_timer);
}
- hci_dev_unlock(hdev);
}
if (hdev)
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 9089e65..8943510 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -292,6 +292,7 @@
struct hci_conn *hcon = conn->hcon;
u8 method;
u32 passkey = 0;
+ int ret = 0;
/* Initialize key to JUST WORKS */
memset(hcon->tk, 0, sizeof(hcon->tk));
@@ -356,15 +357,23 @@
}
agent_request:
+ hci_dev_lock(hcon->hdev);
+
switch (method) {
case SMP_REQ_PASSKEY:
- return mgmt_user_confirm_request(0, HCI_EV_USER_PASSKEY_REQUEST,
- conn->dst, 0);
+ ret = mgmt_user_confirm_request(hcon->hdev->id,
+ HCI_EV_USER_PASSKEY_REQUEST, conn->dst, 0);
+ break;
case SMP_CFM_PASSKEY:
default:
- return mgmt_user_confirm_request(0, HCI_EV_USER_CONFIRM_REQUEST,
- conn->dst, passkey);
+ ret = mgmt_user_confirm_request(hcon->hdev->id,
+ HCI_EV_USER_CONFIRM_REQUEST, conn->dst, passkey);
+ break;
}
+
+ hci_dev_unlock(hcon->hdev);
+
+ return ret;
}
static int send_pairing_confirm(struct l2cap_conn *conn)