summaryrefslogtreecommitdiff
path: root/net/bluetooth/hci_conn.c
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2023-06-28 12:15:53 -0700
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2023-08-11 11:43:02 -0700
commit9f78191cc9f1b34c2e2afd7b554a83bf034092dd (patch)
treef00351059ed7f3f6aa45ea80163ed9b885ed2a26 /net/bluetooth/hci_conn.c
parent04a51d616929eb96b7a3e547bc11d3bb46af2c9f (diff)
Bluetooth: hci_conn: Always allocate unique handles
This attempts to always allocate a unique handle for connections so they can be properly aborted by the likes of hci_abort_conn, so this uses the invalid range as a pool of unset handles that way if userspace is trying to create multiple connections at once each will be given a unique handle which will be considered unset. Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Diffstat (limited to 'net/bluetooth/hci_conn.c')
-rw-r--r--net/bluetooth/hci_conn.c25
1 files changed, 22 insertions, 3 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index a0ffe7db412b..af7dc8131a8c 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -932,6 +932,25 @@ static void cis_cleanup(struct hci_conn *conn)
hci_le_remove_cig(hdev, conn->iso_qos.ucast.cig);
}
+static u16 hci_conn_hash_alloc_unset(struct hci_dev *hdev)
+{
+ struct hci_conn_hash *h = &hdev->conn_hash;
+ struct hci_conn *c;
+ u16 handle = HCI_CONN_HANDLE_MAX + 1;
+
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(c, &h->list, list) {
+ /* Find the first unused handle */
+ if (handle == 0xffff || c->handle != handle)
+ break;
+ handle++;
+ }
+ rcu_read_unlock();
+
+ return handle;
+}
+
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
u8 role)
{
@@ -945,7 +964,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
bacpy(&conn->dst, dst);
bacpy(&conn->src, &hdev->bdaddr);
- conn->handle = HCI_CONN_HANDLE_UNSET;
+ conn->handle = hci_conn_hash_alloc_unset(hdev);
conn->hdev = hdev;
conn->type = type;
conn->role = role;
@@ -1057,7 +1076,7 @@ static void hci_conn_unlink(struct hci_conn *conn)
*/
if ((child->type == SCO_LINK ||
child->type == ESCO_LINK) &&
- child->handle == HCI_CONN_HANDLE_UNSET)
+ HCI_CONN_HANDLE_UNSET(child->handle))
hci_conn_del(child);
}
@@ -1943,7 +1962,7 @@ int hci_conn_check_create_cis(struct hci_conn *conn)
return -EINVAL;
if (!conn->parent || conn->parent->state != BT_CONNECTED ||
- conn->state != BT_CONNECT || conn->handle == HCI_CONN_HANDLE_UNSET)
+ conn->state != BT_CONNECT || HCI_CONN_HANDLE_UNSET(conn->handle))
return 1;
return 0;