diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 0a4c7d60222..255419e6b59 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -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) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index d80c0e33ab5..2c4ab786ae5 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -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);