Commit 1785dbf9 authored by Peter Hurley's avatar Peter Hurley Committed by Gustavo F. Padovan

Bluetooth: hidp: safely acquire hci connection

Claim device lock to safely enumerate hci connection list and bump
hci connection proxy device ref count simultaneously.

This patch incorporates David Herrmann's fix to prevent adding an
HID device when the hci connection no longer exists.
Signed-off-by: default avatarDavid Herrmann <dh.herrmann@googlemail.com>
Signed-off-by: default avatarPeter Hurley <peter@hurleysoftware.com>
Signed-off-by: default avatarGustavo F. Padovan <padovan@profusion.mobi>
parent ab88f714
...@@ -95,8 +95,6 @@ static void __hidp_link_session(struct hidp_session *session) ...@@ -95,8 +95,6 @@ static void __hidp_link_session(struct hidp_session *session)
{ {
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
list_add(&session->list, &hidp_session_list); list_add(&session->list, &hidp_session_list);
hci_conn_hold_device(session->conn);
} }
static void __hidp_unlink_session(struct hidp_session *session) static void __hidp_unlink_session(struct hidp_session *session)
...@@ -785,24 +783,26 @@ static int hidp_session(void *arg) ...@@ -785,24 +783,26 @@ static int hidp_session(void *arg)
return 0; return 0;
} }
static struct device *hidp_get_device(struct hidp_session *session) static struct hci_conn *hidp_find_connection(struct hidp_session *session)
{ {
bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src; bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst; bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
struct device *device = NULL; struct hci_conn *conn;
struct hci_dev *hdev; struct hci_dev *hdev;
hdev = hci_get_route(dst, src); hdev = hci_get_route(dst, src);
if (!hdev) if (!hdev)
return NULL; return NULL;
session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); hci_dev_lock_bh(hdev);
if (session->conn) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
device = &session->conn->dev; if (conn)
hci_conn_hold_device(conn);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev); hci_dev_put(hdev);
return device; return conn;
} }
static int hidp_setup_input(struct hidp_session *session, static int hidp_setup_input(struct hidp_session *session,
...@@ -852,7 +852,7 @@ static int hidp_setup_input(struct hidp_session *session, ...@@ -852,7 +852,7 @@ static int hidp_setup_input(struct hidp_session *session,
input->relbit[0] |= BIT_MASK(REL_WHEEL); input->relbit[0] |= BIT_MASK(REL_WHEEL);
} }
input->dev.parent = hidp_get_device(session); input->dev.parent = &session->conn->dev;
input->event = hidp_input_event; input->event = hidp_input_event;
...@@ -952,7 +952,7 @@ static int hidp_setup_hid(struct hidp_session *session, ...@@ -952,7 +952,7 @@ static int hidp_setup_hid(struct hidp_session *session,
strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64); strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64); strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
hid->dev.parent = hidp_get_device(session); hid->dev.parent = &session->conn->dev;
hid->ll_driver = &hidp_hid_driver; hid->ll_driver = &hidp_hid_driver;
hid->hid_get_raw_report = hidp_get_raw_report; hid->hid_get_raw_report = hidp_get_raw_report;
...@@ -993,6 +993,12 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, ...@@ -993,6 +993,12 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
goto failed; goto failed;
} }
session->conn = hidp_find_connection(session);
if (!session->conn) {
err = -ENOTCONN;
goto failed;
}
bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst); bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->chan->omtu, session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->chan->omtu,
...@@ -1018,6 +1024,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, ...@@ -1018,6 +1024,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID); session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
session->idle_to = req->idle_to; session->idle_to = req->idle_to;
__hidp_link_session(session);
if (req->rd_size > 0) { if (req->rd_size > 0) {
err = hidp_setup_hid(session, req); err = hidp_setup_hid(session, req);
if (err) if (err)
...@@ -1030,8 +1038,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, ...@@ -1030,8 +1038,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
goto purge; goto purge;
} }
__hidp_link_session(session);
hidp_set_timer(session); hidp_set_timer(session);
if (session->hid) { if (session->hid) {
...@@ -1084,8 +1090,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, ...@@ -1084,8 +1090,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
unlink: unlink:
hidp_del_timer(session); hidp_del_timer(session);
__hidp_unlink_session(session);
if (session->input) { if (session->input) {
input_unregister_device(session->input); input_unregister_device(session->input);
session->input = NULL; session->input = NULL;
...@@ -1100,6 +1104,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, ...@@ -1100,6 +1104,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
session->rd_data = NULL; session->rd_data = NULL;
purge: purge:
__hidp_unlink_session(session);
skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->ctrl_transmit);
skb_queue_purge(&session->intr_transmit); skb_queue_purge(&session->intr_transmit);
......
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