Commit 181a42ed authored by Ziyang Xuan's avatar Ziyang Xuan Committed by Luiz Augusto von Dentz

Bluetooth: Make handle of hci_conn be unique

The handle of new hci_conn is always HCI_CONN_HANDLE_MAX + 1 if
the handle of the first hci_conn entry in hci_dev->conn_hash->list
is not HCI_CONN_HANDLE_MAX + 1. Use ida to manage the allocation of
hci_conn->handle to make it be unique.

Fixes: 9f78191c ("Bluetooth: hci_conn: Always allocate unique handles")
Signed-off-by: default avatarZiyang Xuan <william.xuanziyang@huawei.com>
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
parent 624820f7
...@@ -350,6 +350,8 @@ struct hci_dev { ...@@ -350,6 +350,8 @@ struct hci_dev {
struct list_head list; struct list_head list;
struct mutex lock; struct mutex lock;
struct ida unset_handle_ida;
const char *name; const char *name;
unsigned long flags; unsigned long flags;
__u16 id; __u16 id;
...@@ -1446,7 +1448,9 @@ int hci_le_create_cis_pending(struct hci_dev *hdev); ...@@ -1446,7 +1448,9 @@ int hci_le_create_cis_pending(struct hci_dev *hdev);
int hci_conn_check_create_cis(struct hci_conn *conn); int hci_conn_check_create_cis(struct hci_conn *conn);
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, u16 handle);
struct hci_conn *hci_conn_add_unset(struct hci_dev *hdev, int type,
bdaddr_t *dst, u8 role);
void hci_conn_del(struct hci_conn *conn); void hci_conn_del(struct hci_conn *conn);
void hci_conn_hash_flush(struct hci_dev *hdev); void hci_conn_hash_flush(struct hci_dev *hdev);
void hci_conn_check_pending(struct hci_dev *hdev); void hci_conn_check_pending(struct hci_dev *hdev);
......
...@@ -109,7 +109,7 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, ...@@ -109,7 +109,7 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon; struct hci_conn *hcon;
u8 role = out ? HCI_ROLE_MASTER : HCI_ROLE_SLAVE; u8 role = out ? HCI_ROLE_MASTER : HCI_ROLE_SLAVE;
hcon = hci_conn_add(hdev, AMP_LINK, dst, role); hcon = hci_conn_add(hdev, AMP_LINK, dst, role, __next_handle(mgr));
if (!hcon) if (!hcon)
return NULL; return NULL;
...@@ -117,7 +117,6 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, ...@@ -117,7 +117,6 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr,
hcon->state = BT_CONNECT; hcon->state = BT_CONNECT;
hcon->attempt++; hcon->attempt++;
hcon->handle = __next_handle(mgr);
hcon->remote_id = remote_id; hcon->remote_id = remote_id;
hcon->amp_mgr = amp_mgr_get(mgr); hcon->amp_mgr = amp_mgr_get(mgr);
......
...@@ -153,6 +153,9 @@ static void hci_conn_cleanup(struct hci_conn *conn) ...@@ -153,6 +153,9 @@ static void hci_conn_cleanup(struct hci_conn *conn)
hci_conn_hash_del(hdev, conn); hci_conn_hash_del(hdev, conn);
if (HCI_CONN_HANDLE_UNSET(conn->handle))
ida_free(&hdev->unset_handle_ida, conn->handle);
if (conn->cleanup) if (conn->cleanup)
conn->cleanup(conn); conn->cleanup(conn);
...@@ -951,31 +954,18 @@ static void cis_cleanup(struct hci_conn *conn) ...@@ -951,31 +954,18 @@ 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) static int hci_conn_hash_alloc_unset(struct hci_dev *hdev)
{ {
struct hci_conn_hash *h = &hdev->conn_hash; return ida_alloc_range(&hdev->unset_handle_ida, HCI_CONN_HANDLE_MAX + 1,
struct hci_conn *c; U16_MAX, GFP_ATOMIC);
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, u16 handle)
{ {
struct hci_conn *conn; struct hci_conn *conn;
BT_DBG("%s dst %pMR", hdev->name, dst); bt_dev_dbg(hdev, "dst %pMR handle 0x%4.4x", dst, handle);
conn = kzalloc(sizeof(*conn), GFP_KERNEL); conn = kzalloc(sizeof(*conn), GFP_KERNEL);
if (!conn) if (!conn)
...@@ -983,7 +973,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, ...@@ -983,7 +973,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_hash_alloc_unset(hdev); conn->handle = handle;
conn->hdev = hdev; conn->hdev = hdev;
conn->type = type; conn->type = type;
conn->role = role; conn->role = role;
...@@ -1068,6 +1058,20 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, ...@@ -1068,6 +1058,20 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
return conn; return conn;
} }
struct hci_conn *hci_conn_add_unset(struct hci_dev *hdev, int type,
bdaddr_t *dst, u8 role)
{
int handle;
bt_dev_dbg(hdev, "dst %pMR", dst);
handle = hci_conn_hash_alloc_unset(hdev);
if (unlikely(handle < 0))
return NULL;
return hci_conn_add(hdev, type, dst, role, handle);
}
static void hci_conn_cleanup_child(struct hci_conn *conn, u8 reason) static void hci_conn_cleanup_child(struct hci_conn *conn, u8 reason)
{ {
if (!reason) if (!reason)
...@@ -1304,6 +1308,9 @@ u8 hci_conn_set_handle(struct hci_conn *conn, u16 handle) ...@@ -1304,6 +1308,9 @@ u8 hci_conn_set_handle(struct hci_conn *conn, u16 handle)
if (conn->abort_reason) if (conn->abort_reason)
return conn->abort_reason; return conn->abort_reason;
if (HCI_CONN_HANDLE_UNSET(conn->handle))
ida_free(&hdev->unset_handle_ida, conn->handle);
conn->handle = handle; conn->handle = handle;
return 0; return 0;
...@@ -1411,7 +1418,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, ...@@ -1411,7 +1418,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
if (conn) { if (conn) {
bacpy(&conn->dst, dst); bacpy(&conn->dst, dst);
} else { } else {
conn = hci_conn_add(hdev, LE_LINK, dst, role); conn = hci_conn_add_unset(hdev, LE_LINK, dst, role);
if (!conn) if (!conn)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
hci_conn_hold(conn); hci_conn_hold(conn);
...@@ -1588,7 +1595,7 @@ static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst, ...@@ -1588,7 +1595,7 @@ static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst,
memcmp(conn->le_per_adv_data, base, base_len))) memcmp(conn->le_per_adv_data, base, base_len)))
return ERR_PTR(-EADDRINUSE); return ERR_PTR(-EADDRINUSE);
conn = hci_conn_add(hdev, ISO_LINK, dst, HCI_ROLE_MASTER); conn = hci_conn_add_unset(hdev, ISO_LINK, dst, HCI_ROLE_MASTER);
if (!conn) if (!conn)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -1632,7 +1639,7 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst, ...@@ -1632,7 +1639,7 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
BT_DBG("requesting refresh of dst_addr"); BT_DBG("requesting refresh of dst_addr");
conn = hci_conn_add(hdev, LE_LINK, dst, HCI_ROLE_MASTER); conn = hci_conn_add_unset(hdev, LE_LINK, dst, HCI_ROLE_MASTER);
if (!conn) if (!conn)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -1680,7 +1687,7 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, ...@@ -1680,7 +1687,7 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
if (!acl) { if (!acl) {
acl = hci_conn_add(hdev, ACL_LINK, dst, HCI_ROLE_MASTER); acl = hci_conn_add_unset(hdev, ACL_LINK, dst, HCI_ROLE_MASTER);
if (!acl) if (!acl)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
...@@ -1740,7 +1747,7 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, ...@@ -1740,7 +1747,7 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
sco = hci_conn_hash_lookup_ba(hdev, type, dst); sco = hci_conn_hash_lookup_ba(hdev, type, dst);
if (!sco) { if (!sco) {
sco = hci_conn_add(hdev, type, dst, HCI_ROLE_MASTER); sco = hci_conn_add_unset(hdev, type, dst, HCI_ROLE_MASTER);
if (!sco) { if (!sco) {
hci_conn_drop(acl); hci_conn_drop(acl);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -1932,7 +1939,7 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst, ...@@ -1932,7 +1939,7 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
cis = hci_conn_hash_lookup_cis(hdev, dst, dst_type, qos->ucast.cig, cis = hci_conn_hash_lookup_cis(hdev, dst, dst_type, qos->ucast.cig,
qos->ucast.cis); qos->ucast.cis);
if (!cis) { if (!cis) {
cis = hci_conn_add(hdev, ISO_LINK, dst, HCI_ROLE_MASTER); cis = hci_conn_add_unset(hdev, ISO_LINK, dst, HCI_ROLE_MASTER);
if (!cis) if (!cis)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
cis->cleanup = cis_cleanup; cis->cleanup = cis_cleanup;
......
...@@ -2535,6 +2535,8 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv) ...@@ -2535,6 +2535,8 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
mutex_init(&hdev->lock); mutex_init(&hdev->lock);
mutex_init(&hdev->req_lock); mutex_init(&hdev->req_lock);
ida_init(&hdev->unset_handle_ida);
INIT_LIST_HEAD(&hdev->mesh_pending); INIT_LIST_HEAD(&hdev->mesh_pending);
INIT_LIST_HEAD(&hdev->mgmt_pending); INIT_LIST_HEAD(&hdev->mgmt_pending);
INIT_LIST_HEAD(&hdev->reject_list); INIT_LIST_HEAD(&hdev->reject_list);
...@@ -2789,6 +2791,7 @@ void hci_release_dev(struct hci_dev *hdev) ...@@ -2789,6 +2791,7 @@ void hci_release_dev(struct hci_dev *hdev)
hci_codec_list_clear(&hdev->local_codecs); hci_codec_list_clear(&hdev->local_codecs);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
ida_destroy(&hdev->unset_handle_ida);
ida_simple_remove(&hci_index_ida, hdev->id); ida_simple_remove(&hci_index_ida, hdev->id);
kfree_skb(hdev->sent_cmd); kfree_skb(hdev->sent_cmd);
kfree_skb(hdev->recv_event); kfree_skb(hdev->recv_event);
......
...@@ -2335,7 +2335,7 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) ...@@ -2335,7 +2335,7 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
} }
} else { } else {
if (!conn) { if (!conn) {
conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr, conn = hci_conn_add_unset(hdev, ACL_LINK, &cp->bdaddr,
HCI_ROLE_MASTER); HCI_ROLE_MASTER);
if (!conn) if (!conn)
bt_dev_err(hdev, "no memory for new connection"); bt_dev_err(hdev, "no memory for new connection");
...@@ -3151,8 +3151,8 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, ...@@ -3151,8 +3151,8 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
hci_bdaddr_list_lookup_with_flags(&hdev->accept_list, hci_bdaddr_list_lookup_with_flags(&hdev->accept_list,
&ev->bdaddr, &ev->bdaddr,
BDADDR_BREDR)) { BDADDR_BREDR)) {
conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr, conn = hci_conn_add_unset(hdev, ev->link_type,
HCI_ROLE_SLAVE); &ev->bdaddr, HCI_ROLE_SLAVE);
if (!conn) { if (!conn) {
bt_dev_err(hdev, "no memory for new conn"); bt_dev_err(hdev, "no memory for new conn");
goto unlock; goto unlock;
...@@ -3317,7 +3317,7 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data, ...@@ -3317,7 +3317,7 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,
conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, conn = hci_conn_hash_lookup_ba(hdev, ev->link_type,
&ev->bdaddr); &ev->bdaddr);
if (!conn) { if (!conn) {
conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr, conn = hci_conn_add_unset(hdev, ev->link_type, &ev->bdaddr,
HCI_ROLE_SLAVE); HCI_ROLE_SLAVE);
if (!conn) { if (!conn) {
bt_dev_err(hdev, "no memory for new connection"); bt_dev_err(hdev, "no memory for new connection");
...@@ -5890,7 +5890,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, ...@@ -5890,7 +5890,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
if (status) if (status)
goto unlock; goto unlock;
conn = hci_conn_add(hdev, LE_LINK, bdaddr, role); conn = hci_conn_add_unset(hdev, LE_LINK, bdaddr, role);
if (!conn) { if (!conn) {
bt_dev_err(hdev, "no memory for new connection"); bt_dev_err(hdev, "no memory for new connection");
goto unlock; goto unlock;
...@@ -5952,17 +5952,11 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, ...@@ -5952,17 +5952,11 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
conn->dst_type = ev_bdaddr_type(hdev, conn->dst_type, NULL); conn->dst_type = ev_bdaddr_type(hdev, conn->dst_type, NULL);
if (handle > HCI_CONN_HANDLE_MAX) {
bt_dev_err(hdev, "Invalid handle: 0x%4.4x > 0x%4.4x", handle,
HCI_CONN_HANDLE_MAX);
status = HCI_ERROR_INVALID_PARAMETERS;
}
/* All connection failure handling is taken care of by the /* All connection failure handling is taken care of by the
* hci_conn_failed function which is triggered by the HCI * hci_conn_failed function which is triggered by the HCI
* request completion callbacks used for connecting. * request completion callbacks used for connecting.
*/ */
if (status) if (status || hci_conn_set_handle(conn, handle))
goto unlock; goto unlock;
/* Drop the connection if it has been aborted */ /* Drop the connection if it has been aborted */
...@@ -5986,7 +5980,6 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, ...@@ -5986,7 +5980,6 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
mgmt_device_connected(hdev, conn, NULL, 0); mgmt_device_connected(hdev, conn, NULL, 0);
conn->sec_level = BT_SECURITY_LOW; conn->sec_level = BT_SECURITY_LOW;
conn->handle = handle;
conn->state = BT_CONFIG; conn->state = BT_CONFIG;
/* Store current advertising instance as connection advertising instance /* Store current advertising instance as connection advertising instance
...@@ -6622,7 +6615,7 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data, ...@@ -6622,7 +6615,7 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data,
if (ev->status) { if (ev->status) {
/* Add connection to indicate the failed PA sync event */ /* Add connection to indicate the failed PA sync event */
pa_sync = hci_conn_add(hdev, ISO_LINK, BDADDR_ANY, pa_sync = hci_conn_add_unset(hdev, ISO_LINK, BDADDR_ANY,
HCI_ROLE_SLAVE); HCI_ROLE_SLAVE);
if (!pa_sync) if (!pa_sync)
...@@ -7019,12 +7012,12 @@ static void hci_le_cis_req_evt(struct hci_dev *hdev, void *data, ...@@ -7019,12 +7012,12 @@ static void hci_le_cis_req_evt(struct hci_dev *hdev, void *data,
cis = hci_conn_hash_lookup_handle(hdev, cis_handle); cis = hci_conn_hash_lookup_handle(hdev, cis_handle);
if (!cis) { if (!cis) {
cis = hci_conn_add(hdev, ISO_LINK, &acl->dst, HCI_ROLE_SLAVE); cis = hci_conn_add(hdev, ISO_LINK, &acl->dst, HCI_ROLE_SLAVE,
cis_handle);
if (!cis) { if (!cis) {
hci_le_reject_cis(hdev, ev->cis_handle); hci_le_reject_cis(hdev, ev->cis_handle);
goto unlock; goto unlock;
} }
cis->handle = cis_handle;
} }
cis->iso_qos.ucast.cig = ev->cig_id; cis->iso_qos.ucast.cig = ev->cig_id;
...@@ -7129,10 +7122,9 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data, ...@@ -7129,10 +7122,9 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
bis = hci_conn_hash_lookup_handle(hdev, handle); bis = hci_conn_hash_lookup_handle(hdev, handle);
if (!bis) { if (!bis) {
bis = hci_conn_add(hdev, ISO_LINK, BDADDR_ANY, bis = hci_conn_add(hdev, ISO_LINK, BDADDR_ANY,
HCI_ROLE_SLAVE); HCI_ROLE_SLAVE, handle);
if (!bis) if (!bis)
continue; continue;
bis->handle = handle;
} }
if (ev->status != 0x42) if (ev->status != 0x42)
...@@ -7198,7 +7190,7 @@ static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data, ...@@ -7198,7 +7190,7 @@ static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data,
goto unlock; goto unlock;
/* Add connection to indicate the PA sync event */ /* Add connection to indicate the PA sync event */
pa_sync = hci_conn_add(hdev, ISO_LINK, BDADDR_ANY, pa_sync = hci_conn_add_unset(hdev, ISO_LINK, BDADDR_ANY,
HCI_ROLE_SLAVE); HCI_ROLE_SLAVE);
if (!pa_sync) if (!pa_sync)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment