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>
This commit is contained in:
Luiz Augusto von Dentz 2023-06-28 12:15:53 -07:00
parent 04a51d6169
commit 9f78191cc9
3 changed files with 26 additions and 7 deletions

View File

@ -321,8 +321,8 @@ struct adv_monitor {
#define HCI_MAX_SHORT_NAME_LENGTH 10 #define HCI_MAX_SHORT_NAME_LENGTH 10
#define HCI_CONN_HANDLE_UNSET 0xffff
#define HCI_CONN_HANDLE_MAX 0x0eff #define HCI_CONN_HANDLE_MAX 0x0eff
#define HCI_CONN_HANDLE_UNSET(_handle) (_handle > HCI_CONN_HANDLE_MAX)
/* Min encryption key size to match with SMP */ /* Min encryption key size to match with SMP */
#define HCI_MIN_ENC_KEY_SIZE 7 #define HCI_MIN_ENC_KEY_SIZE 7

View File

@ -932,6 +932,25 @@ static void cis_cleanup(struct hci_conn *conn)
hci_le_remove_cig(hdev, conn->iso_qos.ucast.cig); 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, struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
u8 role) 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->dst, dst);
bacpy(&conn->src, &hdev->bdaddr); bacpy(&conn->src, &hdev->bdaddr);
conn->handle = HCI_CONN_HANDLE_UNSET; conn->handle = hci_conn_hash_alloc_unset(hdev);
conn->hdev = hdev; conn->hdev = hdev;
conn->type = type; conn->type = type;
conn->role = role; conn->role = role;
@ -1057,7 +1076,7 @@ static void hci_conn_unlink(struct hci_conn *conn)
*/ */
if ((child->type == SCO_LINK || if ((child->type == SCO_LINK ||
child->type == ESCO_LINK) && child->type == ESCO_LINK) &&
child->handle == HCI_CONN_HANDLE_UNSET) HCI_CONN_HANDLE_UNSET(child->handle))
hci_conn_del(child); hci_conn_del(child);
} }
@ -1943,7 +1962,7 @@ int hci_conn_check_create_cis(struct hci_conn *conn)
return -EINVAL; return -EINVAL;
if (!conn->parent || conn->parent->state != BT_CONNECTED || 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 1;
return 0; return 0;

View File

@ -3173,7 +3173,7 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
* As the connection handle is set here for the first time, it indicates * As the connection handle is set here for the first time, it indicates
* whether the connection is already set up. * whether the connection is already set up.
*/ */
if (conn->handle != HCI_CONN_HANDLE_UNSET) { if (!HCI_CONN_HANDLE_UNSET(conn->handle)) {
bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for existing connection"); bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for existing connection");
goto unlock; goto unlock;
} }
@ -5032,7 +5032,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, void *data,
* As the connection handle is set here for the first time, it indicates * As the connection handle is set here for the first time, it indicates
* whether the connection is already set up. * whether the connection is already set up.
*/ */
if (conn->handle != HCI_CONN_HANDLE_UNSET) { if (!HCI_CONN_HANDLE_UNSET(conn->handle)) {
bt_dev_err(hdev, "Ignoring HCI_Sync_Conn_Complete event for existing connection"); bt_dev_err(hdev, "Ignoring HCI_Sync_Conn_Complete event for existing connection");
goto unlock; goto unlock;
} }
@ -5896,7 +5896,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
* As the connection handle is set here for the first time, it indicates * As the connection handle is set here for the first time, it indicates
* whether the connection is already set up. * whether the connection is already set up.
*/ */
if (conn->handle != HCI_CONN_HANDLE_UNSET) { if (!HCI_CONN_HANDLE_UNSET(conn->handle)) {
bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for existing connection"); bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for existing connection");
goto unlock; goto unlock;
} }