mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
Bluetooth: hidp: safely acquire hci connection
Claim device lock to safely enumerate hci connection list and bump hci connection proxy device ref count simultaneously. Also it prevents kernel crash due to null pointer conn->hdev in deleting conn entry from sysfs. CRs-Fixed: 446403 Change-Id: I5ec4283d359f95e47711dff171d0619b15263349 Signed-off-by: Sumit Bajpai <sbajpai@codeaurora.org> Signed-off-by: Mallikarjuna GB <gbmalli@codeaurora.org>
This commit is contained in:
parent
0c537ac89b
commit
505bdc3bd1
2 changed files with 37 additions and 33 deletions
|
@ -166,7 +166,8 @@ void hci_conn_del_sysfs(struct hci_conn *conn)
|
|||
{
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
queue_work(conn->hdev->workqueue, &conn->work_del);
|
||||
if (conn->hdev)
|
||||
queue_work(conn->hdev->workqueue, &conn->work_del);
|
||||
}
|
||||
|
||||
static inline char *host_bustostr(int bus)
|
||||
|
|
|
@ -93,40 +93,15 @@ static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static struct device *hidp_get_device(struct hidp_session *session)
|
||||
{
|
||||
bdaddr_t *dst = &session->bdaddr;
|
||||
|
||||
struct device *device = NULL;
|
||||
struct hci_dev *hdev;
|
||||
|
||||
hdev = hci_get_route(dst, BDADDR_ANY);
|
||||
if (!hdev)
|
||||
return NULL;
|
||||
|
||||
session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
|
||||
if (session->conn)
|
||||
device = &session->conn->dev;
|
||||
|
||||
hci_dev_put(hdev);
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
static void __hidp_link_session(struct hidp_session *session)
|
||||
{
|
||||
__module_get(THIS_MODULE);
|
||||
list_add(&session->list, &hidp_session_list);
|
||||
|
||||
hci_conn_hold_device(session->conn);
|
||||
}
|
||||
|
||||
static void __hidp_unlink_session(struct hidp_session *session)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
dev = hidp_get_device(session);
|
||||
if (dev)
|
||||
if (session->conn)
|
||||
hci_conn_put_device(session->conn);
|
||||
|
||||
list_del(&session->list);
|
||||
|
@ -660,6 +635,28 @@ static int hidp_session(void *arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct hci_conn *hidp_get_connection(struct hidp_session *session)
|
||||
{
|
||||
bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
|
||||
bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
|
||||
struct hci_conn *conn;
|
||||
struct hci_dev *hdev;
|
||||
|
||||
hdev = hci_get_route(dst, src);
|
||||
if (!hdev)
|
||||
return NULL;
|
||||
|
||||
hci_dev_lock_bh(hdev);
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
|
||||
if (conn)
|
||||
hci_conn_hold_device(conn);
|
||||
hci_dev_unlock_bh(hdev);
|
||||
|
||||
hci_dev_put(hdev);
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
static int hidp_setup_input(struct hidp_session *session,
|
||||
struct hidp_connadd_req *req)
|
||||
{
|
||||
|
@ -707,7 +704,7 @@ static int hidp_setup_input(struct hidp_session *session,
|
|||
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;
|
||||
|
||||
|
@ -808,7 +805,7 @@ static int hidp_setup_hid(struct hidp_session *session,
|
|||
strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 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->hid_output_raw_report = hidp_output_raw_report;
|
||||
|
@ -866,6 +863,12 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
|
|||
session->intr_sock = intr_sock;
|
||||
session->state = BT_CONNECTED;
|
||||
|
||||
session->conn = hidp_get_connection(session);
|
||||
if (!session->conn) {
|
||||
err = -ENOTCONN;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
|
||||
|
||||
skb_queue_head_init(&session->ctrl_transmit);
|
||||
|
@ -874,6 +877,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
|
|||
session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
|
||||
session->idle_to = req->idle_to;
|
||||
|
||||
__hidp_link_session(session);
|
||||
|
||||
if (req->rd_size > 0) {
|
||||
err = hidp_setup_hid(session, req);
|
||||
if (err && err != -ENODEV)
|
||||
|
@ -886,8 +891,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
|
|||
goto purge;
|
||||
}
|
||||
|
||||
__hidp_link_session(session);
|
||||
|
||||
hidp_set_timer(session);
|
||||
|
||||
err = kernel_thread(hidp_session, session, CLONE_KERNEL);
|
||||
|
@ -909,8 +912,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
|
|||
unlink:
|
||||
hidp_del_timer(session);
|
||||
|
||||
__hidp_unlink_session(session);
|
||||
|
||||
if (session->input) {
|
||||
input_unregister_device(session->input);
|
||||
session->input = NULL;
|
||||
|
@ -925,6 +926,8 @@ unlink:
|
|||
session->rd_data = NULL;
|
||||
|
||||
purge:
|
||||
__hidp_unlink_session(session);
|
||||
|
||||
skb_queue_purge(&session->ctrl_transmit);
|
||||
skb_queue_purge(&session->intr_transmit);
|
||||
|
||||
|
|
Loading…
Reference in a new issue