diff options
author | Mayank Rana <mrana@codeaurora.org> | 2015-11-16 12:31:24 -0800 |
---|---|---|
committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 19:58:22 -0700 |
commit | 3c2bb805ce85ab68dda76cb847f6d222c190846c (patch) | |
tree | 9401cfc8c5f15cb4bb5e7a909dac675d87612343 /drivers/usb | |
parent | ea1cd34463715f0776b9b992016000277f550841 (diff) |
usb: u_data_bridge: Check for USB cable connect with gbridge_port_write()
There is NULL pointer crash seen due to accessing port->port_usb from
gbridge_port_write() when port bridge application's write thread is
pre-empted and USB cable disconnect is being performed. Fix this issue
by adding check for USB cable is connected or not and handling USB
request accordingly.
Change-Id: Ide14de298b7186cbe7b7af1e99c8c47bc389130b
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/gadget/function/u_data_bridge.c | 28 |
1 files changed, 21 insertions, 7 deletions
diff --git a/drivers/usb/gadget/function/u_data_bridge.c b/drivers/usb/gadget/function/u_data_bridge.c index 1da24304bcd8..253831755a7d 100644 --- a/drivers/usb/gadget/function/u_data_bridge.c +++ b/drivers/usb/gadget/function/u_data_bridge.c @@ -508,6 +508,7 @@ ssize_t gbridge_port_write(struct file *file, struct usb_request *req; struct list_head *pool; unsigned xfer_size; + struct usb_ep *in; port = file->private_data; if (!port) { @@ -518,11 +519,19 @@ ssize_t gbridge_port_write(struct file *file, spin_lock_irqsave(&port->port_lock, flags); pr_debug("write on port(%p)\n", port); + if (!port->is_connected || !port->port_usb) { + spin_unlock_irqrestore(&port->port_lock, flags); + pr_err("%s: cable is disconnected.\n", __func__); + return -ENODEV; + } + if (list_empty(&port->write_pool)) { spin_unlock_irqrestore(&port->port_lock, flags); pr_debug("%s: Request list is empty.\n", __func__); return 0; } + + in = port->port_usb->in; pool = &port->write_pool; req = list_first_entry(pool, struct usb_request, list); list_del_init(&req->list); @@ -540,13 +549,10 @@ ssize_t gbridge_port_write(struct file *file, ret = -EFAULT; } else { req->length = xfer_size; - ret = usb_ep_queue(port->port_usb->in, req, GFP_KERNEL); + ret = usb_ep_queue(in, req, GFP_KERNEL); if (ret) { pr_err("EP QUEUE failed:%d\n", ret); - spin_lock_irqsave(&port->port_lock, flags); - list_add(&req->list, &port->write_pool); ret = -EIO; - spin_unlock_irqrestore(&port->port_lock, flags); goto err_exit; } spin_lock_irqsave(&port->port_lock, flags); @@ -555,10 +561,18 @@ ssize_t gbridge_port_write(struct file *file, } err_exit: - if (ret) + if (ret) { + spin_lock_irqsave(&port->port_lock, flags); + /* USB cable is connected, add it back otherwise free request */ + if (port->is_connected) + list_add(&req->list, &port->write_pool); + else + gbridge_free_req(in, req); + spin_unlock_irqrestore(&port->port_lock, flags); return ret; - else - return xfer_size; + } + + return xfer_size; } static unsigned int gbridge_port_poll(struct file *file, poll_table *wait) |